Memperbaiki struktur tabel untuk menghindari `Kesalahan: nilai kunci duplikat melanggar kendala unik`

15

Saya punya tabel yang dibuat dengan cara ini:

--
-- Table: #__content
--
CREATE TABLE "jos_content" (
  "id" serial NOT NULL,
  "asset_id" bigint DEFAULT 0 NOT NULL,
   ...
  "xreference" varchar(50) DEFAULT '' NOT NULL,
  PRIMARY KEY ("id")
);

Kemudian beberapa baris dimasukkan menentukan id:

INSERT INTO "jos_content" VALUES (1,36,'About',...)

Pada suatu titik kemudian beberapa catatan dimasukkan tanpa id dan mereka gagal dengan kesalahan: Error: duplicate key value violates unique constraint.

Rupanya id dapat didefinisikan sebagai urutan:

masukkan deskripsi gambar di sini

Setiap sisipan yang gagal meningkatkan penunjuk dalam urutan hingga meningkat ke nilai yang tidak ada lagi dan kueri berhasil.

SELECT nextval('jos_content_id_seq'::regclass)

Apa yang salah dengan definisi tabel? Apa cara cerdas untuk memperbaikinya?

Valentin Despa
sumber
Di PostgreSQL, Anda tidak perlu mengutip nama kolom dan tabel jika semuanya huruf kecil.
Rodrigo

Jawaban:

19

Tidak ada yang salah dengan definisi tabel Anda.
(Kecuali saya akan menggunakan jos_content_idsesuatu atau bukan nama kolom non-deskriptif id.
Dan saya mungkin akan menggunakan textbukanvarchar(50) .

INSERTPernyataan Anda adalah masalahnya.

Dengan idkolom Anda didefinisikan sebagai serial, Anda tidak harus memasukkan nilai manual untuk id. Mereka mungkin bertabrakan dengan nilai berikutnya dari urutan terkait.

Berikan daftar eksplisit kolom target (yang hampir selalu merupakan ide bagus untuk INSERTpernyataan tetap ) dan abaikan kolom serial sepenuhnya.

INSERT INTO jos_content(asset_id, some_column, ...)
VALUES (36,'About',...);

Jika Anda membutuhkan nilai kolom yang dibuat secara otomatis segera, gunakan RETURNINGklausa :

INSERT ...
RETURNING id;  -- possibly more

Lebih detail dalam jawaban terkait ini di SO:

Jika Anda memiliki entri manual dalam serialkolom yang kekuatan konflik kemudian, mengatur urutan ke arus maksimum iduntuk memperbaiki ini sekali :

SELECT setval('jos_content_id_seq', max(id))
FROM   jos_content;

Di mana jos_content_id_seqnama default untuk urutan yang dimiliki oleh jos_content.id, yang sudah Anda temukan di kolom default. Tampaknya ada xhzt8_content_id_seqdalam kasus Anda;


Pembaruan: Masalah serupa muncul pada SO dan saya datang dengan solusi baru:

Erwin Brandstetter
sumber
Bukankah teks lebih lambat daripada varchar (50)?
Rodrigo
2
@Rodrigo: Tidak di Postgres. Ada tautan di atas untuk penjelasan lebih lanjut: dba.stackexchange.com/a/21496/3684 . Atau disini. dba.stackexchange.com/a/89433/3684
Erwin Brandstetter
Tes terakhir di sini < depesz.com/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text > meyakinkan saya bahwa varchar (n) lebih cepat untuk sebagian besar bidang tempat pembatasan ukurannya nyaman (orang-orang) nama, email, alamat, nama spesies, dll). Teks lebih cepat (atau sama) jika Anda tidak akan memeriksa panjangnya, tampaknya.
Rodrigo