PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Ringkas atau beri nomor ulang ID untuk semua tabel, dan setel ulang urutan ke maks(id)?

Pertanyaannya sudah lama, tetapi kami mendapat pertanyaan baru dari pengguna yang putus asa di dba.SE setelah mencoba menerapkan apa yang disarankan di sini. Temukan jawaban dengan detail dan penjelasan lebih lanjut di sana :

jawaban yang diterima saat ini untuk sebagian besar kasus akan gagal .

  • Biasanya, Anda memiliki PRIMARY KEY atau UNIQUE batasan pada id kolom, yang NOT DEFERRABLE secara default. (OP menyebutkan references and constraints .) Batasan tersebut diperiksa setelah setiap baris, sehingga kemungkinan besar Anda mendapatkan pelanggaran unik kesalahan mencoba. Detail:

  • Biasanya, seseorang ingin mempertahankan urutan baris asli sambil menutup celah. Tetapi urutan pembaruan baris adalah sewenang-wenang , mengarah ke angka arbitrer. Contoh yang didemonstrasikan tampaknya mempertahankan urutan aslinya karena penyimpanan fisik masih sesuai dengan urutan yang diinginkan (baris dimasukkan dalam urutan yang diinginkan sesaat sebelumnya), yang hampir tidak pernah terjadi dalam aplikasi dunia nyata dan sama sekali tidak dapat diandalkan.

Masalahnya lebih rumit daripada yang terlihat pada awalnya. Satu solusi (antara lain) jika Anda mampu menghapus batasan PK / UNIK (dan batasan FK terkait) untuk sementara:

BEGIN;

LOCK tbl;

-- remove all FK constraints to the column

ALTER TABLE tbl DROP CONSTRAINT tbl_pkey;  -- remove PK

-- for the simple case without FK references - or see below:    
UPDATE tbl t  -- intermediate unique violations are ignored now
SET    id = t1.new_id
FROM  (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM tbl) t1
WHERE  t.id = t1.id;

-- Update referencing value in FK columns at the same time (if any)

SELECT setval('tbl_id_seq', max(id)) FROM tbl;  -- reset sequence

ALTER TABLE tbl ADD CONSTRAINT tbl_pkey PRIMARY KEY(id); -- add PK back

-- add all FK constraints to the column back

COMMIT;

Ini juga banyak lebih cepat untuk tabel besar, karena memeriksa batasan PK (dan FK) untuk setiap baris lebih mahal daripada menghapus batasan dan menambahkannya kembali.

Jika ada kolom FK di tabel lain yang merujuk ke tbl.id , gunakan CTE pengubah data untuk memperbarui semuanya.

Contoh untuk tabel fk_tbl dan kolom FK fk_id :

WITH u1 AS (
   UPDATE tbl t
   SET    id = t1.new_id
   FROM  (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM tbl) t1
   WHERE  t.id = t1.id
   RETURNING t.id, t1.new_id  -- return old and new ID
   )
UPDATE fk_tbl f
SET    fk_id = u1.new_id      -- set to new ID
FROM   u1
WHERE  f.fk_id = u1.id;       -- match on old ID

Selengkapnya di jawaban yang dirujuk di dba.SE .



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara menjalankan banyak kueri menggunakan perintah psql dari bash shell?

  2. Docker membuat layanan postgresql - tidak dapat membuat pengguna dan basis data selama pembuatan?

  3. sesuaikan pager di psql

  4. Informasi zona waktu apa yang disimpan PostgreSQL?

  5. Mengapa tidak dapat membuat tabel partisi?