Cureyên gumanbar

Di xuyabûna wan de tiştek bi guman nîne. Wekî din, ew tewra ji we re baş û ji bo demek dirêj nas xuya dikin. Lê ew tenê heya ku hûn wan kontrol bikin. Li vir e ku ew cewhera xwe ya xapînok nîşan didin, ji ya ku we hêvî dikir bi tevahî cûda cûda dixebitin. Û carinan ew tiştek dikin ku porê we li ber xwe dide - mînakî, ew daneyên veşartî yên ku ji wan re hatine spartin winda dikin. Gava ku tu bi wan re rû bi rû dibî, ew îdia dikin ku ew hevûdu nas nakin, her çend di bin siyê de ew di bin heman kapê de bi xîret dixebitin. Wext e ku em di dawiyê de wan bînin ava paqij. Werin em jî bi van celebên gumanbar re mijûl bibin.

Nivîsandina daneyan di PostgreSQL de, digel hemî mantiqa xwe, carinan surprîzên pir ecêb peyda dike. Di vê gotarê de em ê hewl bidin ku hin hûrgelên wan ronî bikin, sedema tevgera wan a xerîb fam bikin û fam bikin ka meriv çawa di pratîka rojane de nekevin pirsgirêkan. Ji bo rastiyê bêjim, min ev gotar jî ji bo xwe wekî celebek pirtûka referansê berhev kir, pirtûkek referansê ku di dozên nakok de bi hêsanî dikare were vegotin. Ji ber vê yekê, gava ku surprîzên nû ji celebên gumanbar têne kifş kirin, ew ê were tije kirin. Ji ber vê yekê, em herin, ey şopînerên databasê yên bêwestan!

Dosya hejmara yek. rast / ducar rast / hejmar / pere

Wusa dixuye ku celebên hejmarî di behrê de ji surprîzên herî kêm pirsgirêk in. Lê çawa be jî. Ji ber vê yekê em bi wan re dest pê bikin. Wiha…

Ji bîr kir ku meriv çawa hesab dike

SELECT 0.1::real = 0.1

?column?
boolean
---------
f

Babet çîye? Pirsgirêk ev e ku PostgreSQL 0.1-a domdar a netîp diguhezîne rastbûna ducarî û hewl dide ku wê bi 0.1-a celebê rastîn re bide ber hev. Û ev wateyên bi tevahî cûda ne! Fikir ew e ku di bîranîna makîneyê de hejmarên rastîn temsîl bikin. Ji ber ku 0.1 nikare wekî parçeyek binaryê ya dawî were temsîl kirin (ew ê di binary de 0.0(0011) be), jimareyên bi reqemên cihêreng dê cûda bin, ji ber vê yekê ew ne wekhev in. Bi gelemperî, ev mijarek ji bo gotarek cuda ye, ez ê li vir bi berfirehî nenivîsim.

Xeletî ji ku tê?

SELECT double precision(1)

ERROR:  syntax error at or near "("
LINE 1: SELECT double precision(1)
                               ^
********** Ошибка **********
ERROR: syntax error at or near "("
SQL-состояние: 42601
Символ: 24

Pir kes dizanin ku PostgreSQL destûrê dide nîşankirina fonksiyonel ji bo avêtina celebê. Ango, hûn dikarin ne tenê 1::int, lê her weha int(1) jî binivîsin, ku dê wekhev be. Lê ne ji bo tîpên ku navên wan ji çend peyvan pêk tên! Ji ber vê yekê, heke hûn dixwazin nirxek jimareyî bavêjin da ku celebê rastbûna di forma fonksiyonel de ducar bikin, navnavên vê celebê float8 bikar bînin, ango, SELECT float8(1).

Çi ji bêdawîtiyê mezintir e?

SELECT 'Infinity'::double precision < 'NaN'::double precision

?column?
boolean
---------
t

Binêre ew çawa ye! Derket holê ku tiştek ji bêdawîtiyê mezintir heye, û ew NaN e! Di heman demê de, belgeya PostgreSQL bi çavên dilsoz li me dinêre û îdia dike ku NaN eşkere ji her hejmareke din mezintir e, û ji ber vê yekê, bêdawî ye. Berevajî vê jî ji bo -NaN rast e. Silav, evîndarên matematîkê! Lê divê em ji bîr mekin ku ev hemî di çarçoveya hejmarên rastîn de tevdigerin.

Eye dor

SELECT round('2.5'::double precision)
     , round('2.5'::numeric)

      round      |  round
double precision | numeric
-----------------+---------
2                | 3

Silavek din a neçaverêkirî ji bingehê. Dîsa, ji bîr mekin ku celebên dualî û hejmarî xwedî bandorên dorpêvekirina cihêreng in. Ji bo jimare - ya asayî, dema ku 0,5 bi jor ve tê giroverkirin, û ji bo rastbûna ducarî - 0,5 ber bi hej-jimara herî nêzîk ve tê giroverkirin.

Pere tiştekî taybet e

SELECT '10'::money::float8

ERROR:  cannot cast type money to double precision
LINE 1: SELECT '10'::money::float8
                          ^
********** Ошибка **********
ERROR: cannot cast type money to double precision
SQL-состояние: 42846
Символ: 19

Li gorî PostgreSQL, drav ne hejmarek rastîn e. Li gorî hin kesan jî. Pêdivî ye ku em ji bîr nekin ku avêtina celebê dravê tenê ji celebê hejmarî re gengaz e, mîna ku tenê tîpa hejmarî dikare ji celebê pereyê were avêtin. Lê niha hûn dikarin wekî dilê xwe bi wê re bilîzin. Lê ew ê nebin heman pere.

Nifşê biçûk û rêz

SELECT *
  FROM generate_series(1::smallint, 5::smallint, 1::smallint)

ERROR:  function generate_series(smallint, smallint, smallint) is not unique
LINE 2:   FROM generate_series(1::smallint, 5::smallint, 1::smallint...
               ^
HINT:  Could not choose a best candidate function. You might need to add explicit type casts.
********** Ошибка **********
ERROR: function generate_series(smallint, smallint, smallint) is not unique
SQL-состояние: 42725
Подсказка: Could not choose a best candidate function. You might need to add explicit type casts.
Символ: 18

PostgreSQL hez nake ku wextê xwe li ser piçûkan winda bike. Ev rêzikên li ser bingeha piçûk çi ne? int, ne kêmtir! Ji ber vê yekê, dema ku hewl dide ku pirsa li jor bicîh bîne, databas hewl dide ku piçûkan bavêje celebek din a yekjimar, û dibîne ku dibe ku çend avêtinên weha hebin. Kîjan cast hilbijêrin? Ew nikare vê biryarê bide, û ji ber vê yekê bi xeletiyek têk diçe.

Dosya hejmara du. "char"/char/varchar/text

Di celebên karakteran de hejmarek xerîbî jî hene. Ka em wan jî nas bikin.

Ev çi hîle ne?

SELECT 'ПЕТЯ'::"char"
     , 'ПЕТЯ'::"char"::bytea
     , 'ПЕТЯ'::char
     , 'ПЕТЯ'::char::bytea

 char  | bytea |    bpchar    | bytea
"char" | bytea | character(1) | bytea
-------+-------+--------------+--------
 ╨     | xd0  | П            | xd09f

Ev çi cure "çar" e, ev çi palgoş e? Hewcedariya me bi wan nîn e... Ji ber ku ew xwe wekî karakterek asayî nîşan dide, her çend ew di nav deqan de be jî. Û ew ji char birêkûpêk, ku bê quote ye, cûda dibe, di wê yekê de ku ew tenê baytê yekem ê temsîla rêzê derdixe, lê tîpek normal karaktera yekem derdixe. Di rewşa me de, karaktera yekem tîpa P ye, ku di nûneriya unicode de 2 bayt digire, wekî ku bi veguheztina encamê li celebê bytea ve hatî xuyang kirin. Û tîpa "char" tenê byta yekem a vê nûnertiya unicode digire. Wê demê çima ev celeb hewce ye? Belgekirina PostgreSQL dibêje ku ev celebek taybetî ye ku ji bo hewcedariyên taybetî tê bikar anîn. Ji ber vê yekê ne mimkûn e ku em hewce nebin. Lê li çavên wî binêre û gava ku hûn wî bi tevgera wî ya taybetî re bibînin, hûn ê xelet nebin.

Cihên zêde. Ji ber çavan, ji hiş

SELECT 'abc   '::char(6)::bytea
     , 'abc   '::char(6)::varchar(6)::bytea
     , 'abc   '::varchar(6)::bytea

     bytea     |   bytea  |     bytea
     bytea     |   bytea  |     bytea
---------------+----------+----------------
x616263202020 | x616263 | x616263202020

Li mînaka hatî dayîn binêrin. Min bi taybetî hemî encam veguherand celebê bytea, da ku ew tiştê ku li wir heye bi zelalî xuya bibe. Cihên paşerojê piştî avêtina varchar(6) li ku ne? Di belgeyê de bi kurtî wiha tê gotin: "Dema ku nirxa karakterê li celebek karakterek din tê avêtin, cîhê spî yê paşde tê avêtin." Divê ev nefret were bibîranîn. Û bala xwe bidinê ku ger domdarek rêza binavkirî rasterast ji tîpa varchar(6) re were avêtin, cîhên paşerojê têne parastin. Mucîzeyên weha ne.

Dosya hejmara sê. json/jsonb

JSON avahiyek cuda ye ku jiyana xwe dijî. Ji ber vê yekê, saziyên wê û yên PostgreSQL hinekî cûda ne. Li vir nimûne hene.

Johnson û Johnson. cudahiyê hîs bikin

SELECT 'null'::jsonb IS NULL

?column?
boolean
---------
f

Tişt ev e ku JSON xwedan saziya xweya null e, ku ne analoga NULL di PostgreSQL de ye. Di heman demê de, tişta JSON bixwe dibe ku xwedan nirxa NULL be, ji ber vê yekê raveya SELECT null::jsonb IS NULL (bala xwe nebûna quotên yekane) dê vê carê rast vegere.

Yek tîp her tiştî diguherîne

SELECT '{"1": [1, 2, 3], "2": [4, 5, 6], "1": [7, 8, 9]}'::json

                     json
                     json
------------------------------------------------
{"1": [1, 2, 3], "2": [4, 5, 6], "1": [7, 8, 9]}

---

SELECT '{"1": [1, 2, 3], "2": [4, 5, 6], "1": [7, 8, 9]}'::jsonb

             jsonb
             jsonb
--------------------------------
{"1": [7, 8, 9], "2": [4, 5, 6]}

Tişt ev e ku json û jsonb bi tevahî avahiyên cûda ne. Di json de, tişt wekî ku tê hilanîn, û di jsonb de ew jixwe di şeklê avahiyek parskirî, îndekskirî de tê hilanîn. Ji ber vê yekê di rewşa duyemîn de, nirxa tiştê ji hêla kilîta 1-ê ve ji [1, 2, 3] veguherî [7, 8, 9], ku di dawiyê de bi heman kilîtê ket nav avahiyê.

Ji rûyê xwe avê venexwin

SELECT '{"reading": 1.230e-5}'::jsonb
     , '{"reading": 1.230e-5}'::json

          jsonb         |         json
          jsonb         |         json
------------------------+----------------------
{"reading": 0.00001230} | {"reading": 1.230e-5}

PostgreSQL di pêkanîna JSONB-a xwe de formatkirina hejmarên rastîn diguhezîne, wan tîne forma klasîk. Ev ji bo celebê JSON pêk nayê. Hinekî xerîb, lê ew rast e.

Dosya hejmara çar. tarîx/dem/demjimêr

Di heman demê de bi celebên tarîx/demê re hin xerîbî jî hene. Ka em li wan binêrin. Bihêle ez tavilê rezervek bikim ku hin taybetmendiyên behrê zelal dibin heke hûn cewhera xebata bi deverên demjimêr re baş fam bikin. Lê ev jî mijarek ji bo gotarek cuda ye.

Yên min fêm nakin

SELECT '08-Jan-99'::date

ERROR:  date/time field value out of range: "08-Jan-99"
LINE 1: SELECT '08-Jan-99'::date
               ^
HINT:  Perhaps you need a different "datestyle" setting.
********** Ошибка **********
ERROR: date/time field value out of range: "08-Jan-99"
SQL-состояние: 22008
Подсказка: Perhaps you need a different "datestyle" setting.
Символ: 8

Wusa dixuye ku çi li vir nayê fêm kirin? Lê databas hîn jî fam nake ku em li vir di rêza yekem de çi dikin-sal an roj? Û ew biryar dide ku ew 99 Çile 2008 e, ku hişê wê dişewitîne. Bi gelemperî, dema ku dîrokan di formata nivîsê de vediguhezînin, hûn hewce ne ku pir bi baldarî kontrol bikin ka databas çiqas rast wan nas kiriye (bi taybetî, parametreya datestyle bi fermana SHOW datestyle analîz bikin), ji ber ku nezelalî di vê mijarê de dibe ku pir biha be.

Te ev ji ku anî?

SELECT '04:05 Europe/Moscow'::time

ERROR:  invalid input syntax for type time: "04:05 Europe/Moscow"
LINE 1: SELECT '04:05 Europe/Moscow'::time
               ^
********** Ошибка **********
ERROR: invalid input syntax for type time: "04:05 Europe/Moscow"
SQL-состояние: 22007
Символ: 8

Çima databas nikare dema diyarkirî ya eşkere fam bike? Ji ber ku devera demjimêr ne xwedan kurtenivîsek, lê navek tije ye, ku tenê di çarçoweya tarîxekê de watedar e, ji ber ku ew dîroka guheztinên devera demjimêr dihesibîne, û ew bêyî tarîx kar nake. Û pir peyva rêzika demê pirsan derdixe holê - bernamenûs bi rastî çi dixwest? Ji ber vê yekê, heke hûn lê binêrin, her tişt li vir mentiqî ye.

Çi bi wî heye?

Rewşê bifikirin. Di tabloya we de zeviyek bi tîpa timestamptz heye. Hûn dixwazin wê navnîş bikin. Lê hûn fêm dikin ku avakirina îndekek li ser vê qadê ji ber hilbijartiya wê ya bilind her gav ne rastdar e (hema hema hemî nirxên vî rengî dê bêhempa bin). Ji ber vê yekê hûn biryar didin ku bi xistina celebê tarîxek hilbijartî ya pêvekê kêm bikin. Û hûn surprîzek bistînin:

CREATE INDEX "iIdent-DateLastUpdate"
  ON public."Ident" USING btree
  (("DTLastUpdate"::date));

ERROR:  functions in index expression must be marked IMMUTABLE
********** Ошибка **********
ERROR: functions in index expression must be marked IMMUTABLE
SQL-состояние: 42P17

Babet çîye? Rastî ev e ku ji bo avêtina tîpek timestamptz li celebek tarîxê, nirxa pîvana pergala TimeZone tê bikar anîn, ku fonksiyona veguherîna celebê bi pîvanek xwerû ve girêdayî dike, ango. volatile. Fonksiyonên weha di navnîşan de destûr nayê dayîn. Di vê rewşê de, divê hûn bi zelalî destnîşan bikin ka li kîjan devera demjimêrê avêtina celebê tête kirin.

Dema ku niha jî ne niha ye

Em ji niha ve () vegerandina tarîx/saeta heyî, li gorî qada demjimêrê bikar anîne. Lê li pirsên jêrîn binêrin:

START TRANSACTION;
SELECT now();

            now
  timestamp with time zone
-----------------------------
2019-11-26 13:13:04.271419+03

...

SELECT now();

            now
  timestamp with time zone
-----------------------------
2019-11-26 13:13:04.271419+03

...

SELECT now();

            now
  timestamp with time zone
-----------------------------
2019-11-26 13:13:04.271419+03

COMMIT;

Dîrok/dem wek hev tê vegerandin bê çiqas dem di ser daxwaza berê re derbas bûye! Babet çîye? Rastî ev e ku niha () ne dema niha ye, lê dema destpêkirina danûstendina heyî ye. Ji ber vê yekê, ew di nav danûstandinê de nayê guhertin. Lêpirsînek ku li derveyî çarçoweya danûstendinê hatî destpêkirin bi nepenî di danûstendinê de tê pêçan, ji ber vê yekê em ferq nakin ku dema ku ji hêla SELECT niha ve hatî vegerandin(); bi rastî, ne ya niha... Heke hûn dixwazin demek niha ya rast bi dest bixin, divê hûn fonksiyona clock_timestamp() bikar bînin.

Dosya hejmara pênc. gem

Piçek xerîb

SELECT '111'::bit(4)

 bit
bit(4)
------
1110

Di rewşa dirêjkirina cureyê de divê bit li kîjan alî were zêdekirin? Ew xuya dike ku li çepê ye. Lê tenê bingeh di vê mijarê de xwedî nêrînek cûda ye. Hişyar bin: heke hejmara jimareyan di dema avêtina tîpekê de li hev neke, hûn ê tiştê ku we dixwest bi dest nexin. Ev hem ji bo lêzêdekirina bitikan li bitsên rast û hem jî ji bo qutkirina bits derbas dibe. Li aliyê rastê jî...

Dosya hejmara şeş. Arrays

Tewra NULL jî agir neda

SELECT ARRAY[1, 2] || NULL

?column?
integer[]
---------
{1,2}

Wekî ku mirovên normal li ser SQL rabûn, em li bendê ne ku encama vê îfadeyê NULL be. Lê ne li wir bû. Arrayek tê vegerandin. Çima? Ji ber ku di vê rewşê de bingeh NULL-ê davêje rêzek yekjimar û bi awayekî nepenî bangî fonksiyona array_cat dike. Lê hîn jî ne diyar e ka çima ev "pisika array" rêzê ji nû ve nade. Ev tevger jî tenê pêdivî ye ku were bîranîn.

Bihevrekirin. Gelek tiştên ecêb hene. Piraniya wan, bê guman, ne ew qas rexnegir in ku li ser behremendiyên neguncav bi eşkere biaxivin. Û yên din bi hêsanîya karanînê an pirbûna sepandina wan di hin rewşan de têne rave kirin. Lê di heman demê de gelek sosret hene. Ji ber vê yekê, divê hûn li ser wan zanibin. Ger hûn di tevgera her cûre de tiştek xerîb an neasayî bibînin, di şîroveyan de binivîsin, ez ê kêfxweş bibim ku li dosyayên ku li ser wan hene zêde bikim.

Source: www.habr.com

Add a comment