Mundarija (27)
- Bu darsda
- 1. Nega bu kerak?
- 2. CASE: agar-aks holda
- 2.1 Qidiruvli CASE
- 2.2 Oddiy CASE
- 3. Tur o'girish
- 3.1 :: va CAST
- 4. Matn funksiyalari
- 4.1 Asosiylar
- 4.2 Tozalash va ajratish
- 4.3 Funksiya WHERE'da
- 5. Sana va vaqt funksiyalari
- 5.1 Kesish, ajratish, qo'shish
- 5.2 Vaqt ayirmasi — interval
- 5.3 now() tranzaksiya ichida o'zgarmaydi
- 6. Son funksiyalari
- 6.1 Yaxlitlash va boshqalar
- 6.2 Interval bilan agregat
- 7. SQL qadami: ro'yxat uchun hisoblangan maydonlar (holat 21, commit yo'q)
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): natijani toping
- 2-mashq (o'rta): ixcham ro'yxat
- 3-mashq (qiyin): teglar matndan
- 10. Real ishda
- Xulosa
- Manbalar
PostgreSQL funksiyalari: CASE, matn, sana va son funksiyalari
Qisqacha: SQL'da
SELECTro'yxati,WHEREvaORDER BYda faqat ustun emas, ifoda yoziladi: arifmetika,CASE WHEN … THEN … END(agar-aks holda), tur o'girish ('42'::int) va yuzlab o'rnatilgan funksiyalar. Matn uchun —lower,trim,concat,regexp_replace,split_part; vaqt uchun —now(),date_trunc,extract,interval,age; son uchun —round,greatest,least. Tuzoqlar:7 / 2 = 3(butun bo'linma),||NULLberadi,concatesaNULLni tashlaydi,now()tranzaksiya ichida o'zgarmaydi.
Bu darsda
CASEbilan qiymatga qarab matn yoki son chiqarasiz.::vaCASTbilan tur o'girasiz, butun son bo'linmasi tuzog'ini bilasiz.- Matn funksiyalari bilan tozalaysiz, ajratasiz va formatlaysiz.
now(),date_trunc,extract,interval,agebilan vaqt hisoblaysiz.round,greatest,leastvaintervalagregatlari bilan statistika chiqarasiz.
Oldin bilishingiz kerak: ALTER TABLE va sxemani o'zgartirish, SELECT va WHERE, NULL mantiqi, PostgreSQL ma'lumot turlari.
1. Nega bu kerak?
ALTER TABLE darsida vazifalarga muddat, bajarilgan_vaqt, ustuvorlik qo'shdik. Endi ilova savollar beradi:
- Bu vazifa "faol"mi, "muddati o'tgan"mi yoki "bajarilgan"mi?
- Muddatga qancha vaqt qoldi?
- Vazifalar o'rtacha qancha vaqtda bajariladi?
- Telefon raqamini bir xil shaklga keltirish kerak.
Har birini ilovada — JavaScript'da — qilish mumkin: hamma qatorni olib, aylantirib. Lekin 40 ta emas, 2 million qator bo'lsa-chi? "Muddati o'tganlar soni" uchun 2 million qatorni tarmoq orqali tortish — isrof. Baza shu hisobni ma'lumot yonida bajaradi va faqat natijani beradi.
Ikkinchi sabab — bir xillik. "Muddati o'tgan" qoidasi frontend'da, mobil ilovada va hisobotda uch xil yozilsa, ertaga ular farq qilib qoladi. So'rovdagi bitta CASE hammaga bir xil javob beradi.
O'xshatish: kalkulyatorli kassa. Kassir har mahsulot narxini qog'ozga yozib, uyga olib ketib, u yerda qo'shmaydi. Kassa apparati darhol jami, chegirma va qaytimni hisoblaydi. SQL funksiyalari — bazaning kalkulyatori.
2. CASE: agar-aks holda
2.1 Qidiruvli CASE
CASE — JavaScript'dagi if … else if … else ning SQL ko'rinishi, faqat u qiymat qaytaradi. Bu darsdagi misollar holat 21 bazasida. Joriy vaqt har kuni o'zgaradi, shuning uchun kanon "bugun" sifatida qat'iy vaqt oladi: 2026-10-20 12:00+05. Kanon (PostgreSQL 18.6):
SELECT id, matn,
CASE WHEN bajarildi THEN 'bajarilgan'
WHEN muddat < '2026-10-20 12:00+05' THEN 'muddati o''tgan'
WHEN muddat IS NULL THEN 'muddatsiz'
ELSE 'faol' END AS holat
FROM vazifalar
WHERE egasi_id = 3
ORDER BY id;Natija:
id | matn | holat
----+------------------------------------------------+----------------
10 | Mashinani texnik ko'rikka olib borish #mashina | muddati o'tgan
11 | Moy almashtirish #mashina | bajarilgan
21 | Hovlidagi daraxtlarni oqlash #uy | bajarilgan
24 | Do'konga yangi narxlarni kiritish #ish | muddati o'tgan
32 | Soliq hisobotini topshirish #ish #to'lov | faol
35 | Futbol: payshanba 20:00 #sport | bajarilgan
(6 rows)Bitta qator uchun CASE shunday "yuradi":
flowchart TD
A["Qator"] --> B{"bajarildi?"}
B -->|true| R1["'bajarilgan'"]
B -->|"false"| C{"muddat < bugun?"}
C -->|true| R2["'muddati o''tgan'"]
C -->|"false yoki NULL"| D{"muddat IS NULL?"}
D -->|true| R3["'muddatsiz'"]
D -->|false| R4["ELSE: 'faol'"]Diagrammadagi o'rta tarmoqqa qarang: NULL ham false yo'lidan ketadi.
Qoidalar:
- Shartlar yuqoridan pastga tekshiriladi, birinchi
truebo'lgan yutadi. 11-vazifa bajarilgan — keyingi shartlar uning uchun tekshirilmaydi. Tartib muhim:bajarildibirinchi bo'lmasa, muddati o'tgan bajarilgan vazifa "muddati o'tgan" deb chiqardi. ELSEbo'lmasa va hech bir shart mos kelmasa —NULL.- Shart
NULLbo'lsa — u "mos kelmadi" hisoblanadi (NULL mantiqi). Sardorning muddatsiz vazifasimuddat < …daNULLberadi va keyingi shartga o'tadi.
2.2 Oddiy CASE
Bitta ustunni bir nechta qiymat bilan solishtirsangiz — qisqa shakl. Biz ishga tushirdik (PostgreSQL 17.6, Windows 11):
SELECT ustuvorlik,
CASE ustuvorlik WHEN 'yuqori' THEN '!!!'
WHEN 'orta' THEN '!!'
ELSE '!' END AS belgi
FROM vazifalar WHERE id IN (1, 2, 38) ORDER BY id;Natija:
ustuvorlik | belgi
------------+-------
yuqori | !!!
orta | !!
past | !
(3 rows)CASE istalgan joyda ishlaydi: ORDER BY CASE … END (o'z tartibingiz), count(*) FILTER o'rnida sum(CASE WHEN … THEN 1 ELSE 0 END) (boshqa bazalarda), ALTER TABLE darsidagi USING CASE ….
Tekshirib ko'ring:
CASE WHEN muddat IS NULL THEN 'muddatsiz' WHEN bajarildi THEN 'bajarilgan' … END— muddatsiz, lekin bajarilgan vazifa nima deb chiqadi?
Javob
"muddatsiz". Birinchi mos shart yutadi, bajarildi tekshirilmaydi ham. Shuning uchun eng muhim holat (bajarildi) birinchi turishi kerak.
3. Tur o'girish
3.1 :: va CAST
ifoda::tur — PostgreSQL'ning qisqa yozuvi, CAST(ifoda AS tur) — SQL standarti. Ma'nosi bir xil. Kanon (PostgreSQL 18.6):
SELECT '42'::int + 1 AS cast1,
CAST('2026-10-24' AS date) AS cast2,
7 / 2 AS butun_bolish,
7 / 2.0 AS kasr,
7::numeric / 2 AS numeric_bolish;Natija:
cast1 | cast2 | butun_bolish | kasr | numeric_bolish
-------+------------+--------------+--------------------+--------------------
43 | 2026-10-24 | 3 | 3.5000000000000000 | 3.5000000000000000
(1 row)Uchinchi ustunga qarang: 7 / 2 = 3. Ikki butun son bo'linsa, natija ham butun — kasr qismi tashlanadi. JavaScript'da 7 / 2 = 3.5 edi — bu yerda tuzoq. Bittasini kasrga aylantiring: 7 / 2.0 yoki 7::numeric / 2. Agregatlar darsidagi foiz hisobida 100.0 * … yozganimiz shu sababdan.
O'girib bo'lmaydigan qiymat — xato. Biz ishga tushirdik (PostgreSQL 17.6):
SELECT 'qirq ikki'::int;Natija:
ERROR: invalid input syntax for type integer: "qirq ikki"
LINE 1: SELECT 'qirq ikki'::int;
^Tarjimasi: "integer turi uchun noto'g'ri kiritish: «qirq ikki»". JavaScript'dagi Number("qirq ikki") jim NaN qaytarardi; PostgreSQL esa to'xtatadi. Bu yaxshi: noto'g'ri ma'lumot jim tarqalmaydi.
4. Matn funksiyalari
4.1 Asosiylar
Kanon (PostgreSQL 18.6):
SELECT concat('Aziz', ' ', NULL, 'Karimov') AS concat_null_tashlaydi,
'Aziz' || ' ' || NULL AS pipe_null_beradi,
lower('O''ZBEKISTON'), upper('oʻzbek'),
initcap('aziz karimov'), trim(' salom ') AS trim,
substring('Postgres''ni Docker''da' FROM 1 FOR 8)
AS substring,
left('JavaScript', 4), length('Toshkent');Natija:
concat_null_tashlaydi | pipe_null_beradi | lower | upper | initcap | trim | substring | left | length
-----------------------+------------------+-------------+--------+--------------+-------+-----------+------+--------
Aziz Karimov | | o'zbekiston | OʻZBEK | Aziz Karimov | salom | Postgres | Java | 8
(1 row)| Funksiya | Ish | JavaScript'dagi o'xshashi |
|---|---|---|
Ikki vertikal chiziq (a, b orasida) |
Ulash; NULL bo'lsa — NULL |
a + b |
concat(a, b, …) |
Ulash; NULL ni tashlaydi |
[a, b].join("") |
lower, upper |
Kichik/katta harf | toLowerCase() |
initcap |
Har so'z bosh harfi katta | — |
trim, btrim |
Chetdagi bo'shliqlar | trim() |
substring(s FROM i FOR n) |
Qism (1 dan sanaladi!) | slice(i - 1, …) |
left(s, n), right(s, n) |
Boshidan/oxiridan n belgi |
slice(0, n) |
length, char_length |
Belgilar soni | length (taxminan) |
Ikki tuzoq:
- Indeks 1 dan boshlanadi.
substring(… FROM 1 FOR 8)— birinchi 8 belgi. JavaScript'da indeks 0 dan. ||vaNULL. Ikkinchi ustun bo'sh —NULL. Ism yoki familiyasiNULLbo'lgan foydalanuvchi uchunism || ' ' || familiyabutunlayNULLbo'ladi.concat— xavfsizroq.
upper('oʻzbek') → OʻZBEK: ʻ (U+02BB) harf emas, u o'zgarmadi. PostgreSQL ma'lumot turlari darsida ko'rganimizdek, length belgilarni sanaydi, bayt emas. Biz ishga tushirdik (PostgreSQL 17.6): char_length('oʻqish') — 6, octet_length('oʻqish') — 7 (ʻ 2 bayt).
Diqqat: JS
"…".lengthUTF-16 birliklarini sanaydi,char_length— Unicode belgilarni. Emoji'da ular farq qiladi (2 va 1). Frontend "100 belgi" deb tekshirgan matnni baza boshqacha sanashi mumkin — CREATE TABLE darsidagimatncheklovi bilan bog'liq eslatma.
4.2 Tozalash va ajratish
Kanon (PostgreSQL 18.6):
SELECT regexp_replace('+998 90 123-45-67', '[^0-9]', '', 'g')
AS faqat_raqam,
split_part('aziz@example.com', '@', 2) AS domen,
replace('Bozor #bozor', '#', '') AS replace,
format('%s ning %s ta vazifasi', 'Aziz', 9) AS format,
position('#' IN 'Non olish #uy') AS pozitsiya;Natija:
faqat_raqam | domen | replace | format | pozitsiya
--------------+-------------+-------------+-------------------------+-----------
998901234567 | example.com | Bozor bozor | Aziz ning 9 ta vazifasi | 11
(1 row)regexp_replace(matn, regex, almashtirish, 'g')— regex bo'yicha almashtirish.'g'— hammasini (JS'dagi/…/gflagi).[^0-9]— "raqam bo'lmagan har belgi". Natija — faqat raqamlar: telefonni bir xil shaklda saqlash uchun.split_part(matn, ajratgich, n)— ajratib,n-bo'lakni oladi. JS'dagisplit("@")[1](lekin raqam 1 dan).replace— oddiy (regex'siz) almashtirish.format— shablon;%s— qiymat,%I— nom,%L— qiymat tirnoq bilan. Oxirgi ikkitasi dinamik SQL uchun (Parametrli so'rovlar).position— qism qayerda (1 dan; topilmasa 0).
4.3 Funksiya WHERE'da
Funksiyalar WHERE da ham ishlaydi. Biz ishga tushirdik (PostgreSQL 17.6):
SELECT id, matn FROM vazifalar
WHERE lower(matn) LIKE '%bozor%' AND egasi_id = 1;Natija:
id | matn
----+------------------------------------------
8 | Bozordan kartoshka va piyoz olish #bozor
(1 row)Bu ILIKE ning boshqa bazalardagi ekvivalenti. Lekin bir narsa bor: ustun funksiyaga o'ralsa (lower(matn)), oddiy indeks matn bo'yicha ishlamaydi. Uning uchun ifoda indeksi kerak — CREATE INDEX … (lower(matn)). Aynan shunday indeks bizda bor: foydalanuvchilar_email_key — lower(email) ustida (CREATE TABLE). Batafsil — Partial, expression va covering indekslar.
Tekshirib ko'ring:
split_part('2026-10-24', '-', 2)vasubstring('Toshkent' FROM 2 FOR 3)nima qaytaradi?
Javob
'10' va 'osh'. Ikkalasida ham sanash 1 dan: ikkinchi bo'lak — oy; ikkinchi belgidan boshlab 3 ta — o, s, h.
5. Sana va vaqt funksiyalari
5.1 Kesish, ajratish, qo'shish
Kanon (PostgreSQL 18.6, sessiya zonasi UTC):
SELECT date_trunc('month', '2026-10-24 15:40+05'::timestamptz)
AS oy_boshi,
extract(dow FROM '2026-10-24'::date) AS hafta_kuni,
extract(epoch FROM interval '1 day') AS soniya,
age('2026-10-24'::date, '2007-03-15'::date) AS yosh,
'2026-10-24 15:40'::timestamp + interval '90 minutes'
AS qoshildi;Natija:
oy_boshi | hafta_kuni | soniya | yosh | qoshildi
------------------------+------------+--------------+------------------------+---------------------
2026-10-01 00:00:00+00 | 6 | 86400.000000 | 19 years 7 mons 9 days | 2026-10-24 17:10:00
(1 row)| Funksiya | Ish |
|---|---|
date_trunc('month', t) |
Oy boshigacha "kesish" ('day', 'week', 'hour' ham) |
extract(qism FROM t) |
Qismni son qilib olish: year, month, day, hour, dow (hafta kuni, 0 — yakshanba) |
extract(epoch FROM …) |
Soniyalar soni |
age(a, b) |
Ikki sana farqi — yil, oy, kun bilan |
t + interval '90 minutes' |
Vaqt qo'shish/ayirish |
2026-10-24 — shanba, shuning uchun dow = 6. age — yoshni hisoblash uchun qulay: "19 yil 7 oy 9 kun".
date_trunc Agregatlar darsida haftalik guruhlashda ishlatilgan edi. oy_boshi dagi 00:00:00+00 ga qarang — oy boshi UTC'da hisoblandi. Toshkentning oy boshi esa 5 soat oldin. Bu muammo va uning yechimi (date_trunc(…, 'Asia/Tashkent'), AT TIME ZONE) — SQL'da sana va vaqt zonalari darsining asosiy mavzusi.
Oy oxiri arifmetikasi — biz ishga tushirdik (PostgreSQL 17.6): '2026-01-31'::date + interval '1 month' → 2026-02-28 00:00:00. 31-fevral yo'q, PostgreSQL oyning oxirgi kuniga tushiradi.
5.2 Vaqt ayirmasi — interval
Ikki timestamptz ayirmasi — interval. Kanon (PostgreSQL 18.6) — "bugun" (qat'iy) dan keyingi eng yaqin 5 ta muddat:
SELECT id, matn, muddat - '2026-10-20 12:00+05' AS qolgan_vaqt
FROM vazifalar
WHERE muddat > '2026-10-20 12:00+05' AND NOT bajarildi
ORDER BY muddat
LIMIT 5;Natija:
id | matn | qolgan_vaqt
----+------------------------------------------------+-----------------
23 | Oshxonadagi jo'mrakni almashtirish #ta'mir #uy | 06:00:00
31 | Python laboratoriya ishi #o'qish | 1 day 20:30:00
14 | IELTS writing task 2 mashqi #ingliz | 4 days 08:00:00
32 | Soliq hisobotini topshirish #ish #to'lov | 5 days 06:00:00
34 | SQL JOIN mashqlarini yechish #o'qish | 5 days 09:00:00
(5 rows)"Muddatga 6 soat qoldi" — ilova uchun tayyor ma'lumot.
5.3 now() tranzaksiya ichida o'zgarmaydi
now() — tranzaksiya boshlangan vaqt, soatning hozirgi ko'rsatkichi emas. Butun tranzaksiya davomida u bir xil. Haqiqiy soat — clock_timestamp(). Kanon (PostgreSQL 18.6):
BEGIN;
SELECT now() = now() AS teng,
pg_sleep(0.2),
now() = transaction_timestamp() AS tx_vaqti,
clock_timestamp() > now() AS soat_oldinda;
COMMIT;Natija:
BEGIN
teng | pg_sleep | tx_vaqti | soat_oldinda
------+----------+----------+--------------
t | | t | t
(1 row)
COMMITpg_sleep(0.2) — 0.2 soniya kutish. Kutishdan keyin ham now() tranzaksiya vaqtiga teng, clock_timestamp() esa oldinga ketdi.
Nega bu yaxshi? Bitta tranzaksiyada 100 ta vazifa yaratilsa, hammasining yaratilgan_vaqt i bir xil bo'ladi — ular "bir amal" sifatida ko'rinadi. INSERT va RETURNING darsida now() - yaratilgan_vaqt nol chiqqani ham shu sababdan edi. Uzoq skriptda haqiqiy o'tgan vaqtni o'lchash kerak bo'lsa — clock_timestamp().
Tekshirib ko'ring: Ertalab soat 9:00 da boshlangan va 9:05 da tugagan tranzaksiyada yozilgan vazifaning
DEFAULT now()vaqti qancha bo'ladi?
Javob
9:00 (tranzaksiya boshlangan payt), 9:05 emas. INSERT tranzaksiyaning qaysi daqiqasida bajarilganidan qat'i nazar.
6. Son funksiyalari
6.1 Yaxlitlash va boshqalar
Kanon (PostgreSQL 18.6):
SELECT round(2.5) AS r1, round(3.5) AS r2, round(-2.5) AS r3,
round(1234.5678, 2), trunc(1234.5678, 1),
ceil(1.1), floor(-1.1),
greatest(3, 9, 1), least(3, 9, NULL, 1) AS least_null,
17 % 5 AS qoldiq, power(2, 10), sqrt(2);Natija:
r1 | r2 | r3 | round | trunc | ceil | floor | greatest | least_null | qoldiq | power | sqrt
----+----+----+---------+--------+------+-------+----------+------------+--------+-------+--------------------
3 | 4 | -3 | 1234.57 | 1234.5 | 2 | -2 | 9 | 1 | 2 | 1024 | 1.4142135623730951
(1 row)| Funksiya | Ish |
|---|---|
round(x), round(x, n) |
Yaxlitlash (n xona) |
trunc(x, n) |
Kesish, yaxlitlamasdan |
ceil, floor |
Yuqoriga, pastga butun |
greatest, least |
Ro'yxatdagi eng katta, eng kichik |
% |
Bo'linma qoldig'i |
Ikki nozik joy:
round(-2.5) = -3.numericuchun "yarim" noldan uzoqqa yaxlitlanadi. JavaScript'daMath.round(-2.5)=-2— farq qiladi!float8(haqiqiy son) uchun esa boshqa qoida: biz ishga tushirdik (PostgreSQL 17.6) —round(2.5::numeric)→3,round(2.5::float8)→2,round(3.5::float8)→4("juftga" yaxlitlash). Pul hisobida turni aniq biling (Pul, miqdor va enum'larni modellash).least(3, 9, NULL, 1) = 1.greatestvaleastNULLni e'tiborsiz qoldiradi — oddiyNULLqoidasidan (NULL mantiqi) istisno.
Nolga bo'lish — ERROR: division by zero; himoyasi — x / nullif(y, 0) (NULL mantiqi).
6.2 Interval bilan agregat
avg vaqt oraliqlari bilan ham ishlaydi. Kanon (PostgreSQL 18.6) — ustuvorlik bo'yicha o'rtacha bajarilish vaqti:
SELECT ustuvorlik, count(*),
avg(bajarilgan_vaqt - yaratilgan_vaqt) AS ortacha,
justify_interval(avg(bajarilgan_vaqt - yaratilgan_vaqt))
AS korinishi
FROM vazifalar
WHERE bajarildi
GROUP BY 1
ORDER BY 1;Natija:
ustuvorlik | count | ortacha | korinishi
------------+-------+-----------------+-----------------
orta | 21 | 23:36:08.571428 | 23:36:08.571428
yuqori | 1 | 00:05:00 | 00:05:00
(2 rows)O'rta ustuvorlikdagilar o'rtacha ~23.6 soatda, yuqorisi (bitta — elektr to'lovi) 5 daqiqada bajarilgan. justify_interval — 30:00:00 kabi oraliqni 1 day 06:00:00 ga aylantiradi; bu yerda bir kundan kam, shuning uchun o'zgarmadi. "Past" yo'q — past ustuvorlikda bajarilgan vazifa yo'q. Bu kabi o'lchovlar keyinchalik Window funksiyalar bilan chuqurlashadi.
7. SQL qadami: ro'yxat uchun hisoblangan maydonlar (holat 21, commit yo'q)
Sxema o'zgarmaydi — holat 21 qoladi. Lekin ilova ro'yxati endi bazadan tayyor "holat" va "qolgan vaqt" ni olishi mumkin:
SELECT id, matn, ustuvorlik, muddat,
CASE WHEN bajarildi THEN 'bajarilgan'
WHEN muddat < now() THEN 'muddati_otgan'
WHEN muddat IS NULL THEN 'muddatsiz'
ELSE 'faol' END AS holat,
muddat - now() AS qolgan_vaqt
FROM vazifalar
WHERE egasi_id = 1 AND ota_id IS NULL
ORDER BY ustuvorlik DESC, muddat NULLS LAST, id;Bu yerda haqiqiy now() — natija kunga qarab o'zgaradi, shuning uchun uni ko'rsatmaymiz. Qat'iy "bugun" bilan xuddi shu CASE ni «Qidiruvli CASE» bo'limida ko'rdik. ORDER BY ustuvorlik DESC, muddat NULLS LAST, id — ORDER BY darsidagi barqaror tartib: yuqori ustuvorlik, keyin eng yaqin muddat, muddatsizlar oxirida.
Qaror: "holat"ni bazada hisoblashmi yoki ilovada? Ikkalasi ham to'g'ri bo'lishi mumkin. Bazada — hisobot, filtr (WHERE holat = …) va boshqa mijozlar uchun bir xillik. Ilovada — foydalanuvchining soat mintaqasi va tili hisobga olinadi. Kanon bu "holat"ni bazada saqlamaydi. Holat 40 dagi faol_vazifalar ko'rinishi (view) — saqlangan SELECT — faqat o'chirilgan vazifalarni yashiradi, "holat" ustunini hisoblamaydi. Ko'rinish nima va qachon kerak — Soft delete, timestamps va tarix darsida.
8. Ko'p uchraydigan xatolar
| Xato yoki belgi | Sabab | Davosi |
|---|---|---|
7 / 2 → 3 |
Butun son bo'linmasi | 7 / 2.0, ::numeric |
invalid input syntax for type integer |
O'girib bo'lmaydigan matn | Ma'lumotni tekshiring |
| Ism va familiyani ulash bo'sh natija berdi | Biri NULL |
concat yoki concat_ws |
substring bitta belgi siljigan |
Indeks 1 dan | JS'dagi 0 ni unutib |
CASE kutilmagan holat qaytardi |
Shartlar tartibi | Eng muhimini birinchi |
CASE NULL qaytardi |
ELSE yo'q |
ELSE qo'shing |
| Oy/kun chegarasi 5 soat siljigan | date_trunc UTC'da |
Zona — Sana va vaqt zonalari |
| Bir tranzaksiyadagi vaqtlar bir xil | now() — tranzaksiya vaqti |
clock_timestamp() |
round(-2.5) JS bilan mos emas |
Yaxlitlash qoidasi farqi | Turni va qoidani aniq biling |
9. Mashqlar
1-mashq (oson): natijani toping
9 / 4→concat('Bek', NULL, 'zod')→split_part('osh,lagmon,manti', ',', 3)→extract(month FROM '2026-10-24'::date)→greatest(5, NULL, 7)→
Yechim
- 2 — butun son bo'linmasi (2.25 emas).
- Bekzod —
concatNULLni tashlaydi;||bilanNULLbo'lardi. - manti — uchinchi bo'lak, sanash 1 dan.
- 10 — oktabr.
- 7 —
greatestNULLni e'tiborsiz qoldiradi.
2-mashq (o'rta): ixcham ro'yxat
Holat 21 da Azizning asosiy vazifalari (ota_id IS NULL) uchun:
qisqa— matn 25 belgidan uzun bo'lsa, birinchi 25 belgi +…, aks holda to'liq matn;belgi— ustuvorlik: yuqori!!!, o'rta!!, past!;muddat— Toshkent vaqtidaDD.MM HH24:MIshaklida, muddatsiz bo'lsa—.
Ishora: Toshkent vaqtiga o'tkazish — muddat AT TIME ZONE 'Asia/Tashkent' (buni SQL'da sana va vaqt zonalari darsida tushuntiramiz, hozir shablon sifatida ishlating). Formatlash — to_char(vaqt, 'DD.MM HH24:MI').
Yechim
SELECT id,
CASE WHEN char_length(matn) > 25
THEN left(matn, 25) || '…'
ELSE matn END AS qisqa,
CASE ustuvorlik WHEN 'yuqori' THEN '!!!'
WHEN 'orta' THEN '!!'
ELSE '!' END AS belgi,
coalesce(to_char(muddat AT TIME ZONE 'Asia/Tashkent',
'DD.MM HH24:MI'), '—') AS muddat
FROM vazifalar
WHERE egasi_id = 1 AND ota_id IS NULL
ORDER BY id;Natija (biz ishga tushirdik, PG 17.6):
id | qisqa | belgi | muddat
----+----------------------------+-------+-------------
1 | JavaScript kursining 26-q… | !!! | 31.10 23:59
2 | Postgres'ni Docker'da ko'… | !! | —
8 | Bozordan kartoshka va piy… | !! | —
9 | Onamga dori olib borish #… | !! | —
17 | Portfolio saytiga blog yo… | !! | 15.11 18:00
23 | Oshxonadagi jo'mrakni alm… | !!! | 20.10 18:00
28 | Elektr to'lovini Click or… | !!! | 10.10 23:59
34 | SQL JOIN mashqlarini yech… | !! | 25.10 21:00
38 | Velosiped zanjirini moyla… | ! | —
(9 rows)to_char(NULL, …) — NULL, coalesce uni — ga almashtirdi. Bazada muddat UTC'da (2026-10-31 18:59:00+00), Toshkent vaqtida esa 31.10 23:59 — oy oxiridagi yarim tun. || bu yerda xavfsiz: left(matn, 25) hech qachon NULL emas (matn — NOT NULL).
3-mashq (qiyin): teglar matndan
Vazifa matnidagi #teg larni funksiyalar bilan tahlil qiling (holat 21):
(a) Madinaning (egasi_id 4) har vazifasi uchun: teglar soni (matndagi # belgilari soni) va birinchi teg.
(b) Teglari eng ko'p 3 foydalanuvchi: egasi_id va jami teglar soni.
Ishora: # lar soni = matn uzunligi − # lar olib tashlangan matn uzunligi (replace). Birinchi teg — substring(matn FROM '#[^ ]+'): substring ga regex berilsa, birinchi mos bo'lakni qaytaradi ([^ ]+ — "bo'shliq bo'lmagan belgilar").
Yechim
-- (a)
SELECT id,
char_length(matn) - char_length(replace(matn, '#', ''))
AS teglar_soni,
substring(matn FROM '#[^ ]+') AS birinchi_teg
FROM vazifalar
WHERE egasi_id = 4
ORDER BY id;
-- (b)
SELECT egasi_id,
sum(char_length(matn) - char_length(replace(matn, '#', '')))
AS jami_teglar
FROM vazifalar
GROUP BY egasi_id
ORDER BY jami_teglar DESC, egasi_id
LIMIT 3;Natija (biz ishga tushirdik, PG 17.6):
id | teglar_soni | birinchi_teg
----+-------------+--------------
7 | 1 | #o'qish
13 | 1 | #o'qish
18 | 1 | #to'lov
31 | 1 | #o'qish
37 | 1 | #oila
41 | 0 |
42 | 0 |
46 | 0 |
47 | 0 |
(9 rows)
egasi_id | jami_teglar
----------+-------------
1 | 10
5 | 8
2 | 7
(3 rows)41, 42, 46, 47 — kichik vazifalar, ularda teg yo'q: substring NULL qaytardi (bo'sh katak). Bu usul sodda, lekin xatoga moyil: "Futbol: payshanba 20:00" dagi # bo'lmasa ham, "C# kursi" yoki "#1-o'rin" kabi matn noto'g'ri sanaladi. Shuning uchun UPSERT va MERGE darsida teglar alohida jadvalga, frontend TEG regex'ining aniq nusxasi bilan ajratiladi.
10. Real ishda
- API'da hisoblangan maydonlar —
holat,qolgan_vaqt,toliq_ismkabi maydonlar ko'pinchaSELECTdaCASE/funksiya bilan yasaladi; ORM'lar ham ularni "raw" ifoda sifatida qo'llab-quvvatlaydi. - Ma'lumot tozalash — import qilingan telefon, email, ismlar
regexp_replace,lower,trimbilan bir xil shaklga keltiriladi — ko'pincha bittaUPDATEbilan. - Hisobotlar —
date_trunc,extract,age,avg(interval)— dashboard'larning asosiy asbobi; to'g'ri zona bilan (Sana va vaqt zonalari). - Intervyu savollari: "
now()vaclock_timestamp()farqi?", "7 / 2SQL'da nima beradi?", "COALESCEvaCASEfarqi?".
Xulosa
CASE WHEN … THEN … ELSE … END— qiymat qaytaradigan "agar"; birinchi mos shart yutadi,ELSEsiz —NULL.::tur/CAST— tur o'girish; butun / butun = butun (7 / 2 = 3); o'girib bo'lmasa — xato.- Matn:
||(NULLberadi) vaconcat(NULLni tashlaydi),lower,trim,substring(1 dan),split_part,regexp_replace,format. - Vaqt:
date_trunc,extract,age,interval;now()— tranzaksiya vaqti,clock_timestamp()— haqiqiy soat; zona masalasi — Sana va vaqt zonalari. - Son:
round(numericvafloat8da qoida farq qiladi),greatest/leastNULLni e'tiborsiz qoldiradi,avg(interval).
Keyingi dars: UPSERT va MERGE — vazifa matnidagi #teg larni alohida jadvalga ajratamiz: INSERT … ON CONFLICT, DO NOTHING va DO UPDATE, MERGE … RETURNING.
Manbalar
- PostgreSQL 18 hujjati — Conditional Expressions: CASE
- PostgreSQL 18 hujjati — String Functions va Pattern Matching (
regexp_replace,substring … FROM regex) - PostgreSQL 18 hujjati — Date/Time Functions (
now(),clock_timestamp(),date_trunc,extract,age) - PostgreSQL 18 hujjati — Mathematical Functions (
round,trunc) va greatest/least
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!