Kalite sispèk

Pa gen anyen ki sispèk sou aparans yo. Anplis, yo menm sanble abitye pou ou byen ak pou yon tan long. Men, sa a sèlman jiskaske ou tcheke yo. Sa a se kote yo montre nati trètr yo, k ap travay konplètman yon fason diferan pase ou te espere. Epi pafwa yo fè yon bagay ki fè cheve ou kanpe sou fen - pou egzanp, yo pèdi done sekrè yo konfye yo. Lè ou konfwonte yo, yo reklame ke yo pa konnen youn ak lòt, byenke nan lonbraj yo travay di anba menm kapo a. Li lè yo finalman pote yo nan dlo pwòp. Se pou nou tou fè fas ak kalite sispèk sa yo.

Tape done nan PostgreSQL, pou tout lojik li yo, pafwa prezante sipriz trè etranj. Nan atik sa a nou pral eseye klarifye kèk nan kirks yo, konprann rezon ki fè yo nan konpòtman etranj yo ak konprann ki jan yo pa kouri nan pwoblèm nan pratik chak jou. Pou di verite a, mwen konpile atik sa a tou kòm yon kalite liv referans pou tèt mwen, yon liv referans ki ta ka fasil refere li nan ka kontwovèsyal. Se poutèt sa, li pral rkonstitusyon kòm nouvo supriz soti nan kalite sispèk yo dekouvri. Se konsa, ann ale, o trackers baz done san pran souf!

Dosye nimewo en. reyèl / doub presizyon / nimerik / lajan

Li ta sanble ke kalite nimerik yo se pi piti pwoblèm an tèm de supriz nan konpòtman. Men, pa gen pwoblèm ki jan li ye. Se konsa, ann kòmanse ak yo. Se konsa…

Bliye kijan pou konte

SELECT 0.1::real = 0.1

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

Ki pwoblèm nan? Pwoblèm lan se ke PostgreSQL konvèti konstan ki pa tape 0.1 an doub presizyon epi li eseye konpare li ak 0.1 nan kalite reyèl. Ak sa yo se siyifikasyon konplètman diferan! Lide a se reprezante nimewo reyèl nan memwa machin. Depi 0.1 pa ka reprezante kòm yon fraksyon binè fini (li ta 0.0(0011) nan binè), nimewo ki gen diferan pwofondè ti pral diferan, kidonk rezilta a ke yo pa egal. Anjeneral pale, sa a se yon sijè pou yon atik separe; Mwen pa pral ekri an plis detay isit la.

Ki kote erè a soti?

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

Anpil moun konnen PostgreSQL pèmèt notasyon fonksyonèl pou depoze kalite. Sa vle di, ou ka ekri non sèlman 1::int, men tou, int(1), ki pral ekivalan. Men se pa pou kalite ki gen non plizyè mo! Se poutèt sa, si ou vle jete yon valè nimerik a doub kalite presizyon nan fòm fonksyonèl, sèvi ak alyas nan kalite sa a float8, se sa ki, SELECT float8 (1).

Ki sa ki pi gwo pase infini?

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

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

Gade kijan sa ye! Li sanble ke gen yon bagay ki pi gwo pase Infini, epi li nan NaN! An menm tan an, dokiman PostgreSQL la gade nou ak je onèt epi reklame ke NaN se evidamman pi gran pase nenpòt lòt nimewo, epi, Se poutèt sa, enfini. Opoze a se vre tou pou -NaN. Bonjou, rayisab matematik! Men, nou dwe sonje ke tout bagay sa yo opere nan yon kontèks nimewo reyèl.

Awondi je

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

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

Yon lòt salitasyon inatandi soti nan baz la. Ankò, sonje ke doub presizyon ak kalite nimerik gen efè awondi diferan. Pou nimerik - abityèl la, lè 0,5 awondi moute, ak pou doub presizyon - 0,5 awondi nan direksyon nonb antye relatif ki pi pre a.

Lajan se yon bagay espesyal

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

Dapre PostgreSQL, lajan se pa yon nimewo reyèl. Dapre kèk moun, tou. Nou bezwen sonje ke depoze kalite lajan an se posib sèlman nan kalite a nimerik, menm jan sèlman kalite a nimerik ka jete nan kalite a lajan. Men koulye a, ou ka jwe ak li jan kè ou vle. Men, li p ap menm lajan an.

Smallint ak jenerasyon sekans

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 pa renmen pèdi tan nan vetiy. Ki sekans sa yo ki baze sou smallint? int, pa mwens! Se poutèt sa, lè w ap eseye egzekite rechèch ki anwo a, baz done a ap eseye jete smallint nan kèk lòt kalite nonb antye relatif, epi li wè ke ka gen plizyè jete sa yo. Ki jete yo chwazi? Li pa ka deside sa a, ak Se poutèt sa aksidan ak yon erè.

Dosye nimewo de. "char"/char/varchar/text

Yon kantite bizarre yo prezan tou nan kalite karaktè. Ann konn yo tou.

Ki kalite trik sa yo ye?

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

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

Ki kalite "char" sa a, ki kalite kloun sa a? Nou pa bezwen sa yo... Paske li pretann yo dwe yon char òdinè, menm si li nan quotes. Epi li diferan de yon char regilye, ki se san quotes, nan ke li pwodiksyon sèlman premye octet nan reprezantasyon fisèl la, pandan y ap yon char nòmal pwodiksyon karaktè nan premye. Nan ka nou an, premye karaktè a se lèt P a, ki nan reprezantasyon unicode la pran 2 octets, jan sa evidan nan konvèti rezilta a nan kalite bytea. Ak kalite "char" la pran sèlman premye byte nan reprezantasyon unicode sa a. Lè sa a, poukisa kalite sa a nesesè? Dokiman PostgreSQL la di ke sa a se yon kalite espesyal yo itilize pou bezwen espesyal. Se konsa, nou pa gen anpil chans bezwen li. Men, gade nan je l ', epi ou pa pral fè erè lè ou rankontre l' ak konpòtman espesyal li.

Espas siplemantè. Soti nan je, soti nan tèt ou

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

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

Gade nan egzanp yo bay la. Mwen espesyalman konvèti tout rezilta yo nan kalite bytea, se konsa ke li te klèman vizib sa ki te la. Ki kote espas fin yo apre jete nan varchar(6)? Dokiman an brize di: "Lè yo mete valè karaktè a nan yon lòt kalite karaktè, espas blanch fin jete." Sa a pa renmen dwe sonje. Epi sonje ke si yo jete yon konstan fisèl ki site dirèkteman nan kalite varchar (6), espas fin yo konsève. Sa yo se mirak yo.

Dosye nimewo twa. json/jsonb

JSON se yon estrikti separe ki ap viv pwòp lavi li. Se poutèt sa, antite li yo ak sa yo ki nan PostgreSQL yo yon ti kras diferan. Men kèk egzanp.

Johnson ak Johnson. santi diferans lan

SELECT 'null'::jsonb IS NULL

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

Bagay la se ke JSON gen pwòp antite nil li yo, ki se pa analogue a nan NULL nan PostgreSQL. An menm tan an, objè JSON nan tèt li ka byen gen valè NULL la, kidonk ekspresyon SELECT null::jsonb IS NULL (note absans sitasyon sèl) ap retounen vre fwa sa a.

Yon lèt chanje tout bagay

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]}

Bagay la se ke json ak jsonb yo se estrikti konplètman diferan. Nan json, objè a estoke jan li ye, ak nan jsonb li deja estoke nan fòm yon estrikti analize, endis. Se poutèt sa, nan dezyèm ka a, valè objè a pa kle 1 te ranplase soti nan [1, 2, 3] rive nan [7, 8, 9], ki te antre nan estrikti a nan fen a ak menm kle a.

Pa bwè dlo nan figi ou

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

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

PostgreSQL nan aplikasyon JSONB li yo chanje fòma nimewo reyèl yo, pote yo nan fòm klasik la. Sa a pa rive pou kalite JSON la. Yon ti kras etranj, men li gen rezon.

Dosye nimewo kat. dat/lè/timestamp

Genyen tou kèk bizarrel ak kalite dat / lè. Ann gade yo. Kite m 'fè yon rezèvasyon touswit ke kèk nan karakteristik konpòtman yo vin klè si ou konprann byen sans nan travay ak zòn tan yo. Men, sa a se tou yon sijè pou yon atik separe.

Ou pam pa konprann

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

Li ta sanble ke sa ki enkonpreyansib isit la? Men, baz done a toujou pa konprann sa nou mete an premye plas isit la - ane a oswa jou a? Epi li deside ke se janvye 99, 2008, ki soufle tèt li. An jeneral, lè w ap transmèt dat nan fòma tèks, ou bezwen tcheke avèk anpil atansyon kijan baz done a rekonèt yo kòrèkteman (an patikilye, analize paramèt datestyle la ak lòd SHOW datestyle), paske anbigwite nan zafè sa a ka trè chè.

Ki kote ou te jwenn sa a?

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

Poukisa baz done a pa ka konprann tan an klèman espesifye? Paske zòn lè a pa gen yon abrevyasyon, men yon non konplè, ki fè sans sèlman nan yon kontèks yon dat, depi li pran an kont istwa a nan chanjman zòn tan, epi li pa travay san yon dat. Ak libellé a anpil nan liy tan an soulve kesyon - kisa pwogramè a reyèlman vle di? Se poutèt sa, tout bagay se lojik isit la, si ou gade nan li.

Ki sa ki mal nan li?

Imajine sitiyasyon an. Ou gen yon jaden nan tab ou a ak kalite timestamptz. Ou vle endèks li. Men, ou konprann ke bati yon endèks sou jaden sa a pa toujou jistifye akòz selektivite segondè li yo (prèske tout valè nan kalite sa a pral inik). Se konsa, ou deside diminye selektivite nan endèks la pa depoze kalite a nan yon dat. Epi ou jwenn yon sipriz:

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

Ki pwoblèm nan? Reyalite a se ke yo jete yon kalite timestamptz nan yon kalite dat, yo itilize valè paramèt sistèm TimeZone, ki fè fonksyon konvèsyon kalite a depann sou yon paramèt koutim, i.e. temèt. Fonksyon sa yo pa pèmèt nan endèks la. Nan ka sa a, ou dwe klèman endike nan ki zòn tan kalite jete a fèt.

Lè kounye a se pa menm kounye a ditou

Nou abitye kounye a() retounen dat/lè aktyèl la, pran an kont zòn tan an. Men gade kesyon sa yo:

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;

Yo retounen dat/lè a menm kèlkeswa kantite tan ki pase depi demann anvan an! Ki pwoblèm nan? Reyalite a se ke kounye a () se pa tan aktyèl la, men lè a kòmanse nan tranzaksyon aktyèl la. Se poutèt sa, li pa chanje nan tranzaksyon an. Nenpòt demann ki lanse andeyò sijè ki abòde lan nan yon tranzaksyon an vlope nan yon tranzaksyon implicitement, ki se poukisa nou pa remake ke tan an retounen pa yon senp SELECT kounye a (); an reyalite, pa yon sèl aktyèl la... Si ou vle jwenn yon tan aktyèl onèt, ou bezwen sèvi ak fonksyon an clock_timestamp().

Dosye nimewo senk. ti jan

Etranj yon ti kras

SELECT '111'::bit(4)

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

Ki bò yo ta dwe ajoute nan ka ta gen ekstansyon kalite? Li sanble sou bò gòch la. Men, sèlman baz la gen yon opinyon diferan sou zafè sa a. Fè atansyon: si kantite chif pa koresponn ak depoze yon kalite, ou p ap jwenn sa ou te vle. Sa a aplike a tou de ajoute Bits sou bò dwat la ak koupe Bits. Sou bò dwat la tou...

Dosye nimewo sis. Etalaj

Menm NULL pa t tire

SELECT ARRAY[1, 2] || NULL

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

Kòm moun nòmal leve soti vivan sou SQL, nou espere rezilta a nan ekspresyon sa a yo dwe NULL. Men, li pa t 'la. Yon etalaj retounen. Poukisa? Paske nan ka sa a baz la jete NULL nan yon etalaj nonb antye relatif epi li rele fonksyon an array_cat. Men, li toujou rete klè poukisa "chat etalaj" sa a pa reset etalaj la. Konpòtman sa a tou jis bezwen sonje.

Rezime. Gen anpil bagay etranj. Pifò nan yo, nan kou, yo pa tèlman kritik kòm pale sou konpòtman flagran inapwopriye. Ak lòt moun yo eksplike pa fasil pou itilize oswa frekans aplikasyon yo nan sèten sitiyasyon. Men, an menm tan, gen anpil sipriz. Se poutèt sa, ou bezwen konnen sou yo. Si ou jwenn nenpòt lòt bagay etranj oswa etranj nan konpòtman an nan nenpòt kalite, ekri nan kòmantè yo, mwen pral kontan ajoute nan dosye ki disponib sou yo.

Sous: www.habr.com

Add nouvo kòmantè