Намудҳои шубҳанок

Дар намуди зоҳирии онҳо ҳеҷ чизи шубҳанок нест. Гузашта аз ин, онҳо ҳатто барои шумо хуб ва барои муддати тӯлонӣ шинос ба назар мерасанд. Аммо ин танҳо то он даме, ки шумо онҳоро тафтиш кунед. Дар ин ҷо онҳо табиати маккоронаи худро нишон медиҳанд, ки назар ба он ки шумо интизор будед, тамоман дигар кор мекунанд. Ва баъзан онҳо коре мекунанд, ки мӯйҳои шуморо ба по мегузоранд - масалан, онҳо маълумоти махфии ба онҳо бовар кардашударо гум мекунанд. Вакте ки бо онхо ру ба ру мешавед, онхо даъво мекунанд, ки якдигарро намешиносанд, гарчанде дар соя дар зери як кулоҳ боғайратона кор мекунанд. Вақти он расидааст, ки онҳоро ба оби тоза расонем. Биёед бо ин навъҳои шубҳанок низ мубориза барем.

Навиштани маълумот дар PostgreSQL, бо тамоми мантиқи он, баъзан сюрпризҳои аҷиберо пешкаш мекунад. Дар ин мақола мо кӯшиш мекунем, ки баъзе аз нохунакҳои онҳоро равшан созем, сабаби рафтори аҷиби онҳоро фаҳмем ва дарк кунем, ки чӣ гуна дар амалияи ҳаррӯза ба мушкилот дучор нашавем. Ростӣ, ман ин мақоларо низ ҳамчун як навъ маълумотнома барои худ, як маълумотномае тартиб додаам, ки дар ҳолатҳои баҳсбарангез ба осонӣ ба он муроҷиат кардан мумкин аст. Аз ин рӯ, он бо пайдо шудани сюрпризҳои нав аз намудҳои шубҳанок пур карда мешавад. Пас, биёед, эй трекерҳои хазинаи пойгоҳи додаҳо!

Файли рақами як. воқеӣ / дақиқ дучандон / ададӣ / пул

Чунин ба назар мерасад, ки навъҳои рақамӣ аз ҷиҳати ногаҳонӣ дар рафтор камтарин мушкилот доранд. Аммо новобаста аз он ки чӣ гуна аст. Пас биёед бо онҳо оғоз кунем. Пас…

Чӣ тавр ҳисоб карданро фаромӯш кард

SELECT 0.1::real = 0.1

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

Чӣ гап? Мушкилот дар он аст, ки PostgreSQL доимии 0.1-ро ба дақиқии дукарата табдил медиҳад ва мекӯшад онро бо 0.1 навъи воқеӣ муқоиса кунад. Ва ин маънои тамоман дигар аст! Идея ин аст, ки рақамҳои воқеӣ дар хотираи мошин. Азбаски 0.1-ро ҳамчун як касри дуӣ нишон додан мумкин нест (он дар бинарӣ 0.0(0011) хоҳад буд), ададҳои умқи битҳои гуногун гуногун хоҳанд буд, аз ин рӯ натиҷа онҳо баробар нестанд. Умуман, ин мавзӯъ барои як мақолаи алоҳида аст, ман дар ин ҷо муфассалтар наменависам;

Хатогӣ аз куҷо меояд?

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

Бисёр одамон медонанд, ки PostgreSQL ба қайди функсионалӣ барои кастинги намуд имкон медиҳад. Яъне, шумо метавонед на танҳо 1::int, балки int(1)-ро низ нависед, ки ба он баробар хоҳад буд. Аммо на барои намудҳое, ки номашон аз чанд калима иборат аст! Аз ин рӯ, агар шумо хоҳед, ки арзиши рақамиро ба навъи дақиқи дукарата дар шакли функсионалӣ гузоред, тахаллуси ин навъи float8-ро истифода баред, яъне SELECT float8(1).

Чӣ бузургтар аз беохир аст?

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

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

Бубинед, ки чӣ гуна аст! Маълум мешавад, ки чизи бузургтар аз беохир вуҷуд дорад ва он NaN аст! Ҳамзамон, ҳуҷҷатҳои PostgreSQL ба мо бо чашмони ростқавл менигаранд ва даъво мекунанд, ки NaN бешубҳа аз ҳама рақамҳои дигар ва аз ин рӯ беохир аст. Баръакс барои -NaN низ дуруст аст. Салом, дустдорони математика! Аммо мо бояд дар хотир дорем, ки ҳамаи ин дар заминаи рақамҳои воқеӣ амал мекунад.

Яклухткунии чашм

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

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

Боз як саломи гайричашмдошт аз база. Боз ҳам, дар хотир доред, ки намудҳои дақиқи дукарата ва рақамӣ таъсири мудавваркунии гуногун доранд. Барои рақамӣ - роҳи муқаррарӣ, вақте ки 0,5 яклухт карда мешавад ва барои дақиқии дукарата - 0,5 ба сӯи адади наздиктарин ҷуфт мудаввар карда мешавад.

Пул чизи махсус аст

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

Мувофиқи PostgreSQL, пул рақами воқеӣ нест. Ба гуфтаи баъзе шахсон низ. Мо бояд дар хотир дошта бошем, ки рехтани навъи пул танҳо ба намуди рақамӣ имконпазир аст, ҳамон тавре ки танҳо навъи рақамиро ба намуди пул интиқол додан мумкин аст. Аммо акнун шумо метавонед бо он бозӣ кунед, ки дилатон мехоҳад. Аммо ин ҳамон пул нахоҳад буд.

Насли Smallint ва пайдарпай

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 вақтро барои чизҳои ночиз беҳуда сарф карданро дӯст намедорад. Ин пайдарпайҳо дар асоси smallint кадомҳоянд? int, на камтар! Аз ин рӯ, ҳангоми кӯшиши иҷро кардани дархости дар боло зикршуда, пойгоҳи додаҳо кӯшиш мекунад, ки smallint-ро ба ягон навъи бутуни дигар гузорад ва мебинад, ки шояд якчанд чунин таркишҳо вуҷуд дошта бошанд. Кадом актёрро интихоб кардан лозим аст? Вай дар ин бора қарор қабул карда наметавонад ва аз ин рӯ бо хатогӣ ба садама дучор мешавад.

Файли рақами дуюм. "char"/char/varchar/text

Дар намудҳои аломатҳо як қатор аҷибҳо низ мавҷуданд. Биёед бо онҳо низ шинос шавем.

Ин чӣ гуна найрангҳост?

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

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

Ин чӣ гуна "чар" аст, ин чӣ гуна масхарабоз аст? Мо ба инҳо ниёз надорем... Зеро он худро як аломати оддӣ вонамуд мекунад, гарчанде ки дар нохунак аст. Ва он аз аломати муқаррарӣ, ки бидуни нохунак аст, бо он фарқ мекунад, ки он танҳо байти аввали намоиши сатрро мебарорад, дар ҳоле ки аломати муқаррарӣ аломати аввалро мебарорад. Дар ҳолати мо, аломати аввал ҳарфи P мебошад, ки дар муаррифии юникод 2 байт мегирад, ки ин бо табдил додани натиҷа ба навъи байт шаҳодат медиҳад. Ва навъи "char" танҳо байти якуми ин муаррифии юникодро мегирад. Пас чаро ин намуд лозим аст? Ҳуҷҷатҳои PostgreSQL мегӯяд, ки ин навъи махсусест, ки барои эҳтиёҷоти махсус истифода мешавад. Аз ин рӯ, мо ба он ниёз надорем. Аммо ба чашмонаш нигар ва бо рафтори хосааш бо у вомехуред, хато намекунед.

Ҷойҳои иловагӣ. Аз назар дур, аз ақл

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

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

Ба мисоли овардашуда назар андозед. Ман махсус ҳамаи натиҷаҳоро ба навъи байт табдил додам, то он чизе ки дар он ҷо буд, равшан намоён бошад. Пас аз интиқол ба varchar(6) фосилаҳои пасипардагӣ куҷоянд? Ҳуҷҷатҳо ба таври мухтасар гуфта мешавад: "Ҳангоми интиқоли арзиши аломат ба намуди дигари аломат, холигии пасипардохт хориҷ карда мешавад." Ин нописандиро бояд дар хотир дошт. Ва дар хотир доред, ки агар доимии сатри иқтибосшуда мустақиман ба навъи varchar(6) дода шавад, фосилаҳои пасипарӣ нигоҳ дошта мешаванд. Чунинанд мӯъҷизаҳо.

Файли рақами се. json/jsonb

JSON сохтори алоҳидаест, ки ҳаёти худро дорад. Аз ин рӯ, субъектҳои он ва PostgreSQL каме фарқ мекунанд. Ана мисолхо.

Ҷонсон ва Ҷонсон. фарқиятро ҳис кунед

SELECT 'null'::jsonb IS NULL

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

Гап дар он аст, ки JSON дорои объекти нули худро дорад, ки аналоги NULL дар PostgreSQL нест. Дар айни замон, худи объекти JSON метавонад арзиши NULL дошта бошад, аз ин рӯ ифодаи SELECT null::jsonb IS NULL (набудани нохунакҳои ягонаро қайд кунед) ин дафъа ҳақиқӣ бармегардад.

Як ҳарф ҳама чизро тағйир медиҳад

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

Гап дар он аст, ки json ва jsonb сохторҳои комилан гуногунанд. Дар json, объект ҳамон тавре ки ҳаст, нигоҳ дошта мешавад ва дар jsonb он аллакай дар шакли сохтори таҳлилшуда, индексатсияшуда нигоҳ дошта мешавад. Ин аст, ки дар мавриди дуюм, арзиши объект бо калиди 1 аз [1, 2, 3] ба [7, 8, 9] иваз карда шуд, ки дар охири он бо ҳамон калид ба сохтор ворид шудааст.

Аз рӯи худ об нахӯред

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

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

PostgreSQL ҳангоми татбиқи JSONB форматкунии рақамҳои воқеиро тағир дода, онҳоро ба шакли классикӣ меорад. Ин барои намуди JSON рӯй намедиҳад. Каме аҷиб аст, аммо ӯ дуруст аст.

Файли рақами чор. сана / вақт / тамғаи вақт

Ҳамчунин баъзе аҷибҳо бо намудҳои сана/вақт вуҷуд доранд. Биёед ба онҳо назар кунем. Иҷозат диҳед фавран қайд кунам, ки агар шумо моҳияти кор бо минтақаҳои вақтро хуб фаҳмед, баъзе хусусиятҳои рафтор равшан мешаванд. Аммо ин ҳам мавзӯи мақолаи алоҳида аст.

Азони ман намефаҳманд

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

Чунин ба назар мерасад, ки дар ин ҷо чӣ нофаҳмо аст? Аммо база то ҳол намефаҳмад, ки мо дар ин ҷо чиро дар ҷои аввал мегузорем - сол ё рӯз? Ва ӯ қарор мекунад, ки ин 99 январи соли 2008 аст, ки ақлашро ба воя мерасонад. Умуман, ҳангоми интиқоли санаҳо дар формати матн, шумо бояд хеле бодиққат тафтиш кунед, ки пойгоҳи додаҳо онҳоро то чӣ андоза дуруст эътироф кардааст (хусусан, параметри услуби санаро бо фармони SHOW datestyle таҳлил кунед), зеро номуайянӣ дар ин масъала метавонад хеле гарон бошад.

Шумо инро аз куҷо гирифтед?

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

Чаро базаи маълумотҳо вақти аниқи муайянро дарк карда наметавонад? Зеро минтақаи вақт дорои ихтисорот нест, балки номи пурра дорад, ки танҳо дар заминаи сана маъно дорад, зеро он таърихи тағирёбии минтақаи вақтро ба назар мегирад ва бидуни сана кор намекунад. Ва худи ибораи хатти вақт саволҳоро ба миён меорад - барномасоз воқеан чиро дар назар дошт? Аз ин рӯ, дар ин ҷо ҳама чиз мантиқ аст, агар шумо ба он нигоҳ кунед.

Ба ӯ чӣ шудааст?

Вазъиятро тасаввур кунед. Шумо дар ҷадвали худ майдон бо навъи timestampz доред. Шумо мехоҳед онро индексатсия кунед. Аммо шумо мефаҳмед, ки сохтани индекс дар ин соҳа на ҳамеша аз сабаби интихоби баланди он асоснок карда мешавад (қариб ҳама арзишҳои ин навъи беназир хоҳанд буд). Ҳамин тавр, шумо қарор медиҳед, ки интихоби индексро бо гузоштани навъи ба сана кам кунед. Ва шумо сюрприз мегиред:

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

Чӣ гап? Гап дар он аст, ки барои интиқол додани навъи timestampz ба навъи сана, арзиши параметри системаи TimeZone истифода мешавад, ки функсияи табдилдиҳии навъиро аз параметри фармоишӣ вобаста мекунад, яъне. ноустувор. Чунин функсияҳо дар индекс иҷозат дода намешаванд. Дар ин ҳолат, шумо бояд ба таври возеҳ нишон диҳед, ки навъи cast дар кадом минтақаи вақт иҷро мешавад.

Вақте ки ҳоло ҳоло ҳам нест

Мо одат кардаем, ки ҳоло() бо назардошти минтақаи вақт сана/вақти ҷорӣро баргардонем. Аммо ба саволҳои зерин нигаред:

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;

Санаи/вақт новобаста аз он ки аз дархости қаблӣ чӣ қадар вақт гузашт, ҳамон баргардонида мешавад! Чӣ гап? Далели он аст, ки ҳоло() вақти ҷорӣ нест, балки вақти оғози амалиёти ҷорӣ аст. Аз ин рӯ, он дар дохили транзаксия тағир намеёбад. Ҳар як дархосте, ки берун аз доираи транзаксия оғоз карда мешавад, ба таври ғайримустақим дар транзаксия печонида мешавад, аз ин рӯ мо пай намебарем, ки вақт аз ҷониби SELECT оддии ҳозир (); дар асл, на замони ҷорӣ... Агар шумо хоҳед, ки вақти дақиқи ҷорӣ ба даст оред, шумо бояд функсияи clock_timestamp() -ро истифода баред.

Файли рақами панҷ. каме

Каме аҷиб

SELECT '111'::bit(4)

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

Ҳангоми тамдиди навъи битҳо бояд кадом тараф илова карда шаванд? Чунин ба назар мерасад, ки он дар тарафи чап аст. Аммо танҳо пойгоҳ дар ин бора назари дигар дорад. Эҳтиёт бошед: агар шумораи рақамҳо ҳангоми пахши намуд мувофиқат накунанд, шумо он чизеро, ки мехостед, ба даст намеоред. Ин ҳам ба илова кардани битҳо ба рост ва ҳам буридани битҳо дахл дорад. Инчунин дар тарафи рост ...

Рақами файл. Массивҳо

Ҳатто NULL оташ назад

SELECT ARRAY[1, 2] || NULL

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

Чун одамони муқаррарӣ дар SQL тарбия ёфтаанд, мо интизорем, ки натиҷаи ин ифода NULL бошад. Аммо он ҷо набуд. Массив баргардонида мешавад. Чаро? Зеро дар ин ҳолат пойгоҳ NULL-ро ба массиви бутун мегузорад ва ба таври ғайримустақим функсияи array_cat -ро даъват мекунад. Аммо то ҳол маълум нест, ки чаро ин "гурбаи массив" массивро аз нав барқарор намекунад. Ин рафторро низ танҳо дар хотир бояд дошт.

Ҷамъбаст кунед. Бисёр чизҳои аҷиб вуҷуд доранд. Аксарияти онхо, албатта, он кадар танкидй надоранд, ки дар бораи рафтори ошкоро номуносиб сухан ронанд. Ва дигарон бо осонии истифода ё басомади татбиқи онҳо дар ҳолатҳои муайян шарҳ дода мешаванд. Аммо дар баробари ин бисьёр тааччубхо низ хастанд. Аз ин рӯ, шумо бояд дар бораи онҳо донед. Агар шумо дар рафтори ягон намуди дигар чизи аҷиб ё ғайриоддӣ пайдо кунед, дар шарҳҳо нависед, ман бо омодагӣ ба файлҳои дар онҳо мавҷудбуда илова мекунам.

Манбаъ: will.com

Илова Эзоҳ