Jenis curiga

Aya nanaon curiga ngeunaan penampilan maranéhanana. Leuwih ti éta, maranéhna malah sigana wawuh ka anjeun ogé sarta pikeun lila. Tapi éta ngan dugi ka pariksa aranjeunna. Ieu dimana aranjeunna nunjukkeun sipat insidious maranéhanana, digawé sagemblengna béda ti anjeun nyangka. Sareng sakapeung aranjeunna ngalakukeun hal anu ngajantenkeun rambut anjeun nangtung - contona, aranjeunna kaleungitan data rahasia anu dipercayakeun ka aranjeunna. Nalika anjeun nyanghareupan aranjeunna, aranjeunna ngaku yén aranjeunna henteu terang silih, sanaos dina kalangkang aranjeunna kerja keras dina tiung anu sami. Geus waktuna pikeun tungtungna mawa aranjeunna ka cai bersih. Hayu urang ogé nungkulan jenis curiga ieu.

Ngetik data dina PostgreSQL, pikeun sadaya logikana, sakapeung aya kejutan anu anéh. Dina artikel ieu kami baris coba pikeun netelakeun sababaraha quirks maranéhanana, ngartos alesan pikeun kabiasaan aneh maranéhanana sarta ngarti kumaha teu ngajalankeun kana masalah dina prakték sapopoé. Sabenerna, kuring nyusun artikel ieu ogé salaku jenis buku rujukan pikeun kuring sorangan, buku rujukan anu bisa gampang disebut dina kasus kontroversial. Ku alatan éta, éta bakal dieusi deui nalika kejutan anyar tina jinis anu curiga kapanggih. Janten, hayu urang angkat, oh pelacak pangkalan data anu teu bosen!

Dossier nomer hiji. nyata / precision ganda / angka / duit

Ieu bakal sigana yén jenis numerik nu pangsaeutikna masalah dina watesan kejutan dina kabiasaan. Tapi euweuh urusan kumaha éta. Ku kituna hayu urang mimitian ku aranjeunna. Jadi…

Poho kumaha ngitungna

SELECT 0.1::real = 0.1

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

Naon masalahna? Masalahna nyaéta PostgreSQL ngarobih konstanta anu teu diketik 0.1 ka precision ganda sareng nyobian ngabandingkeunana sareng 0.1 tina jinis nyata. Sareng ieu mangrupikeun hartos anu béda-béda! Ide pikeun ngagambarkeun wilangan riil dina mémori mesin. Kusabab 0.1 teu bisa digambarkeun salaku fraksi binér terhingga (éta bakal 0.0 (0011) dina binér), angka kalawan jero bit béda bakal béda, ku kituna hasilna aranjeunna henteu sarua. Sacara umum, ieu mangrupikeun topik pikeun tulisan anu misah;

Dimana kasalahan asalna?

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

Seueur jalma terang yén PostgreSQL ngamungkinkeun notasi fungsional pikeun jinis tuang. Nyaéta, anjeun tiasa nyerat sanés ngan ukur 1:: int, tapi ogé int (1), anu bakal sami. Tapi sanés pikeun jinis anu namina diwangun ku sababaraha kecap! Ku alatan éta, upami anjeun hoyong tuang nilai numerik kana tipe precision ganda dina formulir fungsi, make alias tina tipe ieu float8, nyaeta, SELECT float8 (1).

Naon anu langkung ageung tibatan takterhingga?

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

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

Tingali kumaha éta! Tétéla aya nu leuwih badag batan infinity, sarta éta NaN! Dina waktos anu sami, dokuméntasi PostgreSQL ningali urang kalayan jujur ​​​​sareng nyatakeun yén NaN écés langkung ageung tibatan nomer anu sanés, sareng, ku kituna, teu aya watesna. Sabalikna oge bener keur -NaN. Halo, pencinta matematika! Tapi urang kudu inget yen sakabeh ieu ngoperasikeun dina konteks wilangan riil.

Panon buleud

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

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

Lain salam kaduga ti pangkalan. Sakali deui, émut yén precision ganda sareng jinis angka gaduh épék rounding anu béda. Pikeun numerik - anu biasa, nalika 0,5 dibuleudkeun, sareng pikeun katepatan ganda - 0,5 dibuleudkeun ka arah integer anu paling caket.

Duit mangrupikeun hal anu khusus

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

Numutkeun kana PostgreSQL, artos sanés nomer nyata. Numutkeun sababaraha individu, teuing. Urang kudu inget yen tuang jenis duit ngan mungkin mun tipe numerik, sagampil ukur tipe numerik bisa tuang kana jenis duit. Tapi ayeuna anjeun tiasa maénkeun éta salaku kahayang haté anjeun. Tapi moal sarua duit.

Smallint jeung runtuyan generasi

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 henteu resep miceunan waktos dina hal-hal anu teu penting. Naon runtuyan ieu dumasar kana smallint? int, teu kurang! Ku alatan éta, nalika nyobian ngaéksekusi query di luhur, database nyoba tuang smallint kana sababaraha tipe integer séjén, sarta ningali yén meureun aya sababaraha casts misalna. Nu matak milih? Manehna teu bisa mutuskeun ieu, sarta ku kituna ngadat jeung kasalahan.

Berkas nomer dua. "char"/char/varchar/text

Sajumlah oddities ogé hadir dina tipe karakter. Hayu urang kenal ogé.

Naon jenis trik ieu?

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

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

Naon jenis "char" ieu, jenis badut naon ieu? Kami henteu peryogi éta ... Kusabab éta nyamar janten char biasa, sanaos dina tanda petik. Sarta eta béda ti char biasa, nu tanpa tanda petik, dina eta kaluaran ukur bait mimiti ngagambarkeun string, bari char normal kaluaran karakter munggaran. Dina kasus urang, karakter kahiji nyaéta hurup P, anu dina representasi unicode nyokot 2 bait, sakumaha dibuktikeun ku ngarobah hasilna kana tipe bytea. Sareng jinis "char" ngan ukur nyandak bait munggaran tina perwakilan unicode ieu. Lajeng naha jenis ieu diperlukeun? Dokuméntasi PostgreSQL nyarios yén ieu mangrupikeun jinis khusus anu dianggo pikeun kabutuhan khusus. Ku kituna urang teu dipikaresep butuh eta. Tapi neuteup kana panonna jeung anjeun moal salah mun anjeun papanggih anjeunna kalawan kabiasaan husus na.

spasi tambahan. Kaluar tina tetempoan, kaluar tina pikiran

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

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

Tingali kana conto anu dipasihkeun. Kuring sacara khusus ngarobih sadayana hasil kana jinis bait, supados jelas katingali naon anu aya. Dimana spasi labuh sanggeus casting ka varchar (6)? Dokuméntasi sacara ringkes nyarios: "Nalika tuang nilai karakter kana jinis karakter anu sanés, spasi bodas anu aya dibuang." Teu resep ieu kudu diinget. Jeung perhatikeun yén lamun konstanta string dicutat matak langsung ka tipe varchar (6), spasi labuh dilestarikan. Sapertos anu mujijat.

Berkas nomer tilu. json/jsonb

JSON mangrupikeun struktur anu misah anu hirupna nyalira. Ku alatan éta, éntitas na sareng PostgreSQL rada béda. Ieu conto.

Adang jeung Adang. ngarasa bédana

SELECT 'null'::jsonb IS NULL

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

Hal éta JSON gaduh éntitas null sorangan, anu sanés analog tina NULL di PostgreSQL. Dina waktos anu sami, objek JSON nyalira tiasa gaduh nilai NULL, janten ekspresi SELECT null::jsonb IS NULL (perhatikeun henteuna tanda petik tunggal) bakal leres-leres ayeuna.

Hiji hurup ngarobah sagalana

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

Masalahna nyaéta json sareng jsonb mangrupikeun struktur anu béda-béda. Dina json, obyék disimpen sakumaha anu kasebut, sareng dina jsonb éta parantos disimpen dina bentuk parsed, struktur indéks. Éta pisan sababna naha dina kasus kadua, nilai obyék ku konci 1 diganti tina [1, 2, 3] ka [7, 8, 9], nu sumping kana struktur di pisan tungtung jeung konci anu sarua.

Ulah nginum cai tina beungeut anjeun

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

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

PostgreSQL dina palaksanaan JSONB na ngarobah pormat angka riil, mawa kana formulir klasik. Ieu henteu lumangsung pikeun tipe JSON. Saeutik aneh, tapi anjeunna leres.

Berkas nomer opat. titimangsa / waktos / cap waktu

Aya ogé sababaraha oddities kalawan jenis tanggal / waktos. Hayu urang tingali aranjeunna. Hayu atuh nyieun reservasi langsung yén sababaraha fitur behavioral jadi jelas lamun ngarti ogé hakekat gawé bareng zona waktu. Tapi ieu ogé topik pikeun artikel misah.

Abdi anjeun teu ngartos

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

Éta sigana naon anu teu kaharti di dieu? Tapi database masih teu ngarti naon urang nempatkeun di tempat munggaran di dieu-taun atawa poé? Sarta manéhna megatkeun yén éta téh 99 Januari 2008, nu blows pikiran nya. Sacara umum, nalika ngirimkeun tanggal dina format téks, anjeun kedah taliti pisan mariksa kumaha leres databés ngakuan aranjeunna (khususna, analisa parameter datestyle sareng paréntah SHOW datestyle), sabab ambiguitas dina masalah ieu tiasa mahal pisan.

Ti mana anjeun meunang ieu?

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

Naha pangkalan data henteu tiasa ngartos waktos anu dijelaskeun sacara eksplisit? Kusabab zona waktu teu boga singketan, tapi ngaran lengkep, nu ngajadikeun rasa ukur dina konteks tanggal hiji, saprak eta tumut kana akun sajarah parobahan zone waktos, sarta teu dianggo tanpa tanggal hiji. Sareng kecap-kecap tina garis waktos nyababkeun patarosan - naon hartosna programer? Ku alatan éta, sagalana geus logis di dieu, lamun nempo eta.

Aya naon nya?

Bayangkeun kaayaan. Anjeun gaduh sawah dina tabel anjeun sareng tipe timestamptz. Anjeun hoyong indéks eta. Tapi anjeun ngartos yén ngawangun indéks dina widang ieu teu salawasna diyakinkeun alatan selectivity tinggi na (ampir kabéh nilai tina tipe ieu bakal unik). Janten anjeun mutuskeun pikeun ngirangan selektipitas indéks ku tuang jinisna ka tanggal hiji. Sareng anjeun nampi kejutan:

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

Naon masalahna? Kanyataanna nyaéta pikeun tuang jinis timestamptz kana jinis tanggal, nilai parameter sistem TimeZone dianggo, anu ngajantenkeun fungsi konversi jinis gumantung kana parameter khusus, i.e. volatile. fungsi sapertos teu diwenangkeun dina indéks dina. Dina hal ieu, anjeun kedah sacara eksplisit nunjukkeun zona waktos dimana jinis tuang dilaksanakeun.

Kapan ayeuna mah malah ayeuna pisan

Kami dipaké pikeun ayeuna () balik tanggal ayeuna / waktos, nyokot kana akun zone waktos. Tapi tingali patarosan di handap ieu:

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;

Tanggal / waktos dipulangkeun sami henteu paduli sabaraha waktos anu kapungkur ti pamundut sateuacana! Naon masalahna? Kanyataan yén ayeuna () sanes waktos ayeuna, tapi waktos mimiti urus ayeuna. Ku alatan éta, teu robah dina urus. Sakur pamundut anu diluncurkeun di luar lingkup transaksi dibungkus dina transaksi sacara implisit, naha urang henteu perhatikeun yén waktosna dipulangkeun ku PILIH anu sederhana ayeuna (); saleresna, teu hiji ayeuna ... Lamun hayang meunang hiji waktos ayeuna jujur, anjeun kudu make clock_timestamp () fungsi.

Berkas nomer lima. bit

Aneh saeutik

SELECT '111'::bit(4)

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

Sisi mana anu kedah ditambihkeun bit upami aya ekstensi jinis? Sigana di kénca. Tapi ngan dasarna boga pamadegan béda dina hal ieu. Ati-ati: upami jumlah digit henteu cocog nalika tuang jinis, anjeun moal kéngingkeun anu dipikahoyong. Ieu lumaku pikeun duanana nambahkeun bit ka katuhu jeung motong bit. Ogé di katuhu ...

Berkas nomer genep. Arrays

Malah NULL henteu hurung

SELECT ARRAY[1, 2] || NULL

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

Salaku jalma normal digedékeun dina SQL, urang ngaharepkeun hasil tina ekspresi ieu NULL. Tapi teu aya. A Asép Sunandar Sunarya balik. Naha? Kusabab dina hal ieu dasarna tuang NULL ka array integer sareng sacara implisit nyauran fungsi array_cat. Tapi tetep can écés naha ieu "ucing array" teu ngareset Asép Sunandar Sunarya. Kalakuan ieu ogé ngan perlu diinget.

nyimpulkeun. Aya loba hal aneh. Kalobaannana, tangtosna, teu jadi kritis sakumaha ngobrol ngeunaan kabiasaan blatantly pantes. Sareng anu sanésna dijelaskeun ku betah dianggo atanapi frékuénsi aplikasina dina kaayaan anu tangtu. Tapi dina waktos anu sami, aya seueur kejutan. Ku alatan éta, anjeun kudu nyaho ngeunaan aranjeunna. Lamun manggihan nanaon sejenna aneh atawa mahiwal dina kabiasaan jenis naon, nulis dina komentar, Kuring bakal senang pikeun nambahkeun kana dossier sadia on aranjeunna.

sumber: www.habr.com

Tambahkeun komentar