Cineálacha amhrasacha

Níl aon rud amhrasach faoina gcuma. Thairis sin, is cosúil go bhfuil siad eolach go maith duit fiú agus ar feadh i bhfad. Ach níl sé sin ach go dtí go seiceálann tú iad. Seo é an áit a léiríonn siad a nádúr insidious, ag obair go hiomlán difriúil ná mar a bhí súil agat. Agus uaireanta a dhéanann siad rud éigin a chuireann ar do chuid gruaige seasamh ar an deireadh - mar shampla, caillfidh siad sonraí rúnda a chuirtear de chúram orthu. Nuair a thugann tú aghaidh orthu, éilíonn siad nach bhfuil aithne acu ar a chéile, cé go n-oibríonn siad go dian faoin gcochall céanna faoi na scáthanna. Tá sé in am iad a thabhairt chuig uisce glan ar deireadh. Lig dúinn déileáil leis na cineálacha amhrasacha seo freisin.

Uaireanta bíonn iontas an-aisteach ar chlóscríobh sonraí in PostgreSQL, mar gheall ar a loighic ar fad. San Airteagal seo déanfaimid iarracht cuid dá gcuid quirks a shoiléiriú, tuiscint a fháil ar an gcúis lena n-iompraíocht aisteach agus tuiscint a fháil ar conas gan dul i ngleic le fadhbanna i gcleachtas laethúil. Chun an fhírinne a rá, chuir mé an t-alt seo le chéile freisin mar chineál leabhar tagartha dom féin, leabhar tagartha a bhféadfaí tagairt a dhéanamh dó go héasca i gcásanna conspóideacha. Dá bhrí sin, déanfar é a athlánú de réir mar a aimsítear iontas nua ó chineálacha amhrasacha. Mar sin, buail an bóthar, sealgairí bunachar sonraí gan staonadh!

Comhad uimhir a haon. beachtas fíor/dúbailte/uimhriúil/airgead

Dhealródh sé go bhfuil cineálacha uimhriúla na fadhbanna is lú i dtéarmaí iontas san iompar. Ach is cuma conas atá sé. Mar sin, a ligean ar tús a chur leo. Mar sin…

Dearmad ar conas a chomhaireamh

SELECT 0.1::real = 0.1

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

Céard atá ort? Is í an fhadhb atá ann ná go ndéanann PostgreSQL an tairiseach neamhchlóscríofa 0.1 a thiontú go cruinneas dúbailte agus déanann sé iarracht é a chur i gcomparáid le 0.1 den fhíorchineál. Agus is bríonna go hiomlán difriúil iad seo! Is é an smaoineamh fíoruimhreacha a léiriú i gcuimhne meaisín. Ós rud é nach féidir 0.1 a léiriú mar chodán dénártha críochta (bheadh ​​sé 0.0(0011) ina dhénártha), beidh na huimhreacha le doimhneachtaí giotáin difriúla difriúil, agus mar sin is é an toradh nach bhfuil siad cothrom. Go ginearálta, is ábhar é seo le haghaidh alt ar leith; ní scríobhfaidh mé níos mine anseo.

Cad as a dtagann an earráid?

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

Tá a fhios ag go leor daoine go gceadaíonn PostgreSQL nodaireacht fheidhmiúil le haghaidh cineál-réitigh. Is é sin, is féidir leat scríobh ní hamháin 1::int, ach freisin int(1), a bheidh comhionann. Ach ní le haghaidh cineálacha a bhfuil a n-ainmneacha comhdhéanta de roinnt focal! Dá bhrí sin, más mian leat luach uimhriúil a chaitheamh chun cineál cruinneas a dhúbailt i bhfoirm fheidhmiúil, bain úsáid as an ailias den chineál seo float8, is é sin, SELECT float8(1).

Cad atá níos mó ná Infinity?

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

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

Féach cad é mar! Tharlaíonn sé go bhfuil rud éigin níos mó ná Infinity, agus tá sé NaN! Ag an am céanna, breathnaíonn doiciméadú PostgreSQL orainn le súile macánta agus maíonn sé gur léir go bhfuil NaN níos mó ná aon uimhir eile, agus, dá bhrí sin, gan teorainn. Tá a mhalairt fíor freisin maidir le -NaN. Dia duit, lovers matamaitice! Ach ní mór dúinn cuimhneamh go n-oibríonn sé seo go léir i gcomhthéacs na bhfíoruimhreacha.

Súl slánú

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

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

Beannacht eile gan choinne ón mbonn. Arís, cuimhnigh go bhfuil éifeachtaí slánúcháin éagsúla ag cruinneas dúbailte agus cineálacha uimhriúla. Le haghaidh uimhriúil - an gnáthcheann, nuair a dhéantar 0,5 a shlánú, agus le haghaidh cruinneas dúbailte - déantar 0,5 a shlánú i dtreo an tslánuimhir chothrom is gaire.

Is rud speisialta é airgead

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

De réir PostgreSQL, ní fíoruimhir é airgead. Dar le roinnt daoine aonair, freisin. Ní mór dúinn cuimhneamh nach féidir an cineál airgid a chaitheamh ach leis an gcineál uimhriúil, díreach mar nach féidir ach an cineál uimhriúil a chaitheamh leis an gcineál airgid. Ach anois is féidir leat imirt leis mar is mian le do chroí. Ach ní bheidh sé ar an airgead céanna.

Smallint agus giniúint seicheamh

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

Ní maith le PostgreSQL am a chur amú ar trifles. Cad iad na seichimh seo atá bunaithe ar smallint? int, nach lú! Mar sin, nuair a dhéantar iarracht an cheist thuas a chur i gcrích, déanann an bunachar sonraí iarracht beag a chaitheamh ar shlánuimhir éigin eile, agus feictear dó go bhféadfadh go mbeadh roinnt castaí dá leithéid ann. Cé acu teilgthe a roghnú? Ní féidir léi é seo a chinneadh, agus mar sin bíonn earráid uirthi.

Comhad uimhir a dó. "char"/char/varchar/téacs

Tá roinnt aisteacha i láthair freisin i gcineálacha carachtar. Cuirimis aithne orthu freisin.

Cén sórt cleasanna iad seo?

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

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

Cén cineál "char" é seo, cén cineál clown é seo? Níl siad sin de dhíth orainn... Toisc go ligeann sé air gur gnáthcharr é, cé go bhfuil sé i Sleachta. Agus tá sé difriúil ó ruabhreac rialta, atá gan comharthaí athfhriotail, sa mhéid is nach n-aschuireann sé ach an chéad bheart den léiriú teaghrán, agus aschuireann gnáth-charr an chéad charachtar. Inár gcás, is é an litir P an chéad charachtar, a thógann suas le 2 beart san ionadaíocht Unicode, mar is léir ón toradh a thiontú go dtí an cineál bytea. Agus ní thógann an cineál “charr” ach an chéad bheart den léiriú Unicode seo. Ansin cén fáth a bhfuil gá leis an gcineál seo? Deir doiciméadú PostgreSQL gur cineál speisialta é seo a úsáidtear le haghaidh riachtanas speisialta. Mar sin ní dócha go mbeidh gá againn leis. Ach féach isteach ina shúile agus ní bheidh aon dul amú ort nuair a bhuailfidh tú leis lena iompar speisialta.

Spásanna breise. As radharc, out of mind

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

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

Féach ar an sampla a thugtar. Thiontaigh mé na torthaí go léir go speisialta don chineál bytea, ionas go raibh sé le feiceáil go soiléir cad a bhí ann. Cá bhfuil na spásanna rianaithe tar éis iad a chaitheamh go varchar(6)? Deir an doiciméadú go gonta: "Nuair a bhíonn luach an charachtair á chaitheamh ar chineál carachtar eile, cuirtear spás bán ar leataobh." Ní mór cuimhneamh ar an neamhshuim seo. Agus tabhair faoi deara má chaitear tairiseach teaghrán luaite go díreach chuig cineál varchar(6), go gcaomhnaítear na spásanna rianaithe. Is iad sin na míorúiltí.

Comhad uimhir a trí. json/sonb

Is struchtúr ar leith é JSON a chónaíonn a shaol féin. Mar sin, tá a heintitis agus eintitis PostgreSQL beagán difriúil. Seo samplaí.

Johnson agus Johnson. bhraitheann an difríocht

SELECT 'null'::jsonb IS NULL

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

Is é an rud go bhfuil a eintiteas nialasach féin ag JSON, nach é an t-analóg de NULL i PostgreSQL. Ag an am céanna, d'fhéadfadh go mbeadh an luach NULLComment ag an réad JSON féin, mar sin beidh an slonn SELECT null::jsonb IS NULL (tabhair faoi deara nach bhfuil comharthaí athfhriotail aonair ann) ar ais fíor an uair seo.

Athraíonn litir amháin gach rud

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

Is é an rud gur struchtúir go hiomlán difriúil iad json agus jsonb. In json, stóráiltear an réad mar atá, agus in jsonb tá sé stóráilte cheana féin i bhfoirm struchtúr parsáilte, innéacsaithe. Sin é an fáth sa dara cás, athraíodh luach an ruda le heochair 1 ó [1, 2, 3] go [7, 8, 9], a tháinig isteach sa struchtúr ag an deireadh leis an eochair chéanna.

Ná hól uisce ó d'aghaidh

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

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

Athraíonn PostgreSQL ina chur i bhfeidhm JSONB formáidiú réaduimhreacha, rud a thugann go dtí an fhoirm chlasaiceach iad. Ní tharlaíonn sé seo don chineál JSON. Beagán aisteach, ach tá an ceart aige.

Comhad uimhir a ceathair. dáta/am/stampa ama

Tá roinnt aisteacha ann freisin maidir le cineálacha dáta/ama. Breathnaímid orthu. Lig dom a chur in áirithe ar an bpointe boise go n-éiríonn cuid de na gnéithe iompraíochta soiléir má thuigeann tú go maith an croílár a bhaineann le bheith ag obair le criosanna ama. Ach is ábhar é seo freisin le haghaidh alt ar leith.

Ní thuigeann mo cheannsa

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

Bheadh ​​sé cosúil go bhfuil cad atá dothuigthe anseo? Ach ní thuigeann an bunachar sonraí fós cad a chuireamar sa chéad áit anseo – an bhliain nó an lá? Agus cinneann sí gurb é 99 Eanáir, 2008, a shéideann a intinn. Go ginearálta, agus dátaí á dtarchur i bhformáid téacs, ní mór duit a sheiceáil go han-chúramach cé chomh cruinn agus a d’aithin an bunachar sonraí iad (go háirithe, anailís a dhéanamh ar an bparaiméadar datestyle leis an ordú SHOW datestyle), mar is féidir le débhríochtaí san ábhar seo a bheith an-chostasach.

Cad as a bhfuair tú é seo?

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

Cén fáth nach féidir leis an mbunachar sonraí an t-am sonraithe a thuiscint? Toisc nach bhfuil giorrúchán ag an gcrios ama, ach ainm iomlán, a dhéanann ciall ach amháin i gcomhthéacs dáta, ós rud é go gcuireann sé san áireamh stair na n-athruithe crios ama, agus ní oibríonn sé gan dáta. Agus ardaíonn foclaíocht an líne ama ceisteanna - cad a bhí i gceist ag an ríomhchláraitheoir i ndáiríre? Dá bhrí sin, tá gach rud loighciúil anseo, má fhéachann tú air.

Cad atá cearr leis?

Samhlaigh an scéal. Tá réimse agat i do tábla le stampa ama cineál. Ba mhaith leat é a innéacsú. Ach tuigeann tú nach bhfuil údar i gcónaí le hinnéacs a thógáil sa réimse seo mar gheall ar a roghnaíocht ard (Beidh beagnach gach luach den chineál seo uathúil). Mar sin socraíonn tú roghnaíocht an innéacs a laghdú tríd an gcineál a chaitheamh go dáta. Agus faigheann tú iontas:

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

Céard atá ort? Is é an fírinne ná chun cineál stampa ama a chaitheamh go cineál dáta, úsáidtear luach paraiméadar an chórais TimeZone, rud a fhágann go bhfuil feidhm chomhshó an chineáil ag brath ar pharaiméadar saincheaptha, i.e. luaineach. Ní cheadaítear feidhmeanna den sórt sin san innéacs. Sa chás seo, ní mór duit a chur in iúl go sainráite cén crios ama a dhéantar an cineál teilgthe.

Nuair nach bhfuil anois fiú anois ar chor ar bith

Tá sé de nós againn anois() an dáta/am reatha a thabhairt ar ais, agus an crios ama á chur san áireamh. Ach féach ar na ceisteanna seo a leanas:

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;

Seoltar an dáta/am ar ais mar an gcéanna is cuma cé mhéad ama atá caite ón iarratas roimhe! Céard atá ort? Is é fírinne an scéil nach é anois() an t-am reatha, ach am tosaithe an idirbhirt reatha. Dá bhrí sin, ní athraíonn sé laistigh den idirbheart. Tá aon cheist a sheoltar lasmuigh de raon feidhme idirbhirt fillte in idirbheart go hintuigthe, agus is é sin an fáth nach dtugaimid faoi deara go bhfuil an t-am ar ais ag SELECT simplí anois(); le fírinne, ní an ceann reatha... Más mian leat am reatha macánta a fháil, ní mór duit an fheidhm clock_timestamp() a úsáid.

Comhad uimhir a cúig. giotán

Aisteach le beagán

SELECT '111'::bit(4)

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

Cén taobh ar cheart na giotáin a chur leis i gcás síneadh cineáil? Is cosúil go bhfuil sé ar chlé. Ach níl ach tuairim éagsúil ag an mbonn ar an ábhar seo. Bí cúramach: más rud é nach ionann líon na n-digití agus cineál á chaitheamh agat, ní bhfaighidh tú an méid a bhí uait. Baineann sé seo le giotán a chur leis an gceart agus le bearradh. Chomh maith leis sin ar dheis ...

Comhad uimhir a sé. Arrays

Níor chuir NULL an tine fiú

SELECT ARRAY[1, 2] || NULL

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

Mar a d’ardaigh gnáthdhaoine ar SQL, táimid ag súil go mbeidh toradh na slonn seo NULLComment. Ach ní raibh sé ann. Cuirtear eagar ar ais. Cén fáth? Toisc sa chás seo caitheann an bonn NULLComment le sraith slánuimhir agus glaonna go hintuigthe ar an bhfeidhm array_cat. Ach níl sé soiléir fós cén fáth nach ndéanann an “cat eagair” seo an t-eagar a athshocrú. Ní mór cuimhneamh ar an iompar seo freisin.

Achoimre. Tá neart rudaí aisteacha ann. Ar ndóigh, níl an chuid is mó acu chomh ríthábhachtach chun labhairt faoi iompar mí-oiriúnach. Agus mínítear cinn eile trí éascaíocht úsáide nó minicíocht a n-infheidhmithe i gcásanna áirithe. Ach ag an am céanna, tá go leor iontas ann. Dá bhrí sin, ní mór duit fios a bheith agat mar gheall orthu. Má fhaigheann tú aon rud eile aisteach nó neamhghnách in iompar de chineál ar bith, scríobh sna tuairimí, beidh mé sásta cur leis na sainchomhaid atá ar fáil orthu.

Foinse: will.com

Add a comment