Mundarija (29)
- Bu darsda
- 1. Nega bu kerak?
- 2. Chiqarish: \copy va COPY
- 2.1 Ikkisining farqi
- 2.2 Faqat kerakli qatorlar
- 3. Jarrohlik tranzaksiyasi
- 3.1 Tuzilishi
- 3.2 Tashqi kalit tartibi
- 3.3 Identity ustuni: COPY id ni yozadi
- 4. Sequence tuzog'i
- 4.1 Takrorlaymiz
- 4.2 To'g'ri tartib: setval(GREATEST(…))
- 4.3 Trigger'lar ishladi
- 5. CRLF tuzog'i
- 5.1 Nima bo'ldi
- 5.2 Versiyaga bog'liq xabar, bitta yechim
- 6. Prod → staging: anonimlashtirish
- 6.1 Nega
- 6.2 So'rovda almashtirish
- 6.3 Nimani yana unutmang
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): tartib
- 2-mashq (o'rta): izohni ko'chirish
- 3-mashq (qiyin): qator oxirlarini tekshirish
- 9. Loyiha qadami: kanon tajribasi
- 10. Real ishda
- Xulosa
- Manbalar
Ma'lumotni qisman ko'chirish: \copy, jarrohlik tranzaksiyasi va CRLF tuzog'i
Qisqacha: Butun bazani tiklash o'rniga faqat kerakli qatorlarni ko'chirish — "jarrohlik usuli": manbadan
\copy (SELECT …) TO STDOUTbilan faylga, maqsadda bitta tranzaksiyadaBEGIN; DELETE …; COPY … FROM stdin; COMMIT;. Uch tuzoq bor: jadvallar tashqi kalit tartibida ko'chiriladi, ko'chirilganidlardan keyin sequencesetvalbilan suriladi, Windows'dan kelgan faylda qator oxiri CRLF bo'lsa, Linux'dagi Postgres uni rad etishi mumkin.
Bu darsda
\copyvaCOPYfarqini bilib, kerakli qatorlarni faylga chiqarasiz.- "Jarrohlik" tranzaksiyasini to'g'ri tartibda yozasiz: o'chirish, ko'chirish, sequence, commit.
- Identity ustuni va sequence tuzog'ini o'z ko'zingiz bilan ko'rasiz.
- CRLF xatosini taniysiz va uning versiyaga bog'liqligini tushuntirasiz.
- Prod ma'lumotini staging'ga anonimlashtirib ko'chirasiz.
Oldin bilishingiz kerak: Backup va restore, Ommaviy ma'lumot: COPY, batch va cursor, Foreign key va referential actions, Tranzaksiya asoslari.
1. Nega bu kerak?
Backup va restore darsida --clean bilan to'liq tiklash zaxiradan keyin ro'yxatdan o'tgan foydalanuvchini o'chirib yuborganini ko'rdik. Real ishda ko'pincha butun bazani emas, uning kichik bir bo'lagini qaytarish yoki ko'chirish kerak bo'ladi:
- Aziz o'z vazifalarini lokal nusxada tartibga keltirdi (ikkitasini tuzatdi, bittasini qo'shdi). Shu o'zgarishlarni prod'ga olib o'tish kerak — prod'dagi boshqa foydalanuvchilar ma'lumotiga tegmasdan.
- Kecha kimdir bitta foydalanuvchining vazifalarini adashib o'chirdi. Zaxirani alohida bazaga tiklab, faqat o'sha qatorlarni qaytarish kerak.
- Dasturchi prod'dagi xatoni takrorlash uchun staging'ga real ko'rinishdagi ma'lumot olmoqchi — lekin haqiqiy emaillarsiz.
Uchala holatda ham yondashuv bitta: kerakli qatorlarni aniq so'rov bilan olamiz va maqsadga bitta tranzaksiyada yozamiz. Kasalxonadagi jarrohga o'xshab: butun tanani almashtirmaydi, faqat kerakli joyni ochadi, ishni qiladi va yopadi — bemorning qolgan qismi o'z holicha ishlayveradi.
Diqqat: Kanon tajribasi (
lokalvaprodbazalari, holat 11 nusxalari) PostgreSQL 18.6 konteynerida, faylni esa Windows'dagi psql 17.6 chiqargan. SQL misollarni biz o'z PostgreSQL 17.6 klasterimizda holat 11 bazasida ishga tushirdik. CRLF xatosi PG 16 va 18 da — kanon, PG 17 da — biz.
2. Chiqarish: \copy va COPY
2.1 Ikkisining farqi
COPY, batch va cursor darsida COPY ning tezligini ko'rgan edik. Uning ikki ko'rinishi bor, farqi — fayl qayerda yoziladi:
| Buyruq | Fayl qayerda | Kim ruxsat beradi |
|---|---|---|
COPY … TO '/yo'l' |
server mashinasida | superuser yoki pg_write_server_files roli |
\copy … TO 'fayl' |
sizning kompyuteringizda (psql) | oddiy SELECT huquqi yetarli |
COPY … TO STDOUT |
psql oqimiga — siz uni faylga yo'naltirasiz | oddiy SELECT huquqi |
\copy — psql meta-buyrug'i: psql o'zi COPY … TO STDOUT yuboradi va kelgan ma'lumotni sizning faylingizga yozadi. Server sizning diskingizni ko'rmaydi — shuning uchun COPY … TO 'C:/…' Docker'dagi serverda ishlamaydi, \copy esa ishlaydi.
2.2 Faqat kerakli qatorlar
COPY ga jadval nomi emas, so'rov berish mumkin. Kanon Azizning (id 1) vazifalarini shunday chiqardi (ustunlar ro'yxati qisqartirildi):
S='SELECT id, egasi_id, matn, bajarildi, tartib'
S+=' FROM vazifalar WHERE egasi_id = 1 ORDER BY id'
psql -X -h 127.0.0.1 -p 5498 -U postgres -d lokal \
-c "\copy ($S) TO STDOUT" > vazifalar.tsvBir muhim detal: \copy butun buyruq bitta qatorda bo'lishi kerak — psql meta-buyruqni qator oxirigacha o'qiydi. Uzun so'rovni shell o'zgaruvchisiga yig'ish shuning uchun qulay.
Izohlar ham xuddi shunday, lekin faqat Azizning vazifalariga tegishlilari — JOIN bilan:
SELECT i.id, i.vazifa_id, i.muallif_id, i.matn, i.yaratilgan_vaqt
FROM izohlar i JOIN vazifalar v ON v.id = i.vazifa_id
WHERE v.egasi_id = 1 ORDER BY i.idKanon natijasi: vazifalar.tsv — 14 qator, izohlar.tsv — 6 qator. Format sukut bo'yicha matn (text): ustunlar tab bilan ajratilgan, NULL — \N.
Tekshirib ko'ring: Nega
vazifa_teglari(vazifa ↔ teg bog'lanishi) ko'chirilmadi?
Javob
Kanon sxemasida teglarni trigger o'zi boshqaradi: vazifa matnidagi #teg lardan teglar va vazifa_teglari ni yozadi (Triggerlar). Vazifa qatori ko'chirilganda trigger ishlaydi va bog'lanishlarni maqsad bazaning o'z teg id'lari bilan quradi. Qo'lda ko'chirsak, manba va maqsaddagi teg id'lari mos kelmasligi mumkin edi.
3. Jarrohlik tranzaksiyasi
3.1 Tuzilishi
Maqsad bazada (prod) Azizning eski vazifalarini yangilari bilan almashtiramiz:
BEGIN;
DELETE FROM vazifalar WHERE egasi_id = 1; -- izohlar CASCADE
COPY vazifalar (id, egasi_id, matn, …) FROM stdin;
COPY izohlar (id, vazifa_id, muallif_id, matn, …) FROM stdin;
-- sequence'larni surish, hisoblagichlarni tekshirish
COMMIT;Butun yo'l bitta rasmda — manbadan maqsadgacha:
flowchart TD
A["lokal: \copy (SELECT) TO STDOUT"] --> B["tr -d '\r'"]
B --> C[BEGIN]
C --> D["DELETE (bolalari CASCADE)"]
D --> E[COPY vazifalar]
E --> F[COPY izohlar]
F --> G["setval(GREATEST)"]
G --> H{xato bormi?}
H -->|yo'q| I[COMMIT]
H -->|ha| J[ROLLBACK]Diagrammada ikki muhim joy bor: ota jadval (vazifalar) bola jadvaldan (izohlar) oldin keladi, va oxirida — yo hammasi (COMMIT), yo hech narsa (ROLLBACK).
Nega bitta tranzaksiya: DELETE dan keyin, COPY dan oldin biror narsa yiqilsa (fayl buzuq, cheklov buzildi), ROLLBACK hammasini qaytaradi — Azizning vazifalari yo'qolib qolmaydi. O'rtadagi holatni boshqa foydalanuvchilar ham ko'rmaydi (Tranzaksiya asoslari).
Kanon prod'ida hayot davom etgan edi: yangi foydalanuvchi ro'yxatdan o'tgan va Dilnoza izoh yozgan. Jarrohlikdan keyin ikkalasi ham joyida qoldi: prod: foydalanuvchilar=9, aziz_vazifalari=14, izohlar=16, prod_izohi_bor=1, prodda@=1. To'liq --clean tiklashdan farqi aynan shu.
3.2 Tashqi kalit tartibi
Ota jadval birinchi, bola — keyin. Izoh vazifaga tashqi kalit (foreign key) bilan bog'langan: vazifasi hali yo'q izohni yozib bo'lmaydi. Biz tekshirdik — 60-vazifa hali yo'q:
COPY izohlar (id, vazifa_id, muallif_id, matn)
FROM stdin (FORMAT csv);
40,60,1,Bu izohning vazifasi hali ko'chirilmagan
\.Natija:
ERROR: insert or update on table "izohlar" violates foreign key constraint "izohlar_vazifa_id_fkey"
DETAIL: Key (vazifa_id)=(60) is not present in table "vazifalar".Tarjima: "izohlar ga yozish izohlar_vazifa_id_fkey tashqi kalitini buzadi: (vazifa_id)=(60) kaliti vazifalar da yo'q". Bizning sxemada tartib: foydalanuvchilar → vazifalar → izohlar (va vazifa_tarixi — FK'siz, trigger yozadi). O'chirishda esa teskari: ON DELETE CASCADE bo'lgani uchun vazifalar ni o'chirish izohlarni ham o'chiradi.
Bu misolda FORMAT csv ishlatdik — dars matnida tab belgisi ko'rinmaydi, vergul ko'rinadi. Haqiqiy faylda sukut matn formati ham, CSV ham ishlaydi; muhimi, chiqarish va yuklash bir xil formatda bo'lsin.
3.3 Identity ustuni: COPY id ni yozadi
vazifalar.id — GENERATED ALWAYS AS IDENTITY (Primary key tanlovi). Oddiy INSERT unga qiymat berishga ruxsat bermaydi:
INSERT INTO vazifalar (id, egasi_id, matn)
VALUES (49, 1, 'Lokal''da qo''shilgan vazifa');Natija:
ERROR: cannot insert a non-DEFAULT value into column "id"
DETAIL: Column "id" is an identity column defined as GENERATED ALWAYS.
HINT: Use OVERRIDING SYSTEM VALUE to override."id ustuniga sukutdan boshqa qiymat yozib bo'lmaydi; u GENERATED ALWAYS identity. Ustidan yozish uchun OVERRIDING SYSTEM VALUE ishlating". Lekin kanon topilmasi: COPY buni so'ramaydi — u id'ni to'g'ridan yozdi. Bu jarrohlik uchun qulay (manba id'lari saqlanadi), lekin keyingi tuzoqni ochadi.
4. Sequence tuzog'i
4.1 Takrorlaymiz
Identity ustunining ortida sequence turadi: u "keyingi id nechchi" ni eslab turadi. COPY id'ni o'zi yozganda sequence buni bilmaydi. Vaqt bo'yicha nima bo'lishini avval jadvalda ko'ring:
| Qadam | Jarrohlik (siz) | Prod'dagi ilova | Natija |
|---|---|---|---|
| 1 | COPY id 49 ni yozdi |
— | max id 49, sequence 48 |
| 2 | COMMIT (setval'siz) |
— | hammasi "joyida" |
| 3 | — | yangi vazifa qo'shadi | sequence 49 ni beradi |
| 4 | — | — | duplicate key (id)=(49) |
Xato siz emas, boshqa odam ishlayotganda chiqadi. Lokal'da qo'shilgan vazifa 49-raqamni oldi, prod sequence'i esa hali 48 da. Tuzatilgan ikki vazifa (28, 38) va yangi 49-vazifani ko'chiramiz, keyin prod'da kimdir yangi vazifa qo'shadi:
BEGIN;
DELETE FROM vazifalar WHERE id IN (28, 38);
COPY vazifalar (id, egasi_id, matn, tartib) FROM stdin (FORMAT csv);
28,1,Elektr to'lovini Click orqali qilish #to'lov #uy,10
38,1,Velosiped zanjirini moylash #ta'mir #sport,12
49,1,Lokal'da qo'shilgan vazifa #kochirish,14
\.
SELECT max(id) AS max_id,
(SELECT last_value FROM vazifalar_id_seq) AS sequence
FROM vazifalar;
INSERT INTO vazifalar (egasi_id, matn)
VALUES (2, 'Prod''da yangi vazifa');
ROLLBACK;Natija — max_id va sequence ga qarang:
BEGIN
DELETE 2
COPY 3
max_id | sequence
--------+----------
49 | 48
(1 row)
ERROR: duplicate key value violates unique constraint "vazifalar_pkey"
DETAIL: Key (id)=(49) already exists.
ROLLBACKSequence 49 ni berdi — u esa allaqachon band. Eng xavflisi: bu xato jarrohlik paytida emas, keyinroq, butunlay boshqa foydalanuvchi vazifa qo'shganda chiqadi. Kanonda ham aynan shunday bo'ldi.
4.2 To'g'ri tartib: setval(GREATEST(…))
COMMIT'dan oldin sequence'ni eng katta id'ga suramiz:
BEGIN;
DELETE FROM vazifalar WHERE id IN (28, 38);
COPY vazifalar (id, egasi_id, matn, tartib) FROM stdin (FORMAT csv);
28,1,Elektr to'lovini Click orqali qilish #to'lov #uy,10
38,1,Velosiped zanjirini moylash #ta'mir #sport,12
49,1,Lokal'da qo'shilgan vazifa #kochirish,14
\.
SELECT setval('vazifalar_id_seq', GREATEST(
(SELECT max(id) FROM vazifalar),
(SELECT last_value FROM vazifalar_id_seq)));
COMMIT;Natija:
BEGIN
DELETE 2
COPY 3
setval
--------
49
(1 row)
COMMITNega GREATEST, oddiy max(id) emas? Prod'da sequence ko'chirilgan id'lardan oldinda bo'lishi ham mumkin: u yerda ko'proq yozuv qo'shilgan. max(id) bilan sequence'ni orqaga surib qo'ysak, keyingi yozuv yana to'qnashadi. GREATEST ikkalasining kattasini oladi — sequence hech qachon orqaga ketmaydi.
4.3 Trigger'lar ishladi
Ko'chirishdan keyin tekshiramiz: teglar qayta qurildimi va keyingi id nechchi?
SELECT v.id, v.tartib, string_agg(t.nom, ' ' ORDER BY t.nom) AS teglar
FROM vazifalar v
JOIN vazifa_teglari vt ON vt.vazifa_id = v.id
JOIN teglar t ON t.id = vt.teg_id
WHERE v.id IN (28, 38, 49)
GROUP BY v.id, v.tartib
ORDER BY v.id;
INSERT INTO vazifalar (egasi_id, matn)
VALUES (2, 'Prod''da yangi vazifa')
RETURNING id;Natija:
id | tartib | teglar
----+--------+----------------
28 | 10 | #to'lov #uy
38 | 12 | #sport #ta'mir
49 | 14 | #kochirish
(3 rows)
id
----
50
(1 row)
INSERT 0 1COPY qatorma-qator trigger'larni ishga tushiradi: yangi #sport va #kochirish teglari prod'da o'zi yaratildi. Kanonda bundan tashqari tarixga 31 yozuv tushdi (o'chirish va qo'shish) va izohlar_soni hisoblagichi ikki marta o'zgardi (CASCADE bilan kamaydi, COPY bilan oshdi). Shuning uchun kanon COMMIT'dan oldin hisoblagichni qayta hisobladi:
UPDATE vazifalar v
SET izohlar_soni = (SELECT count(*) FROM izohlar i
WHERE i.vazifa_id = v.id)
WHERE egasi_id = 1;Maslahat: Trigger'lar ko'chirishni sekinlashtiradi va tarixga "soxta" yozuvlar qo'shadi. Ularni
session_replication_role = replicabilan o'chirish mumkin (Triggerlar darsida 7 marta tezroq bo'lgan), lekin u holdatartibni qo'yadigan trigger ham ishlamaydi vanull value in column "tartib"xatosi chiqadi. Ko'chirishning kichik hajmida trigger'larni yoqiq qoldirish xavfsizroq.
Tekshirib ko'ring: Jarrohlikni
COPY izohlardan keyinsetval('vazifalar_id_seq', …)siz COMMIT qildingiz. Bugun hech narsa buzilmadi. Qachon buziladi?
Javob
Prod'da yangi vazifa qo'shilib, sequence ko'chirilgan eng katta id'ga yetganda. Agar ko'chirilgan id 49 va sequence 48 bo'lsa — darhol keyingi qo'shishda. Agar ko'chirilgan id 1 000 bo'lsa — 952 ta yozuvdan keyin, ehtimol bir haftadan so'ng, va hech kim buni jarrohlik bilan bog'lamaydi.
5. CRLF tuzog'i
5.1 Nima bo'ldi
Kanon faylni Windows'dagi psql bilan chiqardi. Natija: vazifalar.tsv ning 14 qatoridan 14 tasining oxirida CR (\r) bor edi. Windows matn fayllarida qator oxiri ikki belgi — \r\n (CRLF), Linux'da bitta — \n (LF).
Endi bu fayl Linux'dagi serverga (COPY … FROM stdin) beriladi. Kanon ikki holatni sinadi: (c1) hamma qator CRLF, oxiridagi \. esa LF; (c2) birinchi qator LF, ikkinchisi CRLF. Biz uchinchi versiyani — PostgreSQL 17.6 ni qo'shdik (psql -f fayl bilan):
| Holat | PG 16 (kanon) | PG 17.6 (biz) | PG 18.6 (kanon) |
|---|---|---|---|
| c1: hammasi CRLF | xato | xato | COPY 2 |
| c2: aralash | xato | xato | xato |
tr -d '\r' dan keyin |
COPY 2 |
— | COPY 2 |
c1 dagi xato:
ERROR: end-of-copy marker does not match previous newline style
CONTEXT: COPY y, line 3"Ma'lumot oxiri belgisi (\.) oldingi qatorlarning yangi qator uslubiga mos emas". c2 dagi xato:
ERROR: literal carriage return found in data
HINT: Use "\r" to represent carriage return."Ma'lumot ichida haqiqiy CR belgisi topildi. CR ni \r deb yozing". Postgres CRLF'ni faqat hamma qator bir xil bo'lsa qabul qiladi; aralash faylda CR ma'lumotning bir qismi bo'lib qoladi.
5.2 Versiyaga bog'liq xabar, bitta yechim
Diqqat qiling: PG 18 c1 ni xatosiz qabul qildi, 16 va 17 — yo'q. Agar siz lokal'da 18 da sinab, serverda 16 bo'lsa, "lokal'da ishladi" degan tuzoqqa tushasiz. Yechim versiyadan qat'i nazar bitta — faylni yuborishdan oldin CR'ni olib tashlash:
tr -d '\r' < vazifalar.tsv > vazifalar-lf.tsvBir qiziq kuzatuv (biz ishga tushirdik, Windows 11): Windows'dagi psql faylni -f fayl bilan o'qiganda c1 xatosi chiqdi, psql -f - < fayl (stdin) bilan esa chiqmadi — Windows'da stdin matn rejimida o'qilib, CR olib tashlangan. Ya'ni bir xil fayl, bir xil server — o'qish usuliga qarab har xil natija. Shuning uchun natijaga ishonmang, faylni tozalang.
Tekshirib ko'ring: Fayl Windows'da, server — Linux'da, ikkalasida ham PostgreSQL 18. c1 holati xatosiz o'tdi. Tozalash kerakmi?
Javob
Ha. Ertaga fayl aralash bo'lib qolishi mumkin (masalan bitta qator qo'lda tahrirlansa) — c2 xatosi 18 da ham chiqadi. Server 16 ga yoki 17 ga tiklansa — c1 ham yiqiladi. tr -d '\r' arzon va har versiyada bir xil ishlaydi.
6. Prod → staging: anonimlashtirish
6.1 Nega
Teskari yo'nalish ham bor: dasturchi prod'dagi xatoni takrorlash uchun staging yoki lokal bazaga haqiqiy ko'rinishdagi ma'lumot oladi. Lekin prod'dagi email, ism, telefon — shaxsiy ma'lumot. Ular dasturchi noutbukiga tushishi, test xatlariga ketib qolishi yoki loglarda chiqishi mumkin. O'zbekistonda shaxsiy ma'lumotlar haqidagi qonun (O'RQ-547; Analitika: foydalanuvchi xatti-harakatini o'lchash darsida tanishgan edik) shuni talab qiladi: kerakdan ortiq shaxsiy ma'lumot olmaslik.
6.2 So'rovda almashtirish
Anonimlashtirish (anonymization) — shaxsiy maydonlarni chiqarish paytida soxta qiymat bilan almashtirish. Fayl hech qachon haqiqiy emailni ko'rmaydi:
SELECT id,
'foydalanuvchi' || id || '@example.invalid' AS email,
'Foydalanuvchi ' || id AS ism
FROM foydalanuvchilar
ORDER BY id
LIMIT 3;Natija:
id | email | ism
----+--------------------------------+-----------------
1 | foydalanuvchi1@example.invalid | Foydalanuvchi 1
2 | foydalanuvchi2@example.invalid | Foydalanuvchi 2
3 | foydalanuvchi3@example.invalid | Foydalanuvchi 3
(3 rows)id saqlanadi — vazifalar va izohlar bilan bog'lanish buzilmaydi. .invalid domeni — standart bo'yicha hech qachon mavjud bo'lmaydigan zaxiralangan nom: test xati adashib yuborilsa ham hech kimga yetmaydi. Email noyob bo'lishi shart — id qo'shilgani shuning uchun.
Kanon bundan tashqari md5(email) ni ham chiqardi — "bir xil email bir xil hash" bo'lishi takrorlanuvchilarni topishda kerak bo'lsa. Lekin ehtiyot bo'ling: oddiy hash'ni lug'at bilan ochish mumkin (ma'lum emaillar ro'yxatini hash qilib solishtirish). Bu to'liq anonimlik emas, psevdonimlashtirish (pseudonymization).
6.3 Nimani yana unutmang
- Vazifa va izoh matnida ham shaxsiy narsa bo'lishi mumkin ("Onamga dori olib borish", telefon raqami). Ularni ham almashtirish yoki umuman olmaslik kerakmi — har loyihada alohida qaror.
vazifa_tarixi.eski/yangi(JSON) — eski matnlar nusxasi; anonimlashtirilmagan tarix hamma ishni bekor qiladi.- Parol hash'lari, tokenlar — staging'ga hech qachon.
7. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
violates foreign key constraint |
bola jadval otadan oldin | ota → bola tartibi |
keyinroq duplicate key … (id) |
sequence surilmagan | setval(GREATEST(max, last_value)) |
end-of-copy marker does not match |
Windows CRLF, PG ≤ 17 | tr -d '\r' |
literal carriage return found |
aralash LF/CRLF | tr -d '\r' |
\copy sintaksis xatosi |
buyruq ikki qatorga bo'lingan | bitta qator, shell o'zgaruvchi |
izohlar_soni noto'g'ri |
CASCADE va COPY trigger'lari | COMMIT'dan oldin qayta hisoblash |
8. Mashqlar
Mashqlar kurs/mashqlar/27/15-qisman/ da. 2-mashq holat 11 bazasida (biz ishga tushirdik, PostgreSQL 17.6), 3-mashq Node 24 da tekshirilgan.
1-mashq (oson): tartib
Azizning bitta vazifasini izohlari bilan prod'ga ko'chiryapsiz. Bo'sh joylarni to'ldiring:
- Birinchi
COPYqaysi jadvalga — - Ikkinchi
COPY— vazifa_teglarini kim yozadi —- Sequence'ni surish funksiyasi —
- Windows faylidagi CR'ni olib tashlash buyrug'i —
Yechim
- vazifalar, keyin izohlar — izoh vazifaga tashqi kalit bilan bog'langan, ota birinchi.
- trigger — matndagi
#teglardan. - setval —
GREATESTbilan, orqaga surmaslik uchun. - tr —
tr -d '\r'.
2-mashq (o'rta): izohni ko'chirish
Aziz lokal'da 1-vazifasiga izoh yozdi, u yerda u 40-id ni oldi. Prod'da izohlar sequence'i 15 da. Bitta tranzaksiyada: izohni COPY … FROM stdin (FORMAT csv) bilan yozing (id, vazifa_id, muallif_id, matn), sequence'ni suring va COMMIT qiling. Keyin 1-vazifaning izohlar_soni ni o'qing va prod'da yangi izoh qo'shib, uning id'si 41 ekanini tekshiring.
Yechim
BEGIN;
COPY izohlar (id, vazifa_id, muallif_id, matn)
FROM stdin (FORMAT csv);
40,1,1,Lokal'da yozilgan izoh: 27-qismga o'tdim
\.
SELECT setval('izohlar_id_seq', GREATEST(
(SELECT max(id) FROM izohlar),
(SELECT last_value FROM izohlar_id_seq)));
COMMIT;
SELECT izohlar_soni FROM vazifalar WHERE id = 1;
INSERT INTO izohlar (vazifa_id, muallif_id, matn)
VALUES (1, 2, 'Prod''dagi yangi izoh')
RETURNING id;Natija:
BEGIN
COPY 1
setval
--------
40
(1 row)
COMMIT
izohlar_soni
--------------
4
(1 row)
id
----
41
(1 row)
INSERT 0 1izohlar_soni 3 dan 4 ga o'zi o'sdi — COPY izohlar trigger'ini ham ishga tushirdi. setval 40 ni qaytardi, shuning uchun keyingi izoh 41 ni oldi. setval siz yangi izoh 16 ni olardi va hech narsa buzilmasdi — to 40 gacha. Aynan shu kechikkan xato eng xavflisi.
3-mashq (qiyin): qator oxirlarini tekshirish
qatorOxirlari(matn) funksiyasini yozing: u matndagi qatorlarni sanab, { lf, crlf, holat } qaytarsin. holat — "toza" (faqat LF), "crlf" (faqat CRLF) yoki "aralash". Oxirgi qator \n siz tugasa, uni sanamang. Keyin tozala(matn) — hamma \r ni olib tashlaydigan funksiya.
Ishora: matn.split("\n") — har bo'lak (oxirgisidan tashqari) bitta qator; bo'lak \r bilan tugasa — CRLF. Satr oxirini endsWith("\r") bilan tekshiring (Matn ichida qidirish).
Yechim
function qatorOxirlari(matn) {
const bolaklar = matn.split("\n").slice(0, -1);
const crlf = bolaklar.filter((q) => q.endsWith("\r")).length;
const lf = bolaklar.length - crlf;
let holat = "toza";
if (crlf > 0) holat = lf > 0 ? "aralash" : "crlf";
return { lf, crlf, holat };
}
function tozala(matn) {
return matn.replaceAll("\r", "");
}
const c1 = "1\tbir\r\n2\tikki\r\n";
const c2 = "1\tbir\n2\tikki\r\n";
console.log(qatorOxirlari(c1));
console.log(qatorOxirlari(c2));
console.log(qatorOxirlari(tozala(c2)));Konsolda:
{ lf: 0, crlf: 2, holat: 'crlf' }
{ lf: 1, crlf: 1, holat: 'aralash' }
{ lf: 2, crlf: 0, holat: 'toza' }c1 va c2 — kanondagi ikki holatning ma'lumot qismi. slice(0, -1) — oxirgi \n dan keyingi bo'sh bo'lakni tashlaydi. Bunday tekshiruvni skriptga qo'yib, holat !== "toza" bo'lsa ko'chirishni to'xtatish mumkin.
9. Loyiha qadami: kanon tajribasi
Bu darsda vazifalar-api kodi o'zgarmaydi va commit yo'q: qisman ko'chirish — ilovaning emas, bazani boshqaradigan odamning ishi, u bir martalik skript sifatida bajariladi. Kanon tajribasining yakuni:
lokalvaprod— holat 11 nusxalari; prod'da yangi foydalanuvchi va izoh paydo bo'lgan.- Eksport — Windows psql 17 bilan, 14 + 6 qator, hammasi CRLF bilan.
- Jarrohlik — bitta tranzaksiyada
DELETE(13 qator, izohlari CASCADE), ikkiCOPY, ikkisetval,izohlar_soniqayta hisoblandi, COMMIT. - Natija — Azizning 2 ta tuzatilgan va 1 ta yangi vazifasi prod'da, prod'ning yangi foydalanuvchisi va izohi joyida, keyingi
INSERTid 50 ni oldi.
Shu ketma-ketlikni o'z kanon bazangizda takrorlang: lokal va prod ni CREATE DATABASE … TEMPLATE vazifalar bilan yarating, lokal da Azizning vazifalaridan birini o'zgartiring va uni darsdagi tartib bilan prod'ga olib o'ting.
10. Real ishda
- "Mijoz kecha vazifalarini o'chirib yubordi, qaytaring" — eng ko'p uchraydigan qo'llab-quvvatlash so'rovi. To'g'ri javob: zaxirani alohida bazaga tiklash + jarrohlik, butun bazani emas.
- Staging'ni prod'dan to'ldirish — anonimlashtiruvchi skript bilan; ko'p kompaniyalarda bu qoida yozma siyosat.
- Windows'da ishlab, Linux serverga ma'lumot yuboradigan har dasturchi CRLF bilan bir marta to'qnashadi.
- Intervyuda: "Bitta foydalanuvchi ma'lumotini prod'dan qanday tiklaysiz?", "Identity ustuniga qiymat yozsangiz, sequence bilan nima bo'ladi?"
Xulosa
- Butun bazani emas, kerakli qatorlarni:
\copy (SELECT …) TO STDOUT→ bitta tranzaksiyadaDELETE+COPY+COMMIT. - Ota jadval birinchi; trigger boshqaradigan jadvallarni (teglar) ko'chirmang — trigger o'zi quradi.
COPYidentity id'ni yozadi, sequence esa buni bilmaydi —setval(GREATEST(…)), aks holda xato keyinroq chiqadi.- CRLF: PG 16–17 rad etadi, 18 qisman qabul qiladi — har doim
tr -d '\r'. - Prod → staging — shaxsiy maydonlar chiqarish paytida almashtiriladi; hash — psevdonim, anonim emas.
Keyingi dars: Monitoring va favqulodda vaziyatlar — baza "qotib qoldi": kim kimni qulflagan, so'rovni qanday bekor qilish va ulanishni qanday uzish.
Manbalar
- PostgreSQL 18 hujjati —
COPY(matn va CSV formati,\., qator oxirlari): https://www.postgresql.org/docs/18/sql-copy.html - psql —
\copy: https://www.postgresql.org/docs/18/app-psql.html - Sequence funksiyalari (
setval): https://www.postgresql.org/docs/18/functions-sequence.html CREATE TABLE— identity ustunlari vaOVERRIDING SYSTEM VALUE: https://www.postgresql.org/docs/18/sql-createtable.html- RFC 2606 —
.invalidzaxiralangan domeni: https://www.rfc-editor.org/rfc/rfc2606 - O'qilgan sana — 2026-10-25. Kanon o'lchovi (IlmHamroh, 2026-10): eksport, CRLF soni, jarrohlik, sequence, natija; CRLF PG 16 va 18 da; PostgreSQL 18.6. Biz ishga tushirdik (PostgreSQL 17.6, holat 11): FK, identity, sequence va
setvalmisollari, trigger natijasi, anonimlashtirish, CRLF PG 17 da, 2–3-mashqlar.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!