Kadudahang matang

Walay kadudahan ang ilang panagway. Dugang pa, ingon sila pamilyar kanimo ug sa dugay nga panahon. Apan kana hangtod nga imong susihon sila. Dinhi ilang gipakita ang ilang malimbungon nga kinaiya, nagtrabaho nga hingpit nga lahi kaysa imong gipaabut. Ug usahay maghimo sila usa ka butang nga makapabarug sa imong buhok - pananglitan, nawala nila ang sekreto nga datos nga gisalig kanila. Sa diha nga imong atubangon sila, sila nag-angkon nga sila wala makaila sa usag usa, bisan sa mga anino sila makugihon nga nagtrabaho ubos sa sama nga tabon. Panahon na aron sa katapusan dad-on sila sa limpyo nga tubig. Ato usab nga atubangon kining mga kadudahang matang.

Ang pag-type sa datos sa PostgreSQL, alang sa tanan nga lohika niini, usahay magpakita og talagsaon nga mga sorpresa. Sa niini nga artikulo kita mosulay sa pagpatin-aw sa pipila sa ilang mga quirks, makasabut sa rason sa ilang katingad-an nga kinaiya ug makasabut sa unsa nga paagi nga dili modagan ngadto sa mga problema sa adlaw-adlaw nga praktis. Sa pagsulti sa tinuod, akong gihugpong kini nga artikulo isip usa usab ka matang sa reperensiya nga libro alang sa akong kaugalingon, usa ka reperensiya nga basahon nga daling mahisgotan sa mga kontrobersyal nga kaso. Busa, kini mapuno pag-usab samtang ang mga bag-ong surpresa gikan sa mga kadudahang matang nadiskobrehan. Busa, lakaw na, oh walay kakapoy nga database trackers!

Numero uno nga dossier. tinuod / doble nga katukma / numeric / kwarta

Mopatim-aw nga ang mga tipo sa numero mao ang labing gamay nga problema sa mga termino sa mga sorpresa sa pamatasan. Pero bisag unsaon. Busa magsugod kita uban kanila. Kaya nga…

Nakalimot unsaon pag-ihap

SELECT 0.1::real = 0.1

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

Unsay problema? Ang problema mao nga ang PostgreSQL nagbag-o sa wala ma-type nga kanunay nga 0.1 sa doble nga katukma ug gisulayan kini itandi sa 0.1 nga tinuud nga tipo. Ug kini hingpit nga lainlain nga mga kahulugan! Ang ideya mao ang pagrepresentar sa tinuod nga mga numero sa memorya sa makina. Tungod kay ang 0.1 dili mahimong representahan isip usa ka finite binary fraction (kini mahimong 0.0(0011) sa binary), ang mga numero nga adunay lain-laing mga digit mahimong lahi, busa ang resulta nga sila dili managsama. Sa kinatibuk-an nga pagsulti, kini usa ka hilisgutan alang sa usa ka lahi nga artikulo; Dili ako mosulat sa dugang nga detalye dinhi.

Diin gikan ang sayop?

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

Daghang mga tawo ang nahibal-an nga ang PostgreSQL nagtugot sa functional notation alang sa type casting. Sa ato pa, mahimo nimong isulat dili lang ang 1::int, apan usab int(1), nga mahimong katumbas. Apan dili alang sa mga tipo kansang mga ngalan naglangkob sa daghang mga pulong! Busa, kung gusto nimong ihulog ang usa ka numeric nga kantidad sa doble nga tipo sa katukma sa porma nga magamit, gamita ang alyas sa kini nga tipo nga float8, nga mao, PILI ang float8 (1).

Unsay mas dako kay sa infinity?

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

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

Tan-awa kung unsa kini! Kini nahimo nga adunay usa ka butang nga mas dako pa sa infinity, ug kini ang NaN! Sa samang higayon, ang dokumentasyon sa PostgreSQL nagtan-aw kanamo uban ang matinud-anon nga mga mata ug nag-angkon nga ang NaN dayag nga mas dako kay sa bisan unsa nga numero, ug, busa, walay katapusan. Ang sukwahi tinuod usab alang sa -NaN. Hello, math lovers! Apan kinahanglan natong hinumdoman nga kining tanan naglihok sa konteksto sa tinuod nga mga numero.

Paglibot sa mata

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

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

Laing wala damha nga pagtimbaya gikan sa base. Pag-usab, hinumdomi nga ang doble nga katukma ug mga tipo sa numero adunay lainlaing mga epekto sa paglibot. Alang sa numeric - ang naandan, kung ang 0,5 gilibot, ug alang sa doble nga katukma - ang 0,5 gilingin padulong sa labing duol nga integer.

Ang kuwarta usa ka butang nga 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

Sumala sa PostgreSQL, ang salapi dili tinuod nga numero. Sumala sa pipila ka mga indibidwal, usab. Kinahanglan natong hinumdoman nga ang paghulog sa tipo sa kuwarta posible lamang sa numeric type, sama nga ang numeric type lang ang mahimong ihulog sa money type. Apan karon mahimo nimong dulaon kini sumala sa gusto sa imong kasingkasing. Apan dili kini parehas nga kuwarta.

Smallint ug sequence generation

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

Ang PostgreSQL dili gusto nga mag-usik og oras sa mga butang nga walay hinungdan. Unsa kini nga mga han-ay nga gibase sa smallint? int, dili kubos! Busa, sa dihang mosulay sa pagpatuman sa pangutana sa ibabaw, ang database mosulay sa pag-cast sa smallint ngadto sa ubang integer nga tipo, ug makita nga adunay daghan nga mga cast. Kinsa nga cast ang pilion? Dili siya makadesisyon niini, ug busa nahagsa sa usa ka sayup.

Numero sa file duha. "char"/char/varchar/text

Daghang mga katingad-an ang naa usab sa mga tipo sa karakter. Kilalahon ta man sila.

Unsang matanga kini nga mga limbong?

SELECT 'ΠŸΠ•Π’Π―'::"char"
     , 'ΠŸΠ•Π’Π―'::"char"::bytea
     , 'ΠŸΠ•Π’Π―'::char
     , 'ΠŸΠ•Π’Π―'::char::bytea

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

Unsa ni nga klase sa "char", unsa ni nga clown? Dili namo kinahanglan ang mga ... Kay nagpakaaron-ingnon kini nga ordinaryo nga char, bisan kung kini naa sa mga kinutlo. Ug kini lahi sa usa ka regular nga char, nga walay mga kinutlo, tungod kay kini nagpagawas lamang sa unang byte sa representasyon sa string, samtang ang usa ka normal nga char nagpagawas sa unang karakter. Sa among kaso, ang una nga karakter mao ang letra nga P, nga sa representasyon sa unicode adunay 2 bytes, ingon nga ebidensya pinaagi sa pag-convert sa resulta sa tipo sa bytea. Ug ang tipo nga "char" nagkuha lamang sa una nga byte sa kini nga representasyon sa unicode. Nan nganong gikinahanglan man kini nga matang? Ang dokumentasyon sa PostgreSQL nag-ingon nga kini usa ka espesyal nga tipo nga gigamit alang sa mga espesyal nga panginahanglanon. Busa lagmit dili nato kini gikinahanglan. Apan tan-awa ang iyang mga mata ug dili ka masayop kung makit-an nimo siya nga adunay espesyal nga pamatasan.

Dugang nga mga luna. Wala sa panan-aw, wala sa hunahuna

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

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

Tan-awa ang gihatag nga pananglitan. Espesyal nakong gibag-o ang tanan nga mga resulta sa tipo sa bytea, aron kini klaro nga makita kung unsa ang naa. Asa ang mga trailing space pagkahuman sa pag-cast sa varchar(6)? Ang dokumentasyon malip-ot nga nag-ingon: "Sa dihang ihulog ang bili sa karakter ngadto sa lain nga tipo sa karakter, ang nagsunod nga whitespace ilabay." Kinahanglang hinumdoman kini nga dili gusto. Ug timan-i nga kung ang usa ka kinutlo nga string nga makanunayon ihulog direkta sa tipo nga varchar(6), ang mga trailing space gipreserbar. Mao kana ang mga milagro.

File numero tulo. json/jsonb

Ang JSON usa ka lahi nga istruktura nga nagpuyo sa kaugalingon nga kinabuhi. Busa, ang mga entidad niini ug ang sa PostgreSQL gamay nga lahi. Ania ang mga pananglitan.

Johnson ug Johnson. gibati ang kalainan

SELECT 'null'::jsonb IS NULL

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

Ang butang mao nga ang JSON adunay kaugalingon nga null entity, nga dili analogue sa NULL sa PostgreSQL. Sa samang higayon, ang JSON nga butang mismo mahimong adunay bili nga NULL, busa ang ekspresyon nga SELECT null::jsonb IS NULL (timan-i ang pagkawala sa usa ka kinutlo) mobalik nga tinuod niining panahona.

Usa ka letra nagbag-o sa tanan

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

Ang butang mao nga ang json ug jsonb hingpit nga lainlaing mga istruktura. Sa json, ang butang gitipigan ingon nga mao, ug sa jsonb kini gitipigan na sa porma sa usa ka parsed, indexed nga istruktura. Mao nga sa ikaduha nga kaso, ang bili sa butang pinaagi sa yawe 1 giilisan gikan sa [1, 2, 3] ngadto sa [7, 8, 9], nga misulod sa estraktura sa kataposang bahin sa samang yawe.

Ayaw pag-inom ug tubig gikan sa imong nawong

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

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

Ang PostgreSQL sa pagpatuman niini sa JSONB nagbag-o sa pag-format sa tinuod nga mga numero, nga nagdala kanila sa klasikal nga porma. Dili kini mahitabo alang sa tipo sa JSON. Medyo katingad-an, apan tama siya.

Numero sa file upat. petsa/oras/timestamp

Adunay usab pipila ka mga katingad-an nga adunay mga tipo sa petsa/oras. Atong tan-awon sila. Tugoti ako nga maghimo dayon og reserbasyon nga ang pipila sa mga bahin sa pamatasan mahimong klaro kung nasabtan nimo pag-ayo ang diwa sa pagtrabaho sa mga time zone. Apan kini usa usab ka hilisgutan alang sa usa ka lahi nga artikulo.

Ang akoa wala kasabot

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

Morag unsa ang dili masabtan dinhi? Apan ang database wala gihapon makasabut unsa ang atong gibutang sa unang dapit dinhi-ang tuig o ang adlaw? Ug nakahukom siya nga Enero 99, 2008, nga nakapalibog sa iyang hunahuna. Sa kinatibuk-an nga pagsulti, kung magpadala mga petsa sa format sa teksto, kinahanglan nimo nga susihon pag-ayo kung giunsa kini pag-ila sa database (labi na, analisa ang parameter sa datestyle gamit ang SHOW datestyle command), tungod kay ang mga ambiguity sa kini nga butang mahimo’g mahal kaayo.

Diin nimo kini gikuha?

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

Ngano nga dili masabtan sa database ang klaro nga gipiho nga oras? Tungod kay ang time zone wala'y abbreviation, apan usa ka bug-os nga ngalan, nga makatarunganon lamang sa konteksto sa usa ka petsa, tungod kay gikonsiderar niini ang kasaysayan sa pagbag-o sa time zone, ug kini dili molihok nga walay petsa. Ug ang mismong mga pulong sa linya sa oras nagpatunghag mga pangutana - unsa gyud ang gipasabut sa programmer? Busa, ang tanan makatarunganon dinhi, kung imong tan-awon kini.

Unsay problema niya?

Hunahunaa ang kahimtang. Naa kay field sa imong table nga naay type timestamptz. Gusto nimo nga i-index kini. Apan nahibal-an nimo nga ang pagtukod sa usa ka indeks sa kini nga natad dili kanunay makatarunganon tungod sa taas nga pagkapili niini (halos tanan nga mga kantidad sa kini nga tipo mahimong talagsaon). Mao nga nakahukom ka nga pakunhuran ang pagkapili sa indeks pinaagi sa paghulog sa tipo sa usa ka petsa. Ug nakakuha ka usa ka sorpresa:

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

Unsay problema? Ang kamatuoran mao nga ang pag-cast sa usa ka timestamptz type sa usa ka date type, ang bili sa TimeZone system parameter gigamit, nga naghimo sa type conversion function nga nagsalig sa usa ka custom parameter, i.e. dalidalion. Ang ingon nga mga gimbuhaton dili gitugotan sa indeks. Sa kini nga kaso, kinahanglan nimo nga klaro nga ipakita kung asa nga time zone ang tipo nga cast gihimo.

Sa diha nga karon dili bisan karon sa tanan

Naanad na kami karon() nga ibalik ang karon nga petsa/oras, nga gikonsiderar ang time zone. Apan tan-awa ang mosunod nga mga pangutana:

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;

Ang petsa/oras gibalik nga pareho bisag pila ka oras ang milabay sukad sa miaging hangyo! Unsay problema? Ang kamatuoran mao nga karon() dili ang karon nga oras, apan ang oras sa pagsugod sa karon nga transaksyon. Busa, wala kini mausab sulod sa transaksyon. Ang bisan unsang pangutana nga gilusad sa gawas sa sakup sa usa ka transaksyon giputos sa usa ka transaksyon nga dili klaro, mao nga wala kami makamatikod nga ang oras gibalik sa usa ka yano nga PILI karon (); sa pagkatinuod, dili ang kasamtangan ... Kung gusto nimo nga makakuha og matinud-anon nga kasamtangan nga oras, kinahanglan nimo nga gamiton ang clock_timestamp () function.

Numero nga lima. gamay

Katingad-an gamay

SELECT '111'::bit(4)

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

Hain nga bahin ang kinahanglan nga idugang sa mga piraso kung adunay extension sa tipo? Naa daw sa wala. Apan ang base lamang ang adunay lahi nga opinyon bahin niini nga butang. Pag-amping: kung ang gidaghanon sa mga numero dili motakdo sa pag-cast sa usa ka tipo, dili nimo makuha ang imong gusto. Kini magamit sa pagdugang sa mga tipik sa tuo ug sa pagputol sa mga piraso. Sa tuo usab...

Numero sa file unom. Mga laray

Bisan ang NULL wala nagpabuto

SELECT ARRAY[1, 2] || NULL

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

Ingon sa normal nga mga tawo nga gipadako sa SQL, gipaabut namon nga ang resulta niini nga ekspresyon mahimong NULL. Apan wala kini didto. Gibalik ang usa ka laray. Ngano man? Tungod kay sa kini nga kaso ang base nagbutang sa NULL sa usa ka integer array ug implicitly nagtawag sa array_cat function. Apan nagpabilin nga dili klaro kung ngano nga kini nga "array cat" wala mag-reset sa array. Kini nga pamatasan kinahanglan usab nga hinumdoman.

I-summarize. Adunay daghang katingad-an nga mga butang. Kadaghanan kanila, siyempre, dili kaayo kritikal nga maghisgot bahin sa dayag nga dili angay nga pamatasan. Ug ang uban gipatin-aw pinaagi sa kasayon ​​sa paggamit o sa kasubsob sa ilang paggamit sa pipila ka mga sitwasyon. Apan sa samang higayon, adunay daghang mga sorpresa. Busa, kinahanglang mahibalo ka bahin kanila. Kung nakit-an nimo ang bisan unsang butang nga katingad-an o dili kasagaran sa pamatasan sa bisan unsang klase, isulat sa mga komento, malipay ako nga idugang sa mga dossier nga magamit sa kanila.

Source: www.habr.com

Idugang sa usa ka comment