IlmHamroh
JavaScript Full-stack/26-qism. SQL va PostgreSQL11/64-dars18 daqiqa
Mundarija (38)

PostgreSQL ma'lumot turlari: son, pul, matn, vaqt, UUID va JSON

Qisqacha: Har ustunning turi bor va u keyin o'zgartirish qiyin bo'lgan qaror. Asosiy qoidalar: identifikator — bigint; pul — numeric (hech qachon real/double precision emas: 0.1 + 0.2 u yerda 0.30000000000000004); matn — text (uzunlik chegarasi kerak bo'lsa CHECK bilan); vaqt nuqtasi — timestamptz (zonasiz timestamp emas); faqat sana — date; davomiylik — interval; ha/yo'q — boolean. Telefon raqami va pochta indeksi — son emas, text.

Bu darsda

  • Butun sonlar (smallint, integer, bigint) chegaralarini va qachon qaysi birini olishni bilasiz.
  • Pul uchun nega numeric kerakligini 0.1 + 0.2 misolida isbotlaysiz.
  • text, varchar(n) farqini va varchar ga cast qilishdagi jim kesish tuzog'ini tushuntirasiz.
  • timestamptz, timestamp, date va interval ni to'g'ri tanlaysiz.
  • uuid, jsonb, massiv, bytea va inet qayerda kerakligini va har tur qancha joy olishini aytasiz.

Oldin bilishingiz kerak: SQL tili va buyruq turlari, Number turi JS'da: EPSILON, MAX_SAFE_INTEGER, NaN va -0, Date va vaqt zonalari.

1. Nega bu kerak?

JavaScript'da son — number, matn — string, tamom. Bazada esa tanlov ko'p: son uchun beshta, matn uchun uchta, vaqt uchun to'rtta tur. Nega bunchalik?

Chunki noto'g'ri tur yillab yashaydigan xato beradi. Bir necha haqiqiy vaziyat:

  • Narx double precision (kasrli son) ustunida. Har kunlik hisobot bir necha tiyinga "adashadi" — buxgalter topolmaydi, chunki xato yaxlitlashda.
  • Telefon raqami son ustunida. 090… ning boshidagi nol yo'qoladi, +998 ni esa umuman yozib bo'lmaydi.
  • Vaqt zonasiz saqlangan. Server Toshkentdan Frankfurtga ko'chirilgandan keyin hamma buyurtmalar 3–4 soat "siljiydi".

Bu xatolarni jadval to'lgandan keyin tuzatish og'ir: millionlab qatorni qayta yozish, ilovani to'xtatish kerak bo'lishi mumkin. Tur tanlash — uy qurishdan oldin poydevor tanlash kabi: keyin almashtirish deyarli imkonsiz.

Bu darsdagi SQL chiqishlari — kanon PostgreSQL 18.6 bazasida olingan. Ba'zi qo'shimcha misollarni o'z nusxamizda 17.6-bob ishga tushirdik — yonida aytilgan.

2. Butun sonlar

2.1 Uch o'lcham

Tur Bayt Chegara (taxminan) Qachon
smallint 2 ±32 767 kamdan-kam (yosh, reyting)
integer (int) 4 ±2,1 milliard soni, miqdori
bigint 8 ±9,2 × 10¹⁸ identifikatorlar, katta hisoblagichlar

Chegaradan oshsa — Postgres jim "aylanib ketmaydi", xato beradi:

sql
SELECT 2147483647::int + 1;
text
ERROR:  integer out of range

Tarjimasi: "butun son chegaradan tashqarida". ::int — tur o'zgartirish (cast): "bu qiymatni int deb hisobla". bigint da esa bemalol:

sql
SELECT 2147483647::bigint + 1 AS bigint_yetadi;
text
 bigint_yetadi
---------------
    2147483648
(1 row)

2.2 Nega ID uchun bigint

2,1 milliard ko'p tuyuladi. Lekin ID'lar hech qachon qayta ishlatilmaydi: o'chirilgan qatorning raqami "kuyadi", bekor qilingan tranzaksiya ham raqam yeydi (Primary key tanlovi darsida ko'ramiz). Log, hodisa, xabar jadvallari yiliga yuz millionlab qator yig'adi. int ID tugab qolishi — real kompaniyalarda bo'lgan avariya: yangi qator yozib bo'lmay qoladi.

bigint atigi 4 bayt ko'proq oladi. Kanon qarori: hamma ID — bigint.

Maslahat: JavaScript'ning number turi butun sonni faqat 2⁵³ gacha aniq saqlaydi, bigint esa 2⁶³ gacha boradi. Shuning uchun Node.js'dagi pg kutubxonasi bigint ni satr qilib qaytaradi. Buni node-postgres (pg) asoslari darsida hal qilamiz.

3. Kasrli sonlar va pul

3.1 0.1 + 0.2 muammosi

Number turi JS'da: EPSILON, MAX_SAFE_INTEGER, NaN va -0 darsida JS'da 0.1 + 0.2 === 0.3 → false ekanini ko'rgansiz. Postgres'ning real (4 bayt) va double precision (float8, 8 bayt) turlari JS'dagi number bilan bir xil standartda (IEEE 754) — xato ham bir xil. numeric esa sonni o'nlik raqamlar sifatida aniq saqlaydi:

sql
SELECT 0.1::float8 + 0.2::float8 = 0.3::float8 AS float_teng,
       0.1::numeric + 0.2::numeric = 0.3 AS numeric_teng,
       (0.1::float8 + 0.2::float8)::text AS float_aslida;
text
 float_teng | numeric_teng |    float_aslida
------------+--------------+---------------------
 f          | t            | 0.30000000000000004
(1 row)

float8 da 0.1 + 0.2 0.3 ga teng emas. Bu bitta qo'shishda. Ko'p qo'shishda xato to'planadi — o'nta 0.1 ni qo'shamiz. generate_series(1, 10) — 1 dan 10 gacha 10 ta qator yasaydigan funksiya, sum — ularni qo'shadi. Bu so'rovni biz ishga tushirdik (PG 17.6; kanon 18.6 da ham aynan shu raqamlar):

sql
SELECT sum(0.1::float8) AS float_yigindi,
       sum(0.1::numeric) AS numeric_yigindi
FROM generate_series(1, 10);
text
   float_yigindi    | numeric_yigindi
--------------------+-----------------
 0.9999999999999999 |             1.0
(1 row)

Do'konning kunlik hisobotida minglab qator qo'shiladi. Kanon Pul, miqdor va enum'larni modellash darsi uchun 1 mln marta 0.1 ni qo'shdi: float8 — 100000.00000133288, numeric — aniq 100000.0000.

3.2 numeric(p, s)

numeric(10,2) — jami 10 ta raqam, shundan 2 tasi verguldan keyin. Ortiqcha kasr yaxlitlanadi:

sql
SELECT 12345.678::numeric(10,2) AS yaxlitlandi;
text
 yaxlitlandi
-------------
    12345.68
(1 row)

Butun qism sig'masa — xato:

sql
SELECT 123456789.12::numeric(10,2) AS sigmaydi;
text
ERROR:  numeric field overflow
DETAIL:  A field with precision 10, scale 2 must round to an absolute value less than 10^8.

Tarjimasi: "numeric maydoni to'lib ketdi. Aniqligi 10, kasr qismi 2 bo'lgan maydon 10⁸ dan kichik bo'lishi kerak". 10 raqamdan 2 tasi kasrga ketgan, butun qismga 8 ta qoladi.

Pul uchun ikki to'g'ri yo'l bor: numeric(12,2) (so'm va tiyin) yoki bigint da eng kichik birlikda (tiyinlarda) saqlash. Ikkalasini Pul, miqdor va enum'larni modellash darsida solishtiramiz. Noto'g'ri yo'l bitta — real/double precision.

float qachon to'g'ri? Taxminiy o'lchovlar: harorat, koordinata, ilmiy hisob. U yerda oxirgi raqamdagi farq ahamiyatsiz, tezlik esa muhim.

Tekshirib ko'ring: Mahsulot og'irligi (kg, 3 xonali aniqlik), valyuta kursi (11 903.15) va GPS koordinata — har biriga qaysi tur?

Javob

Og'irlik — numeric(10,3): aniq qiymat, hisob-kitobga kiradi (narx × og'irlik). Valyuta kursi — numeric (masalan numeric(12,4)): pul hisobida qatnashadi. GPS koordinata — double precision yoki maxsus geo tur (PostGIS): taxminiy o'lchov, millimetrlik farq muhim emas.

4. Matn

4.1 text, varchar(n), char(n)

Tur Ma'nosi Tavsiya
text istalgan uzunlik asosiy tanlov
varchar(n) ko'pi bilan n belgi chegarani CHECK bilan qilish afzal
char(n) aynan n belgi, bo'sh joy bilan to'ldiriladi ishlatmang

Postgres'da text va varchar(n) bir xil saqlanadi, tezligi ham bir xil. varchar(255) — boshqa bazalardan qolgan odat; Postgres'da 255 ning maxsus ma'nosi yo'q. Uzunlikni cheklash kerak bo'lsa, ikkala usul ishlaydi:

sql
CREATE TEMP TABLE t11 (
  v varchar(5),
  t text CHECK (char_length(t) <= 5)
);
INSERT INTO t11 VALUES ('Assalomu', 'ok');
INSERT INTO t11 VALUES ('ok', 'Assalomu');
text
CREATE TABLE
ERROR:  value too long for type character varying(5)
ERROR:  new row for relation "t11" violates check constraint "t11_t_check"
DETAIL:  Failing row contains (ok, Assalomu).

Ikkalasi ham uzun matnni rad etdi. CHECK ning afzalligi: chegarani keyin o'zgartirish faqat cheklovni almashtirish, ustun turiga tegilmaydi. Cheklovlarni CREATE TABLE va cheklovlar darsida batafsil ko'ramiz.

4.2 varchar ga cast — jim kesish

Mana kutilmagan tuzoq. INSERT xato berdi, lekin cast boshqacha ishlaydi:

sql
SELECT 'Assalomu alaykum'::varchar(5);
text
 varchar
---------
 Assal
(1 row)

Xato yo'q — matn jimgina 5 belgiga kesildi. Bu SQL standartida yozilgan qoida: ochiq cast (::varchar(5)) ortiqchani kesadi, ustunga yozish esa xato beradi. Kodda "tekshirish" uchun cast ishlatsangiz, ma'lumot ogohlantirishsiz yo'qoladi.

4.3 Belgi va bayt

Matn diskda UTF-8 kodlashda saqlanadi. Lotin harfi — 1 bayt, lekin ba'zi belgilar ko'proq oladi. O'zbekcha ʻ (to'g'ri o'zbek apostrofi, U+02BB) — 2 bayt:

sql
SELECT length('Oʻzbekiston') AS belgi,
       octet_length('Oʻzbekiston') AS bayt,
       length('O''zbekiston') AS apostrof_bilan;
text
 belgi | bayt | apostrof_bilan
-------+------+----------------
    11 |   12 |             11
(1 row)

length (yoki char_length) belgilarni sanaydi — 11. octet_length baytlarni — 12. "Ko'pi bilan 100 belgi" qoidasi doim char_length bilan yoziladi. JS'dagi .length boshqacha sanaydi (UTF-16 birliklari): emoji JS'da 2, Postgres'da 1 belgi. Kanon bu farqni vazifalar sxemasida qayd etgan.

5. boolean

boolean — true, false yoki NULL. Postgres kiritishda bir nechta yozuvni tushunadi:

sql
SELECT 'yes'::boolean, 'f'::boolean, 1::boolean;
text
 bool | bool | bool
------+------+------
 t    | f    | t
(1 row)

psql uni t/f deb ko'rsatadi. Holatni "ha"/"yo'q" matni yoki 0/1 son bilan saqlamang — boolean 1 bayt va ma'nosi aniq.

6. Vaqt turlari

6.1 To'rtta tur

Tur Nima saqlaydi Misol
timestamptz vaqt nuqtasi (zona bilan) buyurtma yaratilgan payt
timestamp "devordagi soat", zonasiz kamdan-kam kerak
date faqat sana tug'ilgan kun, yetkazish kuni
interval davomiylik "30 daqiqa", "1 oy"

6.2 timestamptz va timestamp farqi

Nomi chalg'itadi: timestamptz (timestamp with time zone) zonani saqlamaydi. U kiritilgan vaqtni UTC'ga aylantirib saqlaydi va chiqarishda sessiya zonasiga o'giradi. timestamp (without time zone) esa yozilgan raqamlarni hech qanday zonasiz, shundayligicha saqlaydi.

Kanon ikkalasini Toshkent va UTC zonalarida solishtirdi. Toshkent zonasida:

sql
SET TIME ZONE 'Asia/Tashkent';
SELECT '2026-10-24 09:00'::timestamptz AS tz,
       '2026-10-24 09:00'::timestamp AS zonasiz;
text
SET
           tz           |       zonasiz
------------------------+---------------------
 2026-10-24 09:00:00+05 | 2026-10-24 09:00:00
(1 row)

UTC zonasida, Toshkentdagi soat 9 ni berib:

sql
SET TIME ZONE 'UTC';
SELECT '2026-10-24 09:00+05'::timestamptz AS tz_utc_da,
       '2026-10-24 09:00'::timestamp AS zonasiz_ozgarmadi;
text
SET
       tz_utc_da        |  zonasiz_ozgarmadi
------------------------+---------------------
 2026-10-24 04:00:00+00 | 2026-10-24 09:00:00
(1 row)

timestamptz bir xil lahzani ko'rsatdi: Toshkentda 09:00 = UTC'da 04:00. timestamp esa shunchaki "09:00" — qaysi shahar soatiga tegishli ekanini bilmaydi. Ilova, server va foydalanuvchi turli zonalarda bo'lishi mumkin — shuning uchun voqea vaqti doim timestamptz. Zonalarni chuqur SQL'da sana va vaqt zonalari darsida o'rganamiz.

6.3 date va interval

sql
SELECT '2026-10-24'::date + 7 AS bir_haftadan_keyin,
       '2026-11-01'::date - '2026-10-24'::date AS kun_farqi,
       interval '1 day 2 hours' * 3 AS uch_marta,
       '2026-01-31'::date + interval '1 month' AS oy_qoshish;
text
 bir_haftadan_keyin | kun_farqi |    uch_marta    |     oy_qoshish
--------------------+-----------+-----------------+---------------------
 2026-10-31         |         8 | 3 days 06:00:00 | 2026-02-28 00:00:00
(1 row)

To'rt narsaga qarang:

  • date + 7 — 7 kun qo'shildi.
  • Ikki sana ayirmasi — kunlar soni (butun son).
  • interval ni songa ko'paytirish mumkin.
  • 31-yanvarga 1 oy qo'shsak — 28-fevral. 31-fevral yo'q, Postgres oyning oxirgi kunini oldi. Obuna va to'lov muddatlarida bu muhim tafsilot.

Noto'g'ri sanani Postgres qabul qilmaydi (biz o'z nusxamizda sinadik, PostgreSQL 17.6):

sql
SELECT '2026-02-30'::date;
text
ERROR:  date/time field value out of range: "2026-02-30"
LINE 1: SELECT '2026-02-30'::date;
               ^

Sanani matn qilib saqlasangiz, bunday himoya yo'q. Ustiga, matnlar harf bo'yicha solishtiriladi:

sql
SELECT '24.10.2026' < '3.01.2026' AS matn_solishtirish;
text
 matn_solishtirish
-------------------
 t
(1 row)

Nima bo'ldi? Natija — rost (t): birinchi belgilar solishtirildi, '2' belgisi '3' dan kichik. Garchi oktabr yanvardan keyin bo'lsa ham.

Tekshirib ko'ring: Foydalanuvchining tug'ilgan kuni, xabar yuborilgan payt va obuna davomiyligi — qaysi turlar?

Javob

Tug'ilgan kun — date: soat ham, zona ham kerak emas (Toshkentda ham, Nyu-Yorkda ham 15-mart). Xabar yuborilgan payt — timestamptz: aniq lahza, turli zonadagi odamlar o'z vaqtida ko'rishi kerak. Obuna davomiyligi — interval ('1 month', '1 year').

7. Maxsus turlar

7.1 uuid

UUID — 128 bitli noyob identifikator, xxxxxxxx-xxxx-… ko'rinishida. gen_random_uuid() tasodifiy (v4) UUID beradi. PostgreSQL 18 da yangi uuidv7() funksiyasi qo'shildi — uning boshida vaqt bor, shuning uchun ketma-ket yaratilganlari tartib bilan o'sadi:

Natija har safar boshqa qiymat bo'ladi, shuning uchun bu yerda kanon chiqishini ko'rsatamiz:

sql
SELECT gen_random_uuid() AS v4, uuidv7() AS v7;

Kanon chiqishi:

text
                  v4                  |                  v7
--------------------------------------+--------------------------------------
 01180400-e9ec-4e53-8946-06a93bd541b9 | 01a16c44-c2e7-7239-baa3-0de75f6c44de
(1 row)

v7 dagi uchinchi guruh 7 bilan boshlanadi — versiya raqami. uuidv7() PostgreSQL 17 da yo'q: biz o'z nusxamizda sinaganda function uuidv7() does not exist xatosini oldik. UUID qachon ID bo'lishi kerakligini va v4/v7 tezlik farqini Primary key tanlovi darsida o'lchaymiz.

7.2 jsonb va json

Ikkala tur JSON saqlaydi, lekin farqi bor:

sql
SELECT '{"b": 1, "a": [1, 2]}'::jsonb AS jsonb_tartib,
       '{"b": 1, "a": [1, 2]}'::json AS json_matn;
text
     jsonb_tartib      |       json_matn
-----------------------+-----------------------
 {"a": [1, 2], "b": 1} | {"b": 1, "a": [1, 2]}
(1 row)

json matnni aynan saqlaydi (bo'shliqlar, kalitlar tartibi bilan). jsonb uni ikkilik ko'rinishga o'giradi: kalitlar tartiblanadi, takror kalit olib tashlanadi, lekin ichidan qidirish va indeks qurish mumkin. Deyarli har doim — jsonb. Uni JSONB darsida chuqur o'rganamiz. Diqqat: JSON ustuni — relatsion jadvallar o'rnini bosuvchi emas (DB turlari xaritasi va SQL vs NoSQL darsidagi hujjat modeli kamchiliklari shu yerda ham bor).

7.3 Massiv, bytea, inet

sql
SELECT ARRAY['#uy', '#bozor'] AS teglar,
       (ARRAY['#uy', '#bozor'])[1] AS birinchi,
       '#uy' = ANY(ARRAY['#uy', '#bozor']) AS bormi;
text
    teglar    | birinchi | bormi
--------------+----------+-------
 {#uy,#bozor} | #uy      | t
(1 row)
  • Massiv — har tur uchun (text[], int[]). Diqqat: Postgres massivlari 1 dan boshlanadi, JS'dagidek 0 dan emas. Massiv ichida bog'lanish (teglar → boshqa jadval) qo'yib bo'lmaydi — shuning uchun kanon teglarni alohida jadvalda saqlaydi.
  • bytea — ikkilik ma'lumot ('salom'::bytea → \x73616c6f6d). Kichik fayl yoki hash uchun. Katta fayllar (rasm, video) bazada emas, fayl omborida saqlanadi.
  • inet / cidr — IP manzil va tarmoq. Kanon misolida '192.168.1.15'::inet << '192.168.1.0/24'::cidr → t ("bu IP shu tarmoq ichida"). IP'larni matn emas, inet da saqlash tekshiruv va tarmoq amallarini beradi.

8. Qaysi tur qancha joy oladi

Kanon pg_column_size funksiyasi bilan har turdagi bitta qiymat o'lchamini o'lchadi:

Bitta qiymat diskda necha bayt
  • boolean1 bayt
  • smallint2 bayt
  • integer4 bayt
  • bigint8 bayt
  • timestamptz8 bayt
  • text 'salom'5 bayt + 4 bayt sarlavha9 bayt
  • uuid16 bayt

Manba: IlmHamroh kanon o'lchovi, 2026-10-24: PostgreSQL 18.6, pg_column_size; numeric 1.5 — 10 bayt

Nimaga qarang: bigint va timestamptz — 8 bayt, uuid — 16 bayt, ya'ni bigint dan ikki baravar. Bitta qatorda farq kichik. 2 mln qatorli jadvalda va uning indekslarida esa megabaytlarga aylanadi. Matn qisqa bo'lsa ham kichik "sarlavha" qo'shiladi ('salom' — 5 harf, 9 bayt). Telefon raqami '+998 90 000 00 00' matn sifatida — 21 bayt, son sifatida esa 8 bayt bo'lardi (biz o'z nusxamizda o'lchadik). Lekin pastdagi «Telefon — son emas» xatosiga qarang: to'g'rilik joydan muhimroq.

flowchart TD
  Q{Ustunda nima?} --> N[Butun son] --> NB[ID: bigint<br/>soni: integer]
  Q --> P[Pul] --> PN[numeric yoki<br/>bigint tiyinda]
  Q --> T[Matn] --> TT[text + CHECK]
  Q --> V[Vaqt] --> VT[lahza: timestamptz<br/>kun: date]
  Q --> B[Ha/yo'q] --> BB[boolean]

Nimaga qarang: har savolga bitta asosiy javob. Istisnolar bor, lekin ular sababli bo'lishi kerak.

9. SQL qadami: vazifalar ustunlari turlari

CREATE TABLE va cheklovlar darsida yaratiladigan ikki jadval uchun kanon turlarni shunday tanlagan:

Ustun Tur Nega
id bigint ID tugab qolmasin
email, ism text uzunlik CHECK bilan
matn text CHECK — 1–100 belgi (frontend qoidasi)
bajarildi boolean ha/yo'q
yaratilgan_vaqt timestamptz aniq lahza, zona bilan

matn uchun varchar(100) emas, text + CHECK (char_length(matn) BETWEEN 1 AND 100): chegara 22-qismdagi frontend'ning Vazifa.MAKS_UZUNLIK = 100 qoidasi bilan bir xil va keyin o'zgarsa, faqat cheklov almashtiriladi. Bu darsda fayl yozilmaydi va commit yo'q.

10. Ko'p uchraydigan xatolar

10.1 Pul uchun float

real/double precision da pul — yaxlitlash xatolari to'planadi (0.9999999999999999). Pul — numeric yoki bigint (tiyinda).

10.2 Telefon — son emas

Biz telefon raqamini songa aylantirib ko'rdik (PostgreSQL 17.6):

sql
SELECT '0900000000'::bigint AS telefon;
text
  telefon
-----------
 900000000
(1 row)

Boshidagi nol yo'qoldi. +998 va bo'shliqlarni esa son umuman saqlamaydi. Qoida: arifmetika qilinmaydigan "raqam" — telefon, pochta indeksi, pasport seriyasi, karta raqami — text.

10.3 timestamp (zonasiz) bilan voqea vaqti

Server zonasi o'zgarsa yoki foydalanuvchilar turli zonada bo'lsa, zonasiz vaqt noto'g'ri talqin qilinadi. Voqea vaqti — timestamptz.

10.4 Sana — matn

'24.10.2026' matni noto'g'ri tartiblanadi (yuqorida t), '30.02.2026' ni ham qabul qiladi. Sana — date.

10.5 varchar(n) ga cast bilan "tekshirish"

::varchar(5) xato bermaydi, jimgina kesadi. Chegara — CHECK yoki ustun turida, cast'da emas.

10.6 integer chegarasi

integer out of range — ko'pincha ID yoki hisoblagichda. bigint dan boshlang; keyin int → bigint o'zgartirish katta jadvalda uni qayta yozadi (kanon 1 mln qatorda 512 ms o'lchagan — ALTER TABLE va sxemani o'zgartirish darsida).

11. Mashqlar

Mashqlar kurs/mashqlar/26/11-turlar/ da.

1-mashq (oson): tur tanlang

  1. Mahsulot narxi so'mda tiyini bilan — .
  2. Buyurtma yaratilgan aniq lahza — .
  3. Foydalanuvchi ID'si — .
  4. "Yetkazildimi?" — .
  5. Tug'ilgan kun — .
  6. Telefon raqami — .
Yechim

numeric (yoki numeric(12,2); muqobil — bigint tiyinda), timestamptz, bigint, boolean, date, text. Telefon — text, chunki u bilan arifmetika qilinmaydi va boshidagi +, 0 saqlanishi kerak.

2-mashq (o'rta): natijani oldindan ayting

Har so'rov nima qaytaradi yoki qanday xato beradi?

  1. SELECT 0.1::numeric + 0.2::numeric;
  2. SELECT 'Toshkent'::varchar(4);
  3. SELECT '2026-03-31'::date + interval '1 month';
  4. SELECT 40000::smallint;
  5. SELECT (ARRAY[10, 20, 30])[0];
Yechim
  1. 0.3 — numeric aniq.
  2. Tosh — cast jim kesadi.
  3. 2026-04-30 00:00:00 — 31-aprel yo'q, oyning oxirgi kuni olinadi.
  4. ERROR: smallint out of range — smallint ning chegarasi 32 767.
  5. NULL (psql'da bo'sh) — massivlar 1 dan boshlanadi, 0-element yo'q. Xato emas, NULL — bu ham tuzoq.

Biz 1–5 ni o'z nusxamizda ham tekshirdik (PostgreSQL 17.6): natijalar shunday.

3-mashq (qiyin): «Bahor» buyurtmalari jadvali

«Bahor» oshxonasi yetkazib berish buyurtmalari uchun jadval yarating: id, telefon, summa (so'm, tiyin bilan), tolandi (sukut false), yaratilgan (aniq lahza), yetkazish (faqat kun). Ikkita qator qo'shing (Toshkent vaqti bilan 2026-10-24 21:30 va 23:50, yetkazish 25- va 31-oktabr). So'rovlar:

  1. Hamma summalar yig'indisi.
  2. Har buyurtma uchun yetkazishgacha necha kun qoldi (yaratilgan kunidan) va yaratilgan vaqt UTC'da.
  3. telefon va summa qiymatlarining bayt o'lchami (pg_column_size).

CREATE TABLE sintaksisini CREATE TABLE va cheklovlar darsida to'liq o'rganamiz — hozir yechimdagi namunaga qarab yozing. AT TIME ZONE 'UTC' — lahzani UTC soatida ko'rsatadi, ::date — sessiya zonasidagi kun.

Yechim
sql
SET TIME ZONE 'Asia/Tashkent';
CREATE TABLE buyurtmalar (
  id          bigint        GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  telefon     text          NOT NULL,
  summa       numeric(12,2) NOT NULL,
  tolandi     boolean       NOT NULL DEFAULT false,
  yaratilgan  timestamptz   NOT NULL,
  yetkazish   date
);
INSERT INTO buyurtmalar (telefon, summa, yaratilgan, yetkazish) VALUES
  ('+998 90 000 00 01', 105000, '2026-10-24 21:30+05', '2026-10-25'),
  ('+998 90 000 00 02', 0.1, '2026-10-24 23:50+05', '2026-10-31');
SELECT sum(summa) AS jami FROM buyurtmalar;
SELECT id, yetkazish - yaratilgan::date AS kun_qoldi,
       yaratilgan AT TIME ZONE 'UTC' AS utc_vaqt
FROM buyurtmalar ORDER BY id;
SELECT pg_column_size(telefon) AS telefon_bayt,
       pg_column_size(summa) AS summa_bayt
FROM buyurtmalar WHERE id = 1;

Natija (PostgreSQL 17.6):

text
SET
CREATE TABLE
INSERT 0 2
   jami
-----------
 105000.10
(1 row)

 id | kun_qoldi |      utc_vaqt
----+-----------+---------------------
  1 |         1 | 2026-10-24 16:30:00
  2 |         7 | 2026-10-24 18:50:00
(2 rows)

 telefon_bayt | summa_bayt
--------------+------------
           18 |          7
(1 row)

numeric tiyinni aniq qo'shdi (105000.10). 23:50 dagi buyurtma Toshkentda 24-oktabrda yaratilgan, UTC'da ham hali 24-chi (18:50). Agar u 2026-10-25 01:00 da (Toshkent) yaratilganida — Toshkent kuni 25, UTC kuni esa 24 bo'lardi: ::date qaysi zonada hisoblanishi muhim. numeric qiymati hajmi raqamlar soniga bog'liq (bu yerda 7 bayt).

Telefon nega 18 bayt, «Qaysi tur qancha joy oladi» bo'limida esa 21 edi? U yerda biz alohida qiymatni o'lchadik — unga 4 baytlik sarlavha qo'shiladi (17 belgi + 4). Jadvalga yozilgan qisqa matn esa ixcham saqlanadi: sarlavha 1 bayt (17 + 1 = 18). Ikkala raqam ham haqiqiy — nimani o'lchayotganingizga qarang.

4-mashq: SQL qadami

«SQL qadami» jadvaliga foydalanuvchilar uchun yana ikkita ustun taklif qiling: oxirgi kirgan vaqti va tug'ilgan sanasi (ixtiyoriy). Turlarini va nega aynan shunday ekanini yozing.

Yechim

oxirgi_kirish timestamptz — aniq lahza, foydalanuvchi qaysi zonada bo'lishidan qat'i nazar to'g'ri. tugilgan_sana date — faqat kun, soat va zona ma'nosiz. Ikkalasi ham NULL bo'lishi mumkin (hali kirmagan yoki sanani bermagan). Kanon sxemasida bu ustunlar yo'q — bu mashq faqat tur tanlash uchun.

12. Real ishda

  • Kod review: float ustunidagi narx, varchar(255) hamma joyda, timestamp (zonasiz) — review'da birinchi so'raladigan savollar.
  • Migratsiya narxi: int → bigint yoki timestamp → timestamptz katta jadvalda uzoq qulf va to'xtash talab qiladi. Tur bir martada to'g'ri tanlanadi.
  • API bilan chegara: JSON'da bigint va numeric ko'pincha satr bo'lib boradi (JS number aniqligi yetmaydi), timestamptz — ISO 8601 satri (2026-10-24T04:00:00Z).
  • Intervyu savollari: "Pulni qaysi turda saqlaysiz va nega?", "timestamp va timestamptz farqi?", "text va varchar farqi Postgres'da?".

Xulosa

  • Butun son: integer (4 bayt), bigint (8 bayt) — ID uchun bigint; chegaradan oshish — xato (integer out of range).
  • Pul — numeric (yoki tiyinda bigint); float8 da 0.1 + 0.2 = 0.30000000000000004, o'nta 0.1 — 0.9999999999999999.
  • Matn — text + CHECK; ::varchar(n) cast jim kesadi; char_length — belgi, octet_length — bayt (ʻ — 2 bayt).
  • Vaqt nuqtasi — timestamptz (ichida UTC), kun — date, davomiylik — interval; 31-yanvar + 1 oy = 28-fevral.
  • uuid (uuidv7() — PG 18), jsonb (kalitlar tartiblanadi), massiv (1 dan boshlanadi), bytea, inet; telefon va indeks — text.

Keyingi dars: CREATE TABLE va cheklovlar — vazifalar bazasining birinchi ikki jadvalini cheklovlar bilan yaratamiz.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
PostgreSQL ma'lumot turlari: son, pul, matn, vaqt, UUID va JSON — IlmHamroh