شکمن ډولونه

د دوی د ظاهري په اړه هیڅ شک نشته. سربیره پردې ، دوی حتی تاسو ته ښه او د اوږدې مودې لپاره پیژندل شوي ښکاري. مګر دا یوازې هغه وخت دی چې تاسو یې وګورئ. دا هغه ځای دی چې دوی خپل بې رحمه طبیعت ښیې، په بشپړ ډول ستاسو د تمې په پرتله په بشپړ ډول کار کوي. او ځینې وختونه دوی داسې څه کوي چې ستاسو ویښتان په پای کې ودروي - د بیلګې په توګه، دوی هغه پټ معلومات له لاسه ورکوي چې دوی ته سپارل شوي. کله چې تاسو ورسره مخامخ شئ، دوی ادعا کوي چې دوی یو بل نه پیژني، که څه هم په سیوري کې دوی د ورته هود لاندې سخت کار کوي. دا وخت دی چې په پای کې دوی پاکو اوبو ته راوړو. راځئ چې د دې مشکوک ډولونو سره هم معامله وکړو.

په 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 په وینا، پیسې ریښتینې شمیرې ندي. د ځینو اشخاصو په وینا، هم. موږ باید په یاد ولرو چې د پیسو ډول کاسټ کول یوازې د عددي ډول لپاره ممکن دي، لکه څنګه چې یوازې د شمیرې ډول د پیسو ډول ته اچول کیدی شي. مګر اوس تاسو کولی شئ له هغې سره لوبې وکړئ لکه څنګه چې ستاسو زړه غواړي. مګر دا به ورته پیسې نه وي.

سمالټ او ترتیب نسل

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 نه خوښوي چې په لنډو ټکو کې وخت ضایع کړي. دا سلسلې د وړوکي پر بنسټ څه دي؟ int، لږ نه! له همدې امله، کله چې د پورتنۍ پوښتنې د پلي کولو هڅه کوي، ډیټابیس هڅه کوي چې کوچني انټیجر ډول ته یو څه بل ډول ته واړوي، او ګوري چې کیدای شي ډیری ډولونه وي. کوم کاسټ غوره کړئ؟ هغه نشي کولی دا پریکړه وکړي، او له همدې امله د یوې تېروتنې سره ټکر کوي.

د دوتنه نمبر. "چار"/char/varchar/text

د کرکټرونو په ډولونو کې یو شمیر ناخوالې هم شتون لري. راځئ چې دوی هم وپیژنو.

دا څه ډول چلونه دي؟

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

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

دا کوم ډول "چار" دی، دا کوم ډول مسخره ده؟ موږ دې ته اړتیا نلرو ... ځکه چې دا د یو عادي چار په توګه ښکارندوی کوي، حتی که دا په نرخونو کې وي. او دا د منظم چار څخه توپیر لري، کوم چې پرته له اقتباساتو څخه دی، په دې کې دا یوازې د سټینګ نمایش لومړی بایټ تولیدوي، پداسې حال کې چې یو نورمال چار لومړی کرکټر تولیدوي. زموږ په قضیه کې ، لومړی کرکټر د P خط دی ، کوم چې د یونیکوډ نمایش کې 2 بایټونه نیسي ، لکه څنګه چې د بایټ ډول ته د پایلې بدلولو سره ثبوت کیږي. او د "چار" ډول د دې یونیکوډ نمایش یوازې لومړی بایټ اخلي. نو بیا ولې دې ډول ته اړتیا ده؟ د 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

ورکړل شوي مثال ته یو نظر وګورئ. ما په ځانګړې توګه ټولې پایلې د بایټ ډول ته بدلې کړې، نو دا په واضح ډول لیدل کیده چې هلته څه وو. ورچر ته د اچولو وروسته د تعقیب ځایونه چیرته دي (6)؟ اسناد په لنډ ډول وايي: "کله چې د کرکټر ارزښت بل ډول ته واړول شي، د تعقیب سپین ځای له مینځه وړل کیږي." دا ناخوښي باید په یاد وساتل شي. او په یاد ولرئ چې که یو نقل شوی تار ثابت په مستقیم ډول د varchar(6) ټایپ ته واچول شي، د تعقیب ځایونه ساتل کیږي. داسې معجزې دي.

دوسیه دریمه. json/jsonb

JSON یو جلا جوړښت دی چې خپل ژوند ژوند کوي. نو ځکه، د هغې ادارې او د PostgreSQL یو څه توپیر لري. دلته مثالونه دي.

جانسن او جانسن. توپیر احساس کړئ

SELECT 'null'::jsonb IS NULL

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

خبره دا ده چې JSON خپل نول وجود لري، کوم چې په PostgreSQL کې د NULL انلاګ نه دی. په ورته وخت کې، د 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

ولې ډیټابیس په واضح ډول ټاکل شوي وخت نه پوهیږي؟ ځکه چې د وخت زون لنډیز نلري، مګر بشپړ نوم، چې یوازې د نیټې په شرایطو کې معنی لري، ځکه چې دا د وخت زون بدلونونو تاریخ په پام کې نیسي، او دا د نیټې پرته کار نه کوي. او د وخت کرښې خورا کلمې پوښتنې راپورته کوي - د برنامه کونکي واقعیا څه معنی درلوده؟ له همدې امله، دلته هرڅه منطقي دي، که تاسو ورته وګورئ.

په هغه کې څه ګناه ده؟

د وضعیت تصور وکړئ. تاسو په خپل میز کې د timestamptz ډول سره ساحه لرئ. تاسو غواړئ دا شاخص کړئ. مګر تاسو پوهیږئ چې پدې ساحه کې د شاخص رامینځته کول تل د دې لوړ انتخاب له امله توجیه نه کیږي (د دې ډول نږدې ټول ارزښتونه به ځانګړي وي). نو تاسو پریکړه وکړئ چې نیټې ته د ډول په اچولو سره د شاخص انتخاب کم کړئ. او تاسو حیرانتیا ترلاسه کوئ:

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

ستونزه څه ده؟ حقیقت دا دی چې د نیټې ډول ته د timestamptz ډول کاسټ کولو لپاره ، د TimeZone سیسټم پیرامیټر ارزښت کارول کیږي ، کوم چې د ډول تبادلې فعالیت په دودیز پیرامیټر پورې اړه لري ، د بیلګې په توګه. بې ثباته دا ډول دندې په شاخص کې اجازه نلري. په دې حالت کې، تاسو باید په واضح ډول په ګوته کړئ چې په کوم وخت زون کې د ډول ډول کاسټ ترسره کیږي.

کله چې اوس اوس هم نه دی

موږ عادت شوي یو چې اوس() د وخت زون په پام کې نیولو سره اوسنۍ نیټه/وخت بیرته راګرځوو. مګر لاندې پوښتنو ته وګورئ:

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 فنکشن بولي. مګر دا لاهم روښانه نده چې ولې دا "سري پیشو" سري نه تنظیموي. دا چلند هم باید په یاد وساتل شي.

لنډیز. ډیر عجیب شیان شتون لري. ډیری یې، البته، دومره مهم ندي چې په ښکاره توګه د نامناسب چلند په اړه خبرې وکړي. او نور یې د کارولو اسانتیا یا په ځینو شرایطو کې د دوی د پلي کیدو فریکونسۍ لخوا تشریح شوي. مګر په ورته وخت کې ډیری حیرانتیاوې شتون لري. له همدې امله، تاسو باید د هغوی په اړه پوه شي. که تاسو د هر ډول چلند کې کوم بل څه عجیب یا غیر معمولي ومومئ ، په نظرونو کې ولیکئ ، زه به خوښ شم چې په دوی کې موجود دوسیرونو کې اضافه کړم.

سرچینه: www.habr.com

Add a comment