IlmHamroh
JavaScript Full-stack/26-qism. SQL va PostgreSQL39/64-dars15 daqiqa
Mundarija (24)

Pul, miqdor va enum'larni modellash: numeric, tiyin, valyuta va holatlar

Qisqacha: Pul hech qachon float da saqlanmaydi — u ikkilik kasrda yaxlitlanadi va xato yig'iladi. To'g'ri yo'llar: numeric(19,4) (aniq o'nlik kasr) yoki butun son — eng kichik birlikda (bigint tiyin yoki so'm). Pul yonida doim valyuta turadi, boshqa valyutaga o'girish — o'sha kundagi kurs bilan. Holatlar (yangi, tugadi) uchun uch yo'l bor: enum (ixcham, tartibli, lekin qiymatni o'chirib bo'lmaydi), lookup jadval (moslashuvchan) va CHECK (oddiy).

Bu darsda

  • Nega float pul uchun yaroqsizligini raqam bilan ko'rsata olasiz.
  • numeric(19,4) va bigint (tiyin) orasida asosli tanlov qilasiz.
  • Valyuta ustuni va kurs tarixi bilan to'lovlarni to'g'ri so'mga o'girasiz.
  • Summani bo'lishda qoldiqni yo'qotmaslikni bilasiz.
  • Enum, lookup jadval va CHECK ni solishtirib, enum'ga qiymat qo'shish va o'chirish muammosini tushunasiz.

Oldin bilishingiz kerak: PostgreSQL ma'lumot turlari, Normalizatsiya, Subquery va LATERAL, ALTER TABLE.

1. Nega bu kerak?

Ilovada pul paydo bo'lishi bilan xato narxi keskin oshadi. Vazifa matnidagi xato — noqulaylik. To'lovdagi bir tiyinlik xato — mijoz shikoyati, buxgalteriya tafovuti, ba'zan sud.

vazifalar bazasida pul yo'q. Lekin kurs davomida «Bahor» oshxonasi menyusini, 24-qismdagi valyuta CLI'sidagi kurslarni ko'rdik; keyingi qismlarda to'lov (Click, Payme) va obuna paydo bo'ladi. Pulni saqlash qoidasi bir marta to'g'ri o'rganilishi kerak — shuning uchun bu dars tajriba bazasida, «Bahor» va to'lov misollarida.

O'xshatish: dorixona tarozisi. Bozordagi tarozida "taxminan bir kilo" yetarli, dorixonada esa milligramm aniq bo'lishi shart. Pul — dorixona tarozisi: "taxminan" bo'lmaydi.

2. float — pul uchun emas

2.1 Bir million marta 0.1 so'm

Ma'lumot turlari darsida 0.1 + 0.2 ning 0.30000000000000004 berishini ko'rdik. Kichik xato bitta amalda sezilmaydi — lekin u yig'iladi. Kanon tajribasi: bir million to'lov, har biri 0.1 so'm, uch xil turda (kanon sorovlar/39-pul-enum.sql, PostgreSQL 18.6; biz o'z 17.6 klasterimizda qayta ishga tushirdik — chiqish bir xil, uzun qatorlarni bo'lib yozdik):

sql
SELECT sum(0.1::float8) AS float8,
       sum(0.1::numeric(19,4)) AS numeric,
       sum(10::bigint) / 100.0 AS tiyin_bigint
FROM generate_series(1, 1000000);
text
       float8       |   numeric   |    tiyin_bigint
--------------------+-------------+---------------------
 100000.00000133288 | 100000.0000 | 100000.000000000000
(1 row)

float8 — 100 000 dan biroz ortiq; numeric va bigint — aniq 100 000. Xato kichik ko'rinadi, lekin u "ba'zan bor, ba'zan yo'q" — hisobot ikki marta hisoblanganda ikki xil natija berishi mumkin. Sababi: float sonni ikkilik kasrda saqlaydi va 0.1 ikkilikda cheksiz kasr (xuddi 1/3 o'nlikda 0.333… bo'lgani kabi).

JavaScript'da ham aynan shu — number ham float8 (Pul bilan ishlash JS'da darsida chuqur ko'ramiz):

js
console.log(0.1 + 0.2);
let jami = 0;
for (let i = 0; i < 10; i++) jami += 0.1;
console.log(jami);
const tiyinda = 10 * 10;
console.log(tiyinda / 100);

Konsolda:

text
0.30000000000000004
0.9999999999999999
1

O'n marta 10 tiyin qo'shsak — aniq 100 tiyin, ya'ni 1 so'm. O'n marta 0.1 so'm qo'shsak — 0.9999999999999999. Butun sonlar bilan xato yo'q.

2.2 Ikki to'g'ri yo'l

Usul Misol Afzallik Diqqat
numeric(19,4) 35000.0000 Aniq o'nlik kasr, istalgan valyuta Sekinroq, Node'ga satr bo'lib keladi
bigint (eng kichik birlik) tiyin: 3500000 Tez, ixcham (8 bayt) Har joyda "100 ga bo'lish"ni eslash

numeric(19,4) — jami 19 raqam, ulardan 4 tasi verguldan keyin. Nega aynan 4: valyuta kurslari va foizlar (masalan, 12.5 % soliq) oraliq hisobda ko'proq kasr talab qiladi; 19 raqam esa bigint diapazoniga yaqin. Bu ko'p moliyaviy tizimlardagi odatiy tanlov.

So'mda tiyin amalda ishlatilmaydi (narxlar butun so'mda). Shuning uchun faqat so'm bilan ishlaydigan ilovada bigint so'm ham to'g'ri variant — 1-mashqda shunday qilamiz. Bir nechta valyuta (dollar sentlari bilan) bo'lsa — numeric yoki har valyutaning eng kichik birligida bigint.

Node tomonida bitta muhim fakt: pg drayveri numeric va bigint ni satr bo'lib qaytaradi — aniqlik yo'qolmasligi uchun. Buni node-postgres asoslari darsida o'lchov bilan ko'ramiz.

Tekshirib ko'ring: Nega numeric(10,2) emas, numeric(19,4)? So'm uchun 2 ta kasr ham yetarli emasmi?

Javob

Yakuniy summalar uchun 2 ta kasr yetarli bo'lishi mumkin. Lekin oraliq hisoblar ko'proq aniqlik talab qiladi: kurs bilan ko'paytirish, foiz, bo'lish. Aks holda har qadamda yaxlitlanib, xato yig'iladi. numeric(10,2) esa eng ko'pi 99 999 999.99 ni sig'diradi — yirik kompaniya aylanmasi uchun kam; sig'masa numeric field overflow xatosi.

3. Valyuta va kurs

3.1 Pul yonida doim valyuta

"35 000" — so'mmi, dollarmi? Ustun nomi (narx_som) yordam beradi, lekin ilova bir kun boshqa valyutani qabul qilsa — sxema o'zgaradi. To'g'ri yo'l: miqdor yonida valyuta kodi (ISO 4217: UZS, USD, EUR). Kanon tajribasi:

sql
CREATE TABLE t39_tolov (
  id     int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  miqdor numeric(19,4) NOT NULL CHECK (miqdor > 0),
  valyuta char(3) NOT NULL DEFAULT 'UZS'
    CHECK (valyuta ~ '^[A-Z]{3}$'),
  vaqt   timestamptz NOT NULL DEFAULT now()
);
INSERT INTO t39_tolov (miqdor, valyuta, vaqt) VALUES
  (35000, 'UZS', '2026-10-20 13:00+05'),
  (12.5,  'USD', '2026-10-20 14:00+05'),
  (28000, 'UZS', '2026-10-21 13:00+05');
SELECT sum(miqdor) AS notogri_yigindi FROM t39_tolov;
text
CREATE TABLE
INSERT 0 3
 notogri_yigindi
-----------------
      63012.5000
(1 row)

63 012.5 — ma'nosiz son: so'm va dollar qo'shib yuborildi. Baza buni to'smaydi — valyutasi boshqa sonlar ham baribir sonlar. To'g'ri yig'indi — valyuta bo'yicha guruhlab:

sql
SELECT valyuta, sum(miqdor)
FROM t39_tolov GROUP BY valyuta ORDER BY 1;
text
 valyuta |    sum
---------+------------
 USD     |    12.5000
 UZS     | 63000.0000
(2 rows)

Qoida: pulni faqat bir xil valyuta ichida qo'shing. Boshqacha yig'indi kerak bo'lsa — avval bitta valyutaga o'giring.

3.2 Kurs tarixi

Dollarni so'mga qaysi kurs bilan o'giramiz? Bugungi emas — to'lov kunidagi. Aks holda o'tgan oy hisobotlari har kuni o'zgaradi. Shuning uchun kurs jadvali tarixni saqlaydi: (valyuta, sana) — kalit. Har to'lov uchun "to'lov kunidan oldingi eng so'nggi kurs"ni LATERAL bilan olamiz. Kurslar o'ylab topilgan (12 000) — haqiqiy kurslarni 24-qismdagi valyuta CLI Markaziy bank API'sidan olgan edi. Kanon tajribasi:

sql
CREATE TABLE t39_kurs (
  valyuta char(3), sana date, kurs numeric(19,4),
  PRIMARY KEY (valyuta, sana)
);
INSERT INTO t39_kurs VALUES
  ('USD', '2026-10-19', 11950), ('USD', '2026-10-20', 12000),
  ('UZS', '2026-10-20', 1), ('UZS', '2026-10-21', 1);
SELECT t.id, t.miqdor, t.valyuta, k.kurs,
       round(t.miqdor * k.kurs, 2) AS som_da
FROM t39_tolov t
LEFT JOIN LATERAL (
  SELECT kurs FROM t39_kurs k
  WHERE k.valyuta = t.valyuta
    AND k.sana <= (t.vaqt AT TIME ZONE 'Asia/Tashkent')::date
  ORDER BY sana DESC LIMIT 1
) k ON true
ORDER BY t.id;
text
CREATE TABLE
INSERT 0 4
 id |   miqdor   | valyuta |    kurs    |  som_da
----+------------+---------+------------+-----------
  1 | 35000.0000 | UZS     |     1.0000 |  35000.00
  2 |    12.5000 | USD     | 12000.0000 | 150000.00
  3 | 28000.0000 | UZS     |     1.0000 |  28000.00
(3 rows)

Uch nozik joy:

  1. Kun Toshkent bo'yicha ajratiladi (Sana va vaqt zonalari) — UTC kuni bilan kurs bir kun siljishi mumkin.
  2. <= va ORDER BY sana DESC LIMIT 1 — dam olish kunlari kurs e'lon qilinmasa, oxirgi ma'lum kurs olinadi.
  3. round(…, 2) — yaxlitlash faqat oxirida.

3.3 Bo'lish va yaxlitlash

100 000 so'mlik hisobni uch kishi teng bo'lishmoqchi. Har biriga 33 333.33 — lekin uchtasi 99 999.99. Bir tiyin yo'qoldi. Kanon tajribasi:

sql
SELECT round(100000 / 3.0, 2) AS har_biriga,
       round(100000 / 3.0, 2) * 3 AS jami_tiklanmaydi,
       100000 - 2 * round(100000 / 3.0, 2) AS oxirgisiga;
text
 har_biriga | jami_tiklanmaydi | oxirgisiga
------------+------------------+------------
   33333.33 |         99999.99 |   33333.34
(1 row)

Yechim — qoldiqni kimgadir berish: ikki kishiga 33 333.33, oxirgisiga 33 333.34. Jami — aniq 100 000. Buxgalteriyada bu "qoldiqni taqsimlash" deyiladi va qaysi qatorga berilishi qoida bilan belgilanadi (birinchisiga, eng kattasiga). 3-mashqda butun so'mlarda yozamiz.

3.4 money turi — tavsiya etilmaydi

Postgres'da money turi bor. Kanon tajribasi:

sql
SELECT 35000::money AS money_en_us;
text
 money_en_us
-------------
  $35,000.00
(1 row)

Dollar belgisi o'zi paydo bo'ldi — chunki money server lokali (lc_monetary) bo'yicha formatlanadi. Ichida valyuta saqlanmaydi: boshqa lokalli serverda xuddi shu qiymat boshqa belgi bilan chiqadi. Kasrlar soni ham lokalga bog'liq. Postgres hujjati ham uni yangi loyihalarda emas, numeric ni tavsiya qiladi. Xulosa: money ishlatmang.

4. Enum, lookup jadval va CHECK

4.1 Uch yo'l

Holat, tur, daraja — oldindan belgilangan qiymatlar ro'yxati. Bizda ustuvorlik: past, orta, yuqori. Uni saqlashning uch yo'li:

Usul Qiymat qo'shish Qiymat o'chirish Qo'shimcha maydon
Enum (CREATE TYPE … AS ENUM) ALTER TYPE … ADD VALUE Mumkin emas Yo'q
Lookup jadval + FK INSERT DELETE (ishlatilmasa) Bor (rang, tartib)
CHECK (holat IN (…)) Cheklovni qayta yaratish Cheklovni qayta yaratish Yo'q

Enum'ni ALTER TABLE darsida yaratgan edik va uning foydali xususiyatini ko'rdik: tartibi e'londagi tartib (ORDER BY ustuvorlik DESC → yuqori, orta, past), matn tartibi emas.

4.2 Enum'ga qiymat qo'shish

Kanon tajribasi — vaqtinchalik t39_holat turida. Yangi qiymat tranzaksiya ichida qo'shilishi mumkin (PG 12+), lekin o'sha tranzaksiyada ishlatib bo'lmaydi:

sql
CREATE TYPE t39_holat AS ENUM ('yangi', 'jarayonda', 'tugadi');
BEGIN;
ALTER TYPE t39_holat ADD VALUE 'bekor' AFTER 'tugadi';
SELECT 'bekor'::t39_holat;
text
CREATE TYPE
BEGIN
ALTER TYPE
ERROR:  unsafe use of new value "bekor" of enum type t39_holat
LINE 1: SELECT 'bekor'::t39_holat;
               ^
HINT:  New enum values must be committed before they can be used.

Tarjimasi: "enum turidagi yangi «bekor» qiymatidan xavfli foydalanish"; maslahat — "yangi enum qiymatlari ishlatilishidan oldin commit qilinishi kerak". Bu migratsiyalarda haqiqiy muammo: "qiymat qo'sh + mavjud qatorlarni yangila" bitta tranzaksiyada ishlamaydi — ikki bosqichga bo'linadi. Tranzaksiya xatodan keyin ROLLBACK; bilan yopiladi. Tranzaksiyadan tashqarida esa qo'shish darhol ishlaydi:

sql
ALTER TYPE t39_holat ADD VALUE 'bekor' AFTER 'tugadi';
SELECT enum_range(NULL::t39_holat);
text
ALTER TYPE
           enum_range
--------------------------------
 {yangi,jarayonda,tugadi,bekor}
(1 row)

AFTER 'tugadi' — tartibdagi o'rni. enum_range — hamma qiymatlar tartib bilan.

4.3 Enum'dan qiymat o'chirish

sql
ALTER TYPE t39_holat DROP VALUE 'bekor';
text
ERROR:  dropping an enum value is not implemented
LINE 1: ALTER TYPE t39_holat DROP VALUE 'bekor';
                             ^

"Enum qiymatini o'chirish amalga oshirilmagan" — bunday buyruq yo'q. Qiymatni olib tashlash uchun yangi tur yaratib, ustunni unga ko'chirish (ALTER COLUMN … TYPE … USING …) kerak — katta jadvalda bu butun jadvalni qayta yozish. Nomini o'zgartirish esa mumkin:

sql
ALTER TYPE t39_holat RENAME VALUE 'jarayonda' TO 'bajarilmoqda';
SELECT enum_range(NULL::t39_holat);
text
ALTER TYPE
            enum_range
-----------------------------------
 {yangi,bajarilmoqda,tugadi,bekor}
(1 row)

4.4 Lookup jadval va hajm

Lookup jadval — qiymatlar oddiy jadvalda, asosiy jadval ularga tashqi kalit bilan bog'lanadi. Qo'shish va o'chirish — oddiy INSERT/DELETE, qo'shimcha maydonlar (o'zbekcha nomi, rangi, tartibi) — bemalol. Hajmni solishtiramiz (kanon):

sql
CREATE TABLE t39_holat_lookup (
  kod text PRIMARY KEY, nom text NOT NULL, tartib int NOT NULL
);
INSERT INTO t39_holat_lookup VALUES
  ('yangi', 'Yangi', 1), ('jarayonda', 'Jarayonda', 2),
  ('tugadi', 'Tugadi', 3);
SELECT pg_column_size('bajarilmoqda'::t39_holat) AS enum_bayt,
       pg_column_size('jarayonda'::text) AS text_bayt;
text
CREATE TABLE
INSERT 0 3
 enum_bayt | text_bayt
-----------+-----------
         4 |        13
(1 row)

Enum har qatorda 4 bayt, matn kodi — uzunligiga qarab (bu yerda 13). Millionlab qatorda bu farq sezilarli, lekin hal qiluvchi emas.

Qaysi birini tanlash — quyidagi savollar zanjiri bilan. Nimaga qarang: birinchi savol "qiymatda qo'shimcha ma'lumot bormi?".

flowchart TB
  S1{"Nom, rang, tartib kabi<br/>qo'shimcha ma'lumot bormi?"} -- ha --> L["Lookup jadval + FK"]
  S1 -- yo'q --> S2{"Ro'yxat tez-tez o'zgaradimi<br/>yoki qiymat o'chiriladimi?"}
  S2 -- ha --> L
  S2 -- yo'q --> S3{"Tartib muhimmi?"}
  S3 -- ha --> E["Enum"]
  S3 -- yo'q --> C["text + CHECK yoki enum"]
  • Enum — qiymatlar kam, kamdan-kam o'zgaradi, tartib muhim, qo'shimcha ma'lumot yo'q. Kanon ustuvorlik uchun shuni tanlagan.
  • Lookup jadval — qiymatlarni admin panel orqali boshqarish kerak, o'zbekcha nomi yoki rangi bor, qiymat o'chirilishi mumkin.
  • CHECK — juda oddiy holat, 2–3 qiymat, o'zgarmaydi (valyuta ~ '^[A-Z]{3}$' kabi format tekshiruvi ham shu).

Tajriba jadvallarini tozalaymiz:

sql
DROP TABLE t39_tolov, t39_kurs, t39_holat_lookup;
DROP TYPE t39_holat;
text
DROP TABLE
DROP TYPE

5. Ko'p uchraydigan xatolar

1. Pul float/real/double precision da. Xato yig'iladi, hisobotlar mos kelmaydi. Tuzatish: numeric(19,4) yoki bigint eng kichik birlikda.

2. Valyutasiz summa. narx ustuni — qaysi valyutada? Ikkinchi valyuta kelgan kuni hamma eski qatorlar shubhali. Tuzatish: valyuta char(3) (ISO 4217).

3. Bugungi kurs bilan eski to'lovni o'girish. O'tgan oy hisoboti har kuni o'zgaradi. Tuzatish: kurs tarixi va to'lov kunidagi kurs.

4. Har qadamda yaxlitlash. Oraliq natijalar yaxlitlanib, xato yig'iladi. Tuzatish: to'liq aniqlik bilan hisoblab, faqat oxirida yaxlitlang; bo'lishda qoldiqni taqsimlang.

5. money turi. Lokalga bog'liq, valyutasiz. Tuzatish: numeric + valyuta.

6. Tez o'zgaradigan ro'yxat uchun enum. Har yangi holat — migratsiya, o'chirish — imkonsiz. Tuzatish: lookup jadval.

7. Enum qiymatini qo'shib, o'sha tranzaksiyada ishlatish. unsafe use of new value. Tuzatish: migratsiyani ikki qadamga bo'ling.

6. Mashqlar

Mashqlar istalgan bazada (sxemaga bog'liq emas). Jadval yaratadiganlari — BEGIN … ROLLBACK ichida.

1-mashq (oson)

«Bahor» menyusi: t39_menyu (nom PK, narx bigint, narx > 0) — osh 35 000, lag'mon 28 000, manti 30 000, ko'k choy 5 000 (butun so'm). 2 ta osh va 3 ta ko'k choyli buyurtma summasini chiqaring (jami). Ishora: buyurtmani VALUES bilan "jadval" qiling va menyuga birlashtiring (JOIN).

Yechim
sql
BEGIN;
CREATE TABLE t39_menyu (
  nom  text PRIMARY KEY,
  narx bigint NOT NULL CHECK (narx > 0)
);
INSERT INTO t39_menyu VALUES
  ('osh', 35000), ('lag''mon', 28000), ('manti', 30000),
  ('ko''k choy', 5000);
SELECT sum(m.narx * b.soni) AS jami
FROM (VALUES ('osh', 2), ('ko''k choy', 3)) AS b(nom, soni)
JOIN t39_menyu m ON m.nom = b.nom;
ROLLBACK;
text
BEGIN
CREATE TABLE
INSERT 0 4
 jami
-------
 85000
(1 row)

ROLLBACK

2 × 35 000 + 3 × 5 000 = 85 000. Faqat so'm va narxlar butun — bigint yetarli va eng tez. Real buyurtma jadvalida narx buyurtma qatoriga ham nusxalanadi (snapshot).

2-mashq (o'rta)

Ikki to'lov — 2026-10-19 va 2026-10-21 kunlari, har biri 10.00 dollar. Kurslar: 19-oktyabr — 11 950, 20-oktyabr — 12 000 (21-oktyabr kursi yo'q). Har to'lovni o'z kunidagi (yoki undan oldingi eng so'nggi) kurs bilan so'mga o'giring: sana, miqdor, kurs, som_da. Ishora: «Kurs tarixi» bo'limidagi LEFT JOIN LATERAL; to'lovlarni VALUES bilan bering.

Yechim
sql
BEGIN;
CREATE TABLE t39_kurs (
  valyuta char(3), sana date, kurs numeric(19,4),
  PRIMARY KEY (valyuta, sana)
);
INSERT INTO t39_kurs VALUES
  ('USD', '2026-10-19', 11950), ('USD', '2026-10-20', 12000);
SELECT t.sana, t.miqdor, k.kurs, round(t.miqdor * k.kurs, 2) AS som_da
FROM (VALUES (date '2026-10-19', 10.00),
             (date '2026-10-21', 10.00)) AS t(sana, miqdor)
LEFT JOIN LATERAL (
  SELECT kurs FROM t39_kurs
  WHERE valyuta = 'USD' AND sana <= t.sana
  ORDER BY sana DESC LIMIT 1
) k ON true
ORDER BY t.sana;
ROLLBACK;
text
BEGIN
CREATE TABLE
INSERT 0 2
    sana    | miqdor |    kurs    |  som_da
------------+--------+------------+-----------
 2026-10-19 |  10.00 | 11950.0000 | 119500.00
 2026-10-21 |  10.00 | 12000.0000 | 120000.00
(2 rows)

ROLLBACK

21-oktyabr kursi yo'q — oxirgi ma'lumi (20-oktyabr) olindi. Agar kurs umuman topilmasa, LEFT JOIN tufayli qator qoladi va kurs NULL bo'ladi — ilova buni "kurs noma'lum" deb ko'rsatishi kerak, jim 0 emas.

3-mashq (qiyin)

100 000 so'mni 3 kishiga butun so'mlarda, qoldiqsiz bo'ling: qoldiq birinchi kishilarga bittadan beriladi. kishi, ulush ni chiqaring, keyin ulushlar yig'indisi 100 000 ekanini tekshiring. Ishora: butun bo'lish — 100000 / 3 (int), qoldiq — % (Ifodalar); kishilar — generate_series(1, 3).

Yechim
sql
SELECT n AS kishi,
       100000 / 3 + CASE WHEN n <= 100000 % 3 THEN 1 ELSE 0 END
         AS ulush
FROM generate_series(1, 3) AS n;
SELECT sum(100000 / 3 + CASE WHEN n <= 100000 % 3 THEN 1 ELSE 0 END)
         AS jami
FROM generate_series(1, 3) AS n;
text
 kishi | ulush
-------+-------
     1 | 33334
     2 | 33333
     3 | 33333
(3 rows)

  jami
--------
 100000
(1 row)

100000 / 3 = 33 333 (butun bo'lish), qoldiq 100000 % 3 = 1 — u birinchi kishiga. Jami aniq 100 000. Bu "eng katta qoldiq" usulining eng oddiy shakli; ulushlar teng bo'lmasa (masalan, 50 %, 30 %, 20 %), qoldiq eng katta kasr qismli ulushga beriladi.

7. SQL qadami

Bu dars — faqat tajriba, sxema o'zgarmaydi: holat 38 da qolamiz. vazifalar da pul yo'q, shuning uchun kanon tajribasi alohida bazada «Bahor» va to'lov misollarida bajarilgan.

Kanon qarori ustuvorlik haqida: enum qoladi — 3 qiymat, kamdan-kam o'zgaradi, tartib muhim (ro'yxatda "yuqori" birinchi). Agar keyinroq foydalanuvchilar o'z ustuvorlik darajalarini yaratishi kerak bo'lsa (rang va nom bilan) — lookup jadvalga ko'chiriladi; bu migratsiya (ALTER COLUMN … TYPE text USING ustuvorlik::text + tashqi kalit) rejalashtirilgan ish bo'ladi.

Commit yo'q.

8. Real ishda

  • To'lov tizimlari. Click va Payme API'larida summa ko'pincha tiyinda (butun son) uzatiladi — hujjatlarini o'qiganda birligiga e'tibor bering (hujjat bo'yicha; biz ularning API'sini sinamadik). Stripe ham eng kichik birlikda ishlaydi (sent).
  • Buxgalteriya va bank. numeric, valyuta, kurs tarixi, qoldiqni taqsimlash — har kungi ish. Markaziy bank kursi har kuni e'lon qilinadi — kurs jadvali aynan shu ma'lumot.
  • Statuslar. Buyurtma holatlari (yangi, tolangan, yetkazilmoqda) ko'pincha lookup jadval yoki text + CHECK bo'ladi — chunki biznes tez-tez yangi holat qo'shadi.
  • Intervyuda: "pulni qanday saqlaysiz?" — klassik savol. Javob: float emas; numeric yoki eng kichik birlikda bigint; valyuta ustuni; yaxlitlash va qoldiq qoidasi.

Xulosa

  • float pulni yaxlitlaydi va xato yig'iladi: 1 mln × 0.1 → 100000.00000133288.
  • Pul — numeric(19,4) yoki eng kichik birlikda bigint; faqat so'm bo'lsa — bigint so'm.
  • Pul yonida doim valyuta; boshqa valyutaga — to'lov kunidagi kurs bilan (kurs tarixi + LATERAL).
  • Yaxlitlash — oxirida; bo'lishda qoldiqni aniq qoida bilan taqsimlang. money turi — yo'q.
  • Enum — ixcham va tartibli, lekin qiymat o'chirilmaydi va yangi qiymat o'sha tranzaksiyada ishlatilmaydi; tez o'zgaradigan ro'yxat — lookup jadval.

Keyingi dars: Amaliyot: real loyiha sxemasini loyihalash — talablardan yakuniy sxemagacha: vazifalar bazasini review qilamiz va A bosqichni yakunlaymiz.

Manbalar

  • PostgreSQL 18 hujjati: "Numeric Types", "Monetary Types", "Enumerated Types", "ALTER TYPE" — postgresql.org/docs/18, 2026-10-24 da ko'rildi.
  • ISO 4217 — valyuta kodlari standarti.
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Pul, miqdor va enum'larni modellash: numeric, tiyin, valyuta va holatlar — IlmHamroh