አጠራጣሪ ዓይነቶች

ስለ መልካቸው ምንም አጠራጣሪ ነገር የለም. ከዚህም በላይ እነሱ በደንብ እና ለረጅም ጊዜ እርስዎን የሚያውቁ ይመስላሉ. ግን ያ እስኪያረጋግጡ ድረስ ብቻ ነው። እርስዎ ከጠበቁት በተለየ መልኩ የሚሰሩትን መሰሪ ባህሪያቸውን የሚያሳዩበት ይህ ነው። እና አንዳንድ ጊዜ ፀጉርዎ እንዲቆም የሚያደርግ አንድ ነገር ያደርጋሉ - ለምሳሌ በአደራ የተሰጣቸውን ሚስጥራዊ መረጃ ያጣሉ። ሲጋፈጡዋቸው አይተዋወቁም ይሉሃል ምንም እንኳን በጥላ ስር ሆነው ጠንክረን እየሰሩ ነው። በመጨረሻ እነሱን ወደ ንጹህ ውሃ ለማምጣት ጊዜው አሁን ነው. እነዚህን አጠራጣሪ ዓይነቶችም እንይ.

በ 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

ምን እንደሚመስል ተመልከት! ከማይታወቅ ነገር የሚበልጥ ነገር እንዳለ ታወቀ፣ እና እሱ ናኤን ነው! በተመሳሳይ ጊዜ፣ የPostgreSQL ሰነድ እኛን በታማኝነት አይን ይመለከተናል እና ናኤን ከሌሎች ቁጥሮች እንደሚበልጥ በግልጽ ይናገራል፣ እና ስለዚህ፣ ማለቂያ የሌለው። ለ-ናኤንም ተቃራኒው እውነት ነው። ሰላም፣ የሂሳብ ወዳጆች! ነገር ግን ይህ ሁሉ በእውነተኛ ቁጥሮች አውድ ውስጥ እንደሚሰራ ማስታወስ አለብን.

የዓይን ማዞር

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, ምንም ያነሰ! ስለዚህ ከላይ ያለውን መጠይቅ ለማስፈጸም ሲሞክር ዳታቤዙ ትንሿን ወደ ሌላ ኢንቲጀር አይነት ለመወርወር ይሞክራል እና ብዙ እንደዚህ አይነት ቀረጻዎች ሊኖሩ እንደሚችሉ ይመለከታል። የትኛውን ቀረጻ ለመምረጥ? እሷ ይህንን መወሰን አትችልም, እና ስለዚህ በስህተት ይወድቃል.

ፋይል ቁጥር ሁለት. "ቻር"/ቻር/ቫርቻር/ጽሁፍ

በገጸ-ባሕሪያት ዓይነቶች ውስጥ በርካታ ያልተለመዱ ነገሮችም አሉ። እነሱንም እናውቃቸው።

እነዚህ ምን ዓይነት ዘዴዎች ናቸው?

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 እንደሆነ ወሰነች ይህም ሀሳቧን ይመታል። በአጠቃላይ ቀኖችን በጽሑፍ ቅርጸት ሲያስተላልፉ የመረጃ ቋቱ ምን ያህል በትክክል እንዳወቃቸው በጥንቃቄ መመርመር ያስፈልግዎታል (በተለይም በዚህ ጉዳይ ላይ ያሉ አሻሚዎች በጣም ውድ ሊሆኑ ስለሚችሉ የ datestyle መለኪያን በ 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

ምንድነው ችግሩ? እውነታው ግን የጊዜ ማህተም አይነትን ወደ የቀን አይነት ለመጣል የ 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 አሁን እንደተመለሰ የማናስተውለው። በእውነቱ፣ የአሁኑን ሳይሆን... ታማኝ የአሁኑ ጊዜ ማግኘት ከፈለጉ፣ የሰአት_ጊዜ ማህተም() ተግባርን መጠቀም ያስፈልግዎታል።

ፋይል ቁጥር አምስት. ትንሽ

እንግዳ ትንሽ ትንሽ

SELECT '111'::bit(4)

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

ዓይነት ማራዘሚያ ከሆነ ቢትስ ከየትኛው ወገን መጨመር አለበት? በግራ በኩል ያለ ይመስላል. ነገር ግን መሰረቱ ብቻ በዚህ ጉዳይ ላይ የተለየ አስተያየት አለው. ይጠንቀቁ፡ አይነት ሲወስዱ የአሃዞች ቁጥር የማይዛመድ ከሆነ የሚፈልጉትን አያገኙም። ይህ በሁለቱም ወደ ቀኝ ቢት ማከል እና ቢት መቁረጥን ይመለከታል። በቀኝ በኩል ደግሞ...

ፋይል ቁጥር ስድስት. ድርድሮች

NULL እንኳን አልተኮሰም።

SELECT ARRAY[1, 2] || NULL

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

በSQL ላይ እንደተነሱ መደበኛ ሰዎች፣ የዚህ አገላለጽ ውጤት ባዶ ይሆናል ብለን እንጠብቃለን። ግን እዚያ አልነበረም። ድርድር ተመልሷል። ለምን? ምክንያቱም በዚህ አጋጣሚ መሰረቱ NULL ወደ ኢንቲጀር ድርድር ይጥላል እና የarray_cat ተግባርን በተዘዋዋሪ ይጠራል። ነገር ግን ይህ "ድመት" ድመትን እንደገና የማያስጀምርበት ምክንያት አሁንም ግልጽ አይደለም. ይህ ባህሪ እንዲሁ መታወስ አለበት።

ማጠቃለል። ብዙ እንግዳ ነገሮች አሉ። አብዛኞቻቸው፣ በእርግጥ፣ ስለ ተገቢ ያልሆነ ባህሪ ለመናገር ያህል ወሳኝ አይደሉም። እና ሌሎች በአጠቃቀም ቀላልነት ወይም በተወሰኑ ሁኔታዎች ላይ ተፈፃሚነታቸው ድግግሞሽ ተብራርቷል። ግን በተመሳሳይ ጊዜ, ብዙ አስገራሚ ነገሮች አሉ. ስለዚህ, ስለእነሱ ማወቅ አለብዎት. በማንኛውም አይነት ባህሪ ውስጥ ሌላ እንግዳ ወይም ያልተለመደ ነገር ካገኙ በአስተያየቶቹ ውስጥ ይፃፉ, በእነሱ ላይ የሚገኙትን ዶሴዎች ለመጨመር ደስተኛ ነኝ.

ምንጭ: hab.com

አስተያየት ያክሉ