Mathau amheus

Does dim byd amheus am eu hymddangosiad. Ar ben hynny, maent hyd yn oed yn ymddangos yn gyfarwydd i chi yn dda ac am amser hir. Ond dim ond nes i chi eu gwirio y mae hynny. Dyma lle maen nhw'n dangos eu natur llechwraidd, gan weithio'n hollol wahanol i'r disgwyl. Ac weithiau maen nhw'n gwneud rhywbeth sy'n gwneud i'ch gwallt sefyll ar ei ben ei hun - er enghraifft, maen nhw'n colli data cyfrinachol a ymddiriedir iddynt. Pan fyddwch chi'n eu hwynebu, maen nhw'n honni nad ydyn nhw'n adnabod ei gilydd, er eu bod yn gweithio'n galed o dan yr un cwfl yn y cysgodion. Mae'n bryd dod Γ’ nhw i ddΕ΅r glΓ’n o'r diwedd. Gadewch inni hefyd ymdrin Γ’'r mathau amheus hyn.

Mae teipio data yn PostgreSQL, er ei holl resymeg, weithiau'n peri syndod rhyfedd iawn. Yn yr erthygl hon byddwn yn ceisio egluro rhai o'u quirks, deall y rheswm dros eu hymddygiad rhyfedd a deall sut i beidio Γ’ mynd i mewn i broblemau mewn ymarfer bob dydd. A dweud y gwir, lluniais yr erthygl hon hefyd fel rhyw fath o gyfeirlyfr i mi fy hun, cyfeirlyfr y gellid cyfeirio ato’n hawdd mewn achosion dadleuol. Felly, bydd yn cael ei ailgyflenwi wrth i bethau annisgwyl newydd o fathau amheus gael eu darganfod. Felly, gadewch i ni fynd, o olrheinwyr cronfa ddata diflino!

Ffeil rhif un. cywirdeb gwirioneddol/dwbl/rhifol/arian

Mae'n ymddangos mai mathau rhifol yw'r rhai lleiaf problematig o ran syndod mewn ymddygiad. Ond ni waeth sut y mae. Felly gadewch i ni ddechrau gyda nhw. Felly…

Wedi anghofio sut i gyfri

SELECT 0.1::real = 0.1

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

Beth sy'n bod? Y broblem yw bod PostgreSQL yn trosi'r cysonyn heb ei deipio 0.1 i drachywiredd dwbl ac yn ceisio ei gymharu Γ’ 0.1 o fath go iawn. Ac mae'r rhain yn ystyron hollol wahanol! Y syniad yw cynrychioli rhifau real mewn cof peiriant. Gan na ellir cynrychioli 0.1 fel ffracsiwn deuaidd meidraidd (byddai'n 0.0(0011) mewn deuaidd), bydd niferoedd gyda dyfnder didau gwahanol yn wahanol, a dyna'r canlyniad nad ydynt yn hafal. Yn gyffredinol, mae hwn yn bwnc ar gyfer erthygl ar wahΓ’n; ni fyddaf yn ysgrifennu'n fanylach yma.

O ble mae'r gwall yn dod?

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

Mae llawer o bobl yn gwybod bod PostgreSQL yn caniatΓ‘u nodiant swyddogaethol ar gyfer castio math. Hynny yw, gallwch chi ysgrifennu nid yn unig 1::int, ond hefyd int(1), a fydd yn gyfwerth. Ond nid ar gyfer mathau y mae eu henwau'n cynnwys sawl gair! Felly, os ydych chi am fwrw gwerth rhifol i ddyblu math manwl gywir ar ffurf swyddogaethol, defnyddiwch alias y math hwn float8, hynny yw, SELECT float8(1).

Beth sy'n fwy nag anfeidredd?

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

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

Edrychwch sut brofiad ydyw! Mae'n troi allan bod rhywbeth mwy nag anfeidredd, ac mae'n NaN! Ar yr un pryd, mae dogfennaeth PostgreSQL yn edrych arnom yn onest ac yn honni bod NaN yn amlwg yn fwy nag unrhyw rif arall, ac, felly, yn anfeidredd. Mae'r gwrthwyneb hefyd yn wir am -NaN. Helo, cariadon mathemateg! Ond rhaid inni gofio bod hyn i gyd yn gweithredu yng nghyd-destun rhifau real.

Talgrynnu llygaid

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

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

Cyfarchiad annisgwyl arall o'r gwaelod. Unwaith eto, cofiwch fod cywirdeb dwbl a mathau rhifol yn cael effeithiau talgrynnu gwahanol. Ar gyfer rhifol - yr un arferol, pan fydd 0,5 wedi'i dalgrynnu, ac ar gyfer manwl gywirdeb dwbl - mae 0,5 wedi'i dalgrynnu tuag at y cyfanrif eilrif agosaf.

Mae arian yn rhywbeth arbennig

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

Yn Γ΄l PostgreSQL, nid yw arian yn rhif real. Yn Γ΄l rhai unigolion, hefyd. Mae angen inni gofio mai dim ond i'r math rhifol y gellir bwrw'r math o arian, yn union fel mai dim ond y math rhifol y gellir ei fwrw i'r math o arian. Ond nawr gallwch chi chwarae ag ef fel y mae eich calon yn dymuno. Ond nid yr un arian fydd e.

Cynhyrchu Smallint a dilyniant

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

Nid yw PostgreSQL yn hoffi gwastraffu amser ar drifles. Beth mae'r dilyniannau hyn yn seiliedig ar smallint? int, dim llai! Felly, wrth geisio gweithredu'r ymholiad uchod, mae'r gronfa ddata yn ceisio taflu smallint i ryw fath cyfanrif arall, ac yn gweld y gall fod sawl cast o'r fath. Pa gast i ddewis? Ni all hi benderfynu hyn, ac felly mae'n gwrthdaro Γ’ gwall.

Ffeil rhif dau. "char"/char/varchar/testun

Mae nifer o ryfeddodau hefyd yn bresennol mewn mathau o gymeriad. Gadewch i ni ddod i'w hadnabod hefyd.

Pa fath o driciau yw'r rhain?

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

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

Pa fath o "torgoch" yw hwn, pa fath o glown yw hwn? Nid oes angen y rheini arnom... Oherwydd ei fod yn esgus bod yn golosg cyffredin, er ei fod mewn dyfyniadau. Ac mae'n wahanol i golosg rheolaidd, sydd heb ddyfyniadau, gan ei fod yn allbynnu beit cyntaf y cynrychioliad llinyn yn unig, tra bod torgoch arferol yn allbynnu'r nod cyntaf. Yn ein hachos ni, y nod cyntaf yw'r llythyren P, sydd yn y cynrychioliad unicode yn cymryd 2 beit, fel y dangosir trwy drosi'r canlyniad i'r math byte. Ac mae'r math β€œtorgoch” yn cymryd dim ond y beit cyntaf o'r gynrychiolaeth unicode hwn. Yna pam mae angen y math hwn? Mae dogfennaeth PostgreSQL yn dweud bod hwn yn fath arbennig a ddefnyddir ar gyfer anghenion arbennig. Felly mae'n annhebygol y bydd ei angen arnom. Ond edrychwch i mewn i'w lygaid ac ni fyddwch yn camgymryd pan fyddwch yn cwrdd ag ef gyda'i ymddygiad arbennig.

Mannau ychwanegol. Allan o olwg, allan o feddwl

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

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

Cymerwch olwg ar yr enghraifft a roddwyd. Trosais yr holl ganlyniadau yn arbennig i'r math byte, fel ei bod yn amlwg beth oedd yno. Ble mae'r gofodau llusgo ar Γ΄l castio i varchar(6)? Mae'r ddogfennaeth yn nodi'n gryno: "Wrth fwrw gwerth cymeriad i fath arall o gymeriad, mae gofod gwyn llusgo yn cael ei daflu." Rhaid cofio'r atgasedd hwn. A sylwch, os yw cysonyn llinynnol a ddyfynnir yn cael ei gastio'n uniongyrchol i deipio varchar(6), mae'r gofodau llusgo yn cael eu cadw. Y fath yw y gwyrthiau.

Ffeil rhif tri. json/jsonb

Mae JSON yn strwythur ar wahΓ’n sy'n byw ei fywyd ei hun. Felly, mae ei endidau ac endidau PostgreSQL ychydig yn wahanol. Dyma enghreifftiau.

Johnson a Johnson. teimlo'r gwahaniaeth

SELECT 'null'::jsonb IS NULL

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

Y peth yw bod gan JSON ei endid nwl ei hun, nad yw'n analog NULL yn PostgreSQL. Ar yr un pryd, mae'n bosibl iawn y bydd gan y gwrthrych JSON ei hun y gwerth NULL, felly bydd yr ymadrodd SELECT null::jsonb IS NULL (sylwch nad oes dyfyniadau sengl) yn dychwelyd yn wir y tro hwn.

Mae un llythyren yn newid popeth

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

Y peth yw bod json a jsonb yn strwythurau hollol wahanol. Yn json, mae'r gwrthrych yn cael ei storio fel y mae, ac yn jsonb mae eisoes wedi'i storio ar ffurf strwythur wedi'i ddosrannu, wedi'i fynegeio. Dyna pam yn yr ail achos, cafodd gwerth y gwrthrych gan allwedd 1 ei ddisodli o [1, 2, 3] i [7, 8, 9], a ddaeth i mewn i'r strwythur ar y diwedd gyda'r un allwedd.

Peidiwch ag yfed dΕ΅r o'ch wyneb

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

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

Mae PostgreSQL yn ei weithrediad JSONB yn newid fformatio rhifau real, gan ddod Γ’ nhw i'r ffurf glasurol. Nid yw hyn yn digwydd ar gyfer y math JSON. Ychydig yn rhyfedd, ond mae'n iawn.

Ffeil rhif pedwar. dyddiad/amser/stamp amser

Mae rhai pethau rhyfedd hefyd gyda mathau o ddyddiad/amser. Gadewch i ni edrych arnynt. Gadewch imi wneud amheuaeth ar unwaith bod rhai o'r nodweddion ymddygiadol yn dod yn glir os ydych chi'n deall yn dda hanfod gweithio gyda pharthau amser. Ond mae hwn hefyd yn bwnc ar gyfer erthygl ar wahΓ’n.

Nid yw fy un chi yn deall

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

Mae'n ymddangos bod yr hyn sy'n annealladwy yma? Ond nid yw'r gronfa ddata yn deall beth rydyn ni'n ei roi yn y lle cyntaf yma - y flwyddyn neu'r diwrnod? Ac mae hi'n penderfynu mai Ionawr 99, 2008, sy'n chwythu ei meddwl. Yn gyffredinol, wrth drosglwyddo dyddiadau ar ffurf testun, mae angen i chi wirio'n ofalus iawn pa mor gywir y mae'r gronfa ddata yn eu hadnabod (yn benodol, dadansoddi'r paramedr arddull dyddiad gyda'r gorchymyn arddull dyddiad SHOW), oherwydd gall amwyseddau yn y mater hwn fod yn ddrud iawn.

O ble cawsoch chi hwn?

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

Pam na all y gronfa ddata ddeall yr amser penodol? Oherwydd nad oes gan y parth amser dalfyriad, ond enw llawn, sy'n gwneud synnwyr yng nghyd-destun dyddiad yn unig, gan ei fod yn cymryd i ystyriaeth hanes newidiadau parth amser, ac nid yw'n gweithio heb ddyddiad. Ac mae union eiriad y llinell amser yn codi cwestiynau - beth oedd gwir ystyr y rhaglennydd? Felly, mae popeth yn rhesymegol yma, os edrychwch arno.

Beth sy'n bod arno?

Dychmygwch y sefyllfa. Mae gennych faes yn eich bwrdd gyda stamp amser teip. Rydych chi eisiau ei fynegeio. Ond rydych chi'n deall nad yw adeiladu mynegai ar y maes hwn bob amser yn gyfiawn oherwydd ei ddetholusrwydd uchel (bydd bron pob gwerth o'r math hwn yn unigryw). Felly rydych chi'n penderfynu lleihau detholedd y mynegai trwy gastio'r math i ddyddiad. Ac rydych chi'n cael syrpreis:

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

Beth sy'n bod? Y ffaith yw bod gwerth paramedr system TimeZone yn cael ei ddefnyddio i fwrw math stamp amser i fath o ddyddiad, sy'n gwneud y swyddogaeth trosi math yn dibynnu ar baramedr arferiad, h.y. anweddol. Ni chaniateir swyddogaethau o'r fath yn y mynegai. Yn yr achos hwn, rhaid i chi nodi'n benodol ym mha gylchfa amser y mae'r cast math yn cael ei berfformio.

Pan nad yw nawr hyd yn oed nawr o gwbl

Rydym wedi arfer Γ’ nawr() dychwelyd y dyddiad/amser cyfredol, gan ystyried y parth amser. Ond edrychwch ar yr ymholiadau canlynol:

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;

Mae'r dyddiad/amser yn cael ei ddychwelyd yr un fath ni waeth faint o amser sydd wedi mynd heibio ers y cais blaenorol! Beth sy'n bod? Y ffaith yw nad nawr() yw'r amser presennol, ond amser cychwyn y trafodiad cyfredol. Felly, nid yw'n newid o fewn y trafodiad. Mae unrhyw ymholiad a lansiwyd y tu allan i gwmpas trafodiad yn cael ei lapio mewn trafodiad yn ymhlyg, a dyna pam nad ydym yn sylwi bod yr amser a ddychwelwyd gan SELECT syml nawr(); mewn gwirionedd, nid yr un presennol... Os ydych chi am gael amser cerrynt gonest, mae angen i chi ddefnyddio'r swyddogaeth clock_timestamp().

Ffeil rhif pump. bit

Rhyfedd braidd

SELECT '111'::bit(4)

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

Pa ochr y dylid ychwanegu'r darnau rhag ofn estyniad math? Mae'n ymddangos ei fod ar y chwith. Ond dim ond y sylfaen sydd Γ’ barn wahanol ar y mater hwn. Byddwch yn ofalus: os nad yw nifer y digidau yn cyfateb wrth gastio math, ni chewch yr hyn yr oeddech ei eisiau. Mae hyn yn berthnasol i ychwanegu darnau i'r dde a trimio darnau. Hefyd ar y dde...

Ffeil rhif chwech. Araeau

Ni wnaeth hyd yn oed NULL danio

SELECT ARRAY[1, 2] || NULL

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

Wrth i bobl arferol godi ar SQL, disgwyliwn i ganlyniad yr ymadrodd hwn fod yn NULL. Ond nid oedd yno. Dychwelir arae. Pam? Oherwydd yn yr achos hwn mae'r sylfaen yn taflu NULL i arae cyfanrif ac yn ymhlyg yn galw'r swyddogaeth array_cat. Ond mae'n dal yn aneglur pam nad yw'r β€œgath arae” hon yn ailosod yr arae. Mae angen cofio'r ymddygiad hwn hefyd.

Crynhoi. Mae digon o bethau rhyfedd. Nid yw'r rhan fwyaf ohonynt, wrth gwrs, mor hanfodol Γ’ siarad am ymddygiad amlwg amhriodol. Ac mae eraill yn cael eu hesbonio gan rwyddineb defnydd neu amlder eu cymhwysedd mewn rhai sefyllfaoedd. Ond ar yr un pryd, mae yna lawer o bethau annisgwyl. Felly, mae angen i chi wybod amdanynt. Os byddwch yn dod o hyd i unrhyw beth arall rhyfedd neu anarferol yn ymddygiad o unrhyw fath, ysgrifennwch yn y sylwadau, byddaf yn hapus i ychwanegu at y coflenni sydd ar gael arnynt.

Ffynhonnell: hab.com

Ychwanegu sylw