INSERT — bir va bir nechta qator, INSERT IGNORE, ON DUPLICATE KEY

~15 daq · MySQL · DML — Ma'lumot Boshqarish

Muammodan boshlaylik

Tuzilma tayyor — jadvallar bo'sh. Endi ularni ma'lumot bilan to'ldirish kerak: yangi mijoz ro'yxatdan o'tdi, yangi mahsulot keldi, buyurtma berildi. Bu ishni INSERT bajaradi.

Oddiy ko'rinadi, lekin real hayotda savollar paydo bo'ladi: 10 000 ta mahsulotni Excel dan qanday tez yuklash kerak? Mahsulot allaqachon bor bo'lsa — xato berish kerakmi yoki yangilash? Bu darsda shularga javob beramiz.


Asosiy sintaksis

INSERT INTO mijozlar (ism, email, telefon, shahar)
VALUES ('Dilshod Aliyev', 'dilshod@mail.uz', '+998901234567', 'Toshkent');
  • Ustunlar ro'yxati va qiymatlar ro'yxati bir xil tartibda
  • Matn va sanalar — bittalik tirnoqda '...'
  • Sonlar — tirnoqsiz
  • NULL — tirnoqsiz

Ko'rsatilmagan ustunlar DEFAULT qiymatini oladi (id — avtomatik, yaratilgan — hozirgi vaqt).

Ustunlarni har doim yozing

-- ❌ Ishlaydi, lekin xavfli
INSERT INTO toifalar VALUES (NULL, 'Planshetlar');

-- ✅
INSERT INTO toifalar (nom) VALUES ('Planshetlar');

Ustunlarsiz variant jadvaldagi barcha ustunlarni aniq tartibda kutadi. Ertaga jadvalga yangi ustun qo'shilsa — bu so'rov buziladi.


Bir nechta qator — bir so'rovda

INSERT INTO mahsulotlar (toifa_id, nom, narx, soni) VALUES
    (1, 'Xiaomi Redmi Note 13', 2900000, 20),
    (1, 'Google Pixel 8',       8500000, 3),
    (3, 'Zaryadlovchi 65W',     350000,  40);

Bu uchta alohida INSERT dan ancha tez: serverga bitta so'rov, bitta tranzaksiya, indekslar bir marta yangilanadi. 10 000 qatorni yuklashda farq — soniyalar va daqiqalar.

[!TIP] Juda ko'p qator bo'lsa — 500-1000 tadan bo'laklarga bo'ling. Bitta ulkan so'rov max_allowed_packet chegarasiga urilishi mumkin.


Yangi qatorning ID si

INSERT INTO buyurtmalar (mijoz_id) VALUES (2);
SELECT LAST_INSERT_ID();

LAST_INSERT_ID() — joriy ulanishda oxirgi yaratilgan AUTO_INCREMENT qiymati. Boshqa foydalanuvchilar bir vaqtda qator qo'shsa ham — sizga faqat o'zingiznikini qaytaradi. Shuning uchun xavfsiz.

Buyurtma va uning qatorlarini yaratish:

INSERT INTO buyurtmalar (mijoz_id) VALUES (2);
SET @bid = LAST_INSERT_ID();

INSERT INTO buyurtma_qatorlari (buyurtma_id, mahsulot_id, soni, narx) VALUES
    (@bid, 5, 1, 3100000),
    (@bid, 6, 2, 120000);

@bid — sessiya o'zgaruvchisi. Ilovada (PHP, Node) bu lastInsertId() yoki insertId orqali olinadi.


Boshqa jadvaldan nusxalash: INSERT ... SELECT

CREATE TABLE arxiv_buyurtmalar LIKE buyurtmalar;

INSERT INTO arxiv_buyurtmalar
SELECT * FROM buyurtmalar WHERE yaratilgan < '2026-01-01';

So'rov natijasi to'g'ridan-to'g'ri boshqa jadvalga yoziladi — ilovaga olib chiqmasdan.


Takrorlanish muammosi

email — UNIQUE. Mavjud email bilan qo'shsak:

INSERT INTO mijozlar (ism, email) VALUES ('Aziz', 'aziz@mail.uz');
-- ERROR 1062: Duplicate entry 'aziz@mail.uz' for key 'mijozlar.email'

Bu ko'pincha to'g'ri xatti-harakat. Lekin ba'zan boshqacha kerak bo'ladi. Uch variant bor.

1. INSERT IGNORE — jimgina o'tkazib yuborish

INSERT IGNORE INTO mijozlar (ism, email) VALUES
    ('Aziz', 'aziz@mail.uz'),        -- bor — o'tkazib yuboriladi
    ('Yangi', 'yangi@mail.uz');      -- yo'q — qo'shiladi

Xato o'rniga ogohlantirish. Import paytida "borlarini tashlab ket, yangilarini qo'sh" uchun qulay.

[!WARNING] IGNORE faqat dublikatni emas, boshqa xatolarni ham yutib yuboradi: noto'g'ri tur, NOT NULL buzilishi — qiymat jimgina "tuzatiladi". Ehtiyotkorlik bilan ishlating va SHOW WARNINGS; bilan tekshiring.

2. ON DUPLICATE KEY UPDATE — bor bo'lsa yangilash (upsert)

Ombor ma'lumoti har kuni yetkazib beruvchidan keladi. Mahsulot bor bo'lsa — narx va sonini yangilash, yo'q bo'lsa — qo'shish:

ALTER TABLE mahsulotlar ADD COLUMN sku VARCHAR(30) NULL UNIQUE;

INSERT INTO mahsulotlar (sku, nom, narx, soni)
VALUES ('APL-IP15', 'iPhone 15', 12300000, 10)
AS yangi
ON DUPLICATE KEY UPDATE
    narx = yangi.narx,
    soni = mahsulotlar.soni + yangi.soni;
  • sku bo'yicha mahsulot yo'q → yangi qator
  • Bor → narx yangilanadi, soni qo'shiladi (omborga yangi partiya keldi)
  • AS yangi — kiritilayotgan qiymatlarga nom (MySQL 8.0.19+)

Eski versiyalarda VALUES(narx) yozilardi — u eskirgan, lekin eski kodda ko'p uchraydi:

ON DUPLICATE KEY UPDATE narx = VALUES(narx);

Ko'rish hisoblagichi uchun klassik misol:

INSERT INTO sahifa_korishlari (sahifa, soni) VALUES ('/php', 1)
ON DUPLICATE KEY UPDATE soni = soni + 1;

Bitta so'rov — tekshirish ham, qo'shish ham, yangilash ham. Ikki foydalanuvchi bir vaqtda kirsa ham to'g'ri ishlaydi.

3. REPLACE — o'chirib, qaytadan qo'shish

REPLACE INTO mahsulotlar (sku, nom, narx, soni) VALUES ('APL-IP15', 'iPhone 15', 12300000, 10);

Dublikat bo'lsa — eski qatorni o'chiradi, keyin yangisini qo'shadi.

[!WARNING] REPLACE xavfli: eski qator o'chiriladi, shuning uchun yangi id beriladi, ko'rsatilmagan ustunlar DEFAULT ga qaytadi, va ON DELETE CASCADE bo'lsa — bog'liq qatorlar ham o'chadi. Deyarli har doim ON DUPLICATE KEY UPDATE yaxshiroq.


Fayldan yuklash

CSV fayldan million qatorni yuklashning eng tez yo'li:

LOAD DATA LOCAL INFILE '/yol/mahsulotlar.csv'
INTO TABLE mahsulotlar
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(sku, nom, narx, soni);

IGNORE 1 LINES — sarlavha qatorini tashlab ketish. Bu INSERT lardan o'nlab marta tez. (local_infile sozlamasi yoqilgan bo'lishi kerak.)


Nima uchun shunday?

Nima uchun SELECT qilib "bormi?" deb tekshirib, keyin INSERT yoki UPDATE qilish noto'g'ri?

So'rov A: SELECT ... WHERE sku='X'  → yo'q
So'rov B: SELECT ... WHERE sku='X'  → yo'q
So'rov A: INSERT sku='X'            → ✅
So'rov B: INSERT sku='X'            → ❌ Duplicate entry

Tekshirish va yozish orasida boshqa so'rov "suqilib kirishi" mumkin — bu race condition deyiladi. ON DUPLICATE KEY UPDATE esa tekshirish va yozishni bitta atomar amalda bajaradi — orasiga hech kim kira olmaydi.


Xulosa

Eslab qoling:

  • INSERT INTO t (ustunlar) VALUES (...) — ustunlarni doim yozing
  • Ko'p qator — bitta INSERT da, vergul bilan
  • LAST_INSERT_ID() — yangi qator id si, faqat sizning ulanishingizniki
  • INSERT ... SELECT — jadvaldan jadvalga
  • INSERT IGNORE — dublikatni o'tkazish (boshqa xatolarni ham yutadi!)
  • ON DUPLICATE KEY UPDATE — upsert; REPLACE dan xavfsizroq
  • LOAD DATA INFILE — katta CSV uchun

Keyingi dars

10-dars: SELECT — WHERE, AND, OR, NOT, BETWEEN, IN, LIKE, IS NULL