Sửa cấu trúc bảng để tránh `Lỗi: giá trị khóa trùng lặp vi phạm ràng buộc duy nhất`


14

Tôi có một bảng được tạo theo cách này:

--
-- 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")
);

Sau đó, một số hàng được chèn chỉ định id:

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

Tại một thời điểm sau, một số bản ghi được chèn mà không có id và chúng không thành công với lỗi : Error: duplicate key value violates unique constraint.

Rõ ràng id đã được định nghĩa là một chuỗi:

nhập mô tả hình ảnh ở đây

Mỗi lần chèn không thành công sẽ tăng con trỏ trong chuỗi cho đến khi nó tăng lên một giá trị không còn tồn tại và các truy vấn thành công.

SELECT nextval('jos_content_id_seq'::regclass)

Điều gì là sai với định nghĩa bảng? Cách thông minh để khắc phục điều này là gì?


Trong PostgreSQL, bạn không cần trích dẫn tên cột và bảng nếu tất cả đều là chữ thường.
Rodrigo

Câu trả lời:


18

Không có gì sai với định nghĩa bảng của bạn.
(Ngoại trừ mũ tôi sẽ sử dụng jos_content_idhoặc một cái gì đó thay vì tên cột không mô tả id.
Và tôi có thể sẽ sử dụng textthay vìvarchar(50) .

INSERTTuyên bố của bạn là vấn đề.

Với idcột của bạn được xác định là serial, bạn không nên chèn giá trị thủ công cho id. Những người có thể va chạm với giá trị tiếp theo từ chuỗi liên kết.

Cung cấp một danh sách rõ ràng các cột mục tiêu (hầu như luôn luôn là một ý tưởng tốt cho các INSERTcâu lệnh được duy trì ) và bỏ qua các cột nối tiếp hoàn toàn.

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

Nếu bạn cần (các) giá trị của cột được tạo tự động ngay lập tức, hãy sử dụng RETURNINGmệnh đề :

INSERT ...
RETURNING id;  -- possibly more

Thêm chi tiết trong câu trả lời liên quan này trên SO:

Nếu bạn có các mục nhập thủ công trong serialcác cột có thể xung đột sau này, hãy đặt trình tự của bạn thành mức tối đa hiện tại idđể khắc phục điều này một lần :

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

Trong trường hợp jos_content_id_seqlà tên mặc định cho một chuỗi thuộc sở hữu của jos_content.id, mà bạn đã tìm thấy trong các cột mặc định. Có vẻ là xhzt8_content_id_seqtrong trường hợp của bạn;


Cập nhật: Một vấn đề tương tự xuất hiện trên SO và tôi đã đưa ra một giải pháp mới:


Không phải văn bản chậm hơn varchar (50)?
Rodrigo

2
@Rodrigo: Không có trong Postgres. Có một liên kết ở trên để giải thích thêm: dba.stackexchange.com/a/21496/3684 . Hoặc ở đây. dba.stackexchange.com/a/89433/3684
Erwin Brandstetter

Các bài kiểm tra cuối cùng ở đây < depesz.com/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text > thuyết phục tôi rằng varchar (n) là nhanh hơn đối với hầu hết các lĩnh vực nơi một hạn chế về kích thước rất thuận tiện (người tên, email, địa chỉ, tên loài, vv). Văn bản sẽ nhanh hơn (hoặc tương tự) nếu bạn không kiểm tra độ dài.
Rodrigo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.