Selain apa yang disediakan @Craig (dan koreksi sebagian):
Efektif Postgres 9.4 , UNIQUE
, PRIMARY KEY
dan EXCLUDE
kendala diperiksa segera setelah setiap baris saat didefinisikan NOT DEFERRABLE
. Ini berbeda dari jenis NOT DEFERRABLE
kendala lainnya (saat ini hanya REFERENCES
(kunci asing)) yang diperiksa setelah setiap pernyataan . Kami mengerjakan semua ini berdasarkan pertanyaan terkait pada SO:
Hal ini tidak cukup untuk UNIQUE
(atau PRIMARY KEY
atau EXCLUDE
) kendala untuk DEFERRABLE
membuat kode disajikan dengan beberapa pernyataan kerja.
Dan Anda tidak dapat menggunakan ALTER TABLE ... ALTER CONSTRAINT
untuk tujuan ini. Per dokumentasi:
ALTER CONSTRAINT
Formulir ini mengubah atribut dari kendala yang sebelumnya dibuat. Saat ini hanya batasan kunci asing yang dapat diubah .
Penekanan berani saya. Gunakan sebaliknya:
ALTER TABLE t
DROP CONSTRAINT category_name_key
, ADD CONSTRAINT category_name_key UNIQUE(name) DEFERRABLE;
Lepaskan dan tambahkan kendala kembali dalam satu pernyataan sehingga tidak ada jendela waktu bagi siapa pun untuk menyelinap di baris yang menyinggung. Untuk tabel besar akan tergoda untuk melestarikan entah bagaimana indeks unik yang mendasarinya, karena itu mahal untuk menghapus dan membuatnya kembali. Sayangnya, itu sepertinya tidak mungkin dilakukan dengan alat standar (jika Anda memiliki solusi untuk itu, beri tahu kami!):
Untuk satu pernyataan membuat batasan ditangguhkan sudah cukup:
UPDATE category c
SET name = c_old.name
FROM category c_old
WHERE c.id IN (1,2)
AND c_old.id IN (1,2)
AND c.id <> c_old.id;
Permintaan dengan CTE juga adalah pernyataan tunggal :
WITH x AS (
UPDATE category SET name = 'phones' WHERE id = 1
)
UPDATE category SET name = 'tablets' WHERE id = 2;
Namun , untuk kode Anda dengan beberapa pernyataan, Anda (tambahan) harus benar-benar menunda kendala - atau mendefinisikannya sebagai salah INITIALLY DEFERRED
satu yang biasanya lebih mahal daripada yang di atas. Tetapi mungkin tidak mudah untuk mengemas semuanya menjadi satu pernyataan.
BEGIN;
SET CONSTRAINTS category_name_key DEFERRED;
UPDATE category SET name = 'phones' WHERE id = 1;
UPDATE category SET name = 'tablets' WHERE id = 2;
COMMIT;
Waspadai batasan sehubungan dengan FOREIGN KEY
kendala. Per dokumentasi:
Kolom yang direferensikan harus berupa kolom dari batasan kunci primer atau unik yang tidak dapat ditangguhkan dalam tabel yang direferensikan.
Jadi, Anda tidak dapat memiliki keduanya sekaligus.