Xoş gəldin, kütləvi məlumat yükləmələrinin ən dramatik ssenarilərinin mərkəzinə! Bu gün məlumat yüklənməsi zamanı yaranan səhvlərlə necə effektiv davranmaq lazım olduğunu ON CONFLICT konstruksiyası ilə öyrənəcəyik. Bu, sanki təyyarədə autopilot-u qoşmaq kimidir: nəsə səhv getsə belə, nə edəcəyini biləcəksən və fəlakətin qarşısını alacaqsan. Gəlin PostgreSQL-in fəndlərini araşdıraq!
Heç kim sürprizləri sevmir, xüsusən də məlumatlar yüklənməkdən imtina edəndə! Kütləvi yükləmə prosesində bir neçə tipik problemə rast gələ bilərsən:
- Məlumatların təkrarlanması. Məsələn, cədvəldə
UNIQUEməhdudiyyəti varsa, və sənin məlumat faylında bol-bol təkrarlar varsa. - Məhdudiyyətlərlə konfliktlər. Məsələn,
NOT NULLməhdudiyyəti olan sütuna boş dəyər yükləməyə çalış. Nəticə? Səhv. PostgreSQL belə hallarda həmişə ciddi olur. - Təkrarlanan əsas məlumat. Cədvəldə artıq sənin CSV faylındakı kimi eyni identifikatorlu məlumatlar ola bilər.
Gəlin baxaq, bu "gizli daşlardan" ON CONFLICT ilə necə yayınmaq olar.
Səhvlərin işlənməsi üçün ON CONFLICT-dən istifadə
ON CONFLICT konstruksiyasının sintaksisi konflikt zamanı (məsələn, UNIQUE və ya PRIMARY KEY məhdudiyyəti ilə) nə etmək lazım olduğunu göstərməyə imkan verir. PostgreSQL sənə ya mövcud məlumatı yeniləmək, ya da konfliktli sətri görməməzliyə vurmaq imkanı verir.
Budur, ON CONFLICT konstruksiyasının əsas sintaksisi:
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...)
ON CONFLICT (conflict_target)
DO UPDATE SET column1 = new_value1, column2 = new_value2;
Əgər sadəcə konflikti görməməzliyə vurmaq istəyirsənsə, DO UPDATE-i DO NOTHING ilə əvəz edə bilərsən.
Nümunə: konflikt zamanı məlumatların yenilənməsi
Tutaq ki, bizdə students adlı cədvəl var:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
age INT
);
İndi yeni məlumatlar yükləmək istəyirik, amma bəziləri artıq bazada var:
INSERT INTO students (id, name, age)
VALUES
(1, 'Peter', 22), -- Bu tələbə artıq var
(2, 'Anna', 20), -- Yeni tələbə
(3, 'Mal', 25) -- Yeni tələbə
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
age = EXCLUDED.age;
Bu nümunədə, əgər əlavə etmək istədiyimiz ID-li tələbə artıq varsa, onun məlumatları yenilənəcək:
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
age = EXCLUDED.age;
Burada EXCLUDED sehrli sözünə fikir ver. Bu, "sən əlavə etməyə çalışdığın, amma konfliktə görə istisna olunan dəyərlər" deməkdir.
Nəticə:
id = 1olan tələbənin məlumatları (ad və yaş) yenilənəcək.id = 2vəid = 3olan tələbələr cədvələ əlavə olunacaq.
Nümunə: konfliktlərin görməməzliyə vurulması
Əgər məlumatları yeniləmək istəmirsənsə və sadəcə konflikti yaradan sətrləri görməməzliyə vurmaq istəyirsənsə, DO NOTHING istifadə et:
INSERT INTO students (id, name, age)
VALUES
(1, 'Peter', 22), -- Bu tələbə artıq var
(2, 'Anna', 20), -- Yeni tələbə
(3, 'Mal', 25) -- Yeni tələbə
ON CONFLICT (id) DO NOTHING;
İndi konfliktli sətrlər sadəcə əlavə olunmayacaq, qalanlar isə rahatlıqla bazada yerləşəcək.
Səhvlərin log-lanması
Bəzən görməməzliyə vurmaq və ya yeniləmək kifayət etmir. Məsələn, konfliktləri sonradan analiz üçün qeyd etmək lazımdır. Bunun üçün xüsusi log cədvəli yarada bilərik:
CREATE TABLE conflict_log (
conflict_time TIMESTAMP DEFAULT NOW(),
id INT,
name TEXT,
age INT,
conflict_reason TEXT
);
Sonra log-lama ilə səhvlərin işlənməsini əlavə edirik:
INSERT INTO students (id, name, age)
VALUES
(1, 'Peter', 22),
(2, 'Anna', 20),
(3, 'Mal', 25)
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
age = EXCLUDED.age
RETURNING EXCLUDED.id, EXCLUDED.name, EXCLUDED.age
INTO conflict_log;
Bu sonuncu nümunə yalnız stored procedures içində işləyəcək. Bunun necə işlədiyini biz PL-SQL öyrənəndə biləcəksən. Bir az qabağa getdim, sadəcə məlumat yükləmə konfliktini həll etməyin başqa bir yolunu göstərmək istədim: bütün problemli sətrlərin log-lanması.
İndi konfliktlərin səbəblərini analiz edə bilərsən. Bu texnika xüsusilə mürəkkəb sistemlərdə faydalıdır, çünki kütləvi yükləmələr zamanı "izləri" saxlamaq vacibdir.
Praktik nümunə
Gəlin bütün bildiklərimizi bir sadə tapşırıqda birləşdirək. Təsəvvür et ki, səndə tələbələrin yenilənməsi üçün CSV faylı var və onu cədvələ yükləmək istəyirsən:
students_update.csv faylı
| id | name | age |
|---|---|---|
| 1 | Otto | 23 |
| 2 | Anna | 21 |
| 4 | Wally | 30 |
Məlumatların yüklənməsi və konfliktlərin işlənməsi
- Əvvəlcə
tmp_studentsadlı müvəqqəti cədvəl yaradırıq:
CREATE TEMP TABLE tmp_students (
id INTEGER,
name TEXT,
age INTEGER
);
- Fayldan məlumatları
\COPYilə yükləyirik:
\COPY tmp_students FROM 'students_update.csv' DELIMITER ',' CSV HEADER
- Müvəqqəti cədvəldən əsas cədvələ
INSERT ON CONFLICTilə məlumatları əlavə edirik:
INSERT INTO students (id, name, age)
SELECT id, name, age FROM tmp_students
ON CONFLICT (id) DO UPDATE
SET name = EXCLUDED.name,
age = EXCLUDED.age;
İndi bütün məlumatlar, o cümlədən yenilənmələr (id = 1 sətri), uğurla yükləndi.
Tipik səhvlər və onlardan necə yayınmaq olar
Səhvlər hətta ən təcrübəli proqramçılarda da olur, amma necə yayınmaq lazım olduğunu bilsən, saatlarla (bəlkə də günlərlə) əsəbini qoruyarsan.
UNIQUEməhdudiyyəti ilə konflikt.ON CONFLICT-də düzgün sahəni göstərdiyinə əmin ol. Məsələn, səhv açar (idəvəzinəemail) göstərsən, PostgreSQL sadəcə sorğunu "əlvida" deyəcək.EXCLUDED-un səhv istifadəsi. Bu alias yalnız cari sorğuda ötürülən dəyərlərə aiddir. Onu başqa kontekstlərdə istifadə etməyə çalışma.- Sütunların buraxılması.
SET-də göstərilən bütün sütunların cədvəldə olduğuna əmin ol. Məsələn,SET non_existing_column = 'value'əlavə etsən, səhv alacaqsan.
ON CONFLICT-dən istifadə PostgreSQL-də kütləvi məlumat yükləmələrini çevik və təhlükəsiz edir. Sən təkcə konfliktlərə görə sorğuların "uçub getməsinin" qarşısını almırsan, həm də məlumatlarının necə işlənəcəyinə tam nəzarət edirsən. İstifadəçilərin (və serverlərin!) sənə minnətdar olacaq.
GO TO FULL VERSION