UPSERT — INSERT ON CONFLICT DO UPDATE / DO NOTHING
Foydalanuvchi har kuni tizimga kiradi. Bugungi kirish statistikasini saqlash kerak. Qoida oddiy:
- Bugun birinchi marta kirsa — yangi qator qo'sh
- Bugun allaqachon kirgan bo'lsa — kirish sonini oshir
Buni oddiy INSERT bilan qilsangiz:
INSERT INTO statistika (foydalanuvchi_id, sana, kirish_soni)
VALUES (1, '2024-03-15', 1);
-- Ikkinchi marta:
-- ERROR: duplicate key value violates unique constraint
INSERT xato beradi — bu foydalanuvchining bugungi yozuvi allaqachon bor. Yechim uchun avval SELECT, keyin shart bo'yicha INSERT yoki UPDATE yozish — noqulay va ikki so'rov. UPSERT ikkalasini bitta so'rovda bajaradi.
UPSERT nima?
UPSERT — "UPDATE or INSERT" ning qisqartmasi. Yozuv bo'lmasa — qo'shadi, bo'lsa — yangilaydi.
Hayotiy o'xshatma
Telefon daftari. Yangi kontakt qo'shmoqchisiz. Agar bu raqam allaqachon bor bo'lsa — ismini yangilaysiz. Yo'q bo'lsa — yangi qator qo'shasiz. Ikki holat, bitta harakat.
ON CONFLICT DO UPDATE
INSERT INTO statistika (foydalanuvchi_id, sana, kirish_soni)
VALUES (1, '2024-03-15', 1)
ON CONFLICT (foydalanuvchi_id, sana) -- ← bu juft allaqachon bormi?
DO UPDATE SET
kirish_soni = statistika.kirish_soni + 1; -- ← bor bo'lsa — yangilash
EXCLUDED — kiritilmoqchi bo'lgan yangi qiymatlar. statistika — mavjud jadval:
INSERT INTO foydalanuvchilar (id, ism, email)
VALUES (1, 'Alibek', 'alibek@mail.com')
ON CONFLICT (id)
DO UPDATE SET
ism = EXCLUDED.ism, -- ← yangi kelgan ism
email = EXCLUDED.email; -- ← yangi kelgan email
To'liqroq misol — mahsulot narxlarini sinxronlashtirish:
INSERT INTO mahsulotlar (kod, nom, narx)
VALUES
('PRD001', 'Noutbuk', 8500000),
('PRD002', 'Telefon', 3200000),
('PRD003', 'Quloqchin', 450000)
ON CONFLICT (kod)
DO UPDATE SET
nom = EXCLUDED.nom,
narx = EXCLUDED.narx;
-- Bor bo'lsa — nom va narx yangilanadi
-- Yo'q bo'lsa — yangi qator qo'shiladi
ON CONFLICT DO NOTHING
To'qnashuv bo'lsa — e'tibor bermay o'tib ketadi, xato bermaydi:
INSERT INTO teglar (nom)
VALUES ('javascript')
ON CONFLICT (nom) DO NOTHING;
-- 'javascript' allaqachon bo'lsa — hech narsa bo'lmaydi, xato yo'q
Qaysi holda foydali? Ko'p ma'lumot import qilayotganda — ba'zilari allaqachon bor, ba'zilari yangi. Bor bo'lganlarini o'tkazib, yangilarini qo'shish kerak:
INSERT INTO shaharslar (kod, nom)
SELECT kod, nom FROM vaqtinchalik_jadval
ON CONFLICT (kod) DO NOTHING;
ON CONFLICT — qaysi constraint ga
ON CONFLICT qaysi ustun yoki constraint da to'qnashuv bo'lishini aniq ko'rsatishi kerak:
-- Ustun nomi bilan
ON CONFLICT (email)
-- Bir nechta ustun (composite unique)
ON CONFLICT (foydalanuvchi_id, sana)
-- Constraint nomi bilan
ON CONFLICT ON CONSTRAINT foydalanuvchilar_email_key
Tez-tez uchraydigan xatolar
Constraint ko'rsatilmagan ustun
ON CONFLICT faqat UNIQUE yoki PRIMARY KEY bo'lgan ustunlar uchun ishlaydi:
-- ❌ — 'ism' ustunida UNIQUE yo'q
ON CONFLICT (ism) DO UPDATE SET ...
-- ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
-- ✅ — avval UNIQUE qo'shing
ALTER TABLE foydalanuvchilar ADD CONSTRAINT unique_ism UNIQUE (ism);
DO UPDATE da jadval nomini unutish
-- ❌
DO UPDATE SET kirish_soni = kirish_soni + 1
-- Bu qaysi kirish_soni — yangi keladiganmi yoki mavjudmi? Noaniq.
-- ✅ — jadval nomi bilan aniq ko'rsating
DO UPDATE SET kirish_soni = statistika.kirish_soni + 1
Xulosa
UPSERT — bitta so'rovda: yozuv yo'q bo'lsa qo'shadi, bor bo'lsa yangilaydi.
INSERT INTO jadval (...)
VALUES (...)
ON CONFLICT (ustun)
DO UPDATE SET ustun = EXCLUDED.ustun; -- yangilash
-- yoki
DO NOTHING; -- e'tibor bermay o'tish
EXCLUDED — kiritilmoqchi bo'lgan yangi qiymatlar. Mavjud jadval qiymatlari esa jadval nomi orqali olinadi.
Keyingi dars
11-dars: Aggregate funksiyalar, GROUP BY, HAVING, FILTER