Làm cách nào để thêm một cột có ràng buộc khóa ngoài vào bảng đã tồn tại?


11

Tôi có các bảng sau,

CREATE TABLE users (id int PRIMARY KEY);

-- already exists with data
CREATE TABLE message ();

Làm thế nào để tôi thay đổi messagesbảng như vậy,

  1. một cột mới được gọi senderđược thêm vào nó
  2. nơi senderđược khóa ngoại tham chiếu đến usersbảng

Điều này đã không làm việc

# ALTER TABLE message ADD FOREIGN KEY (sender) REFERENCES users;
ERROR:  column "sender" referenced in foreign key constraint does not exist

Có tuyên bố này không tạo ra cột là tốt?


3
Bạn cần tạo cột trước khi bạn tham chiếu nó. Tôi cũng sẽ thử đọc tài liệu cho ALTER TABLE ở đây, và rất chú ý đến các ví dụ.
Kassandry

Hassan, tôi đã dọn sạch câu hỏi này để sử dụng DDL và tôi đã loại bỏ những thứ không hoạt động. Xem nếu điều này trả lời câu hỏi: dba.stackexchange.com/a/202564/2639 . Hãy từ chối bất kỳ chỉnh sửa nào trong số này, tôi chỉ muốn làm sạch nó cho hậu thế.
Evan Carroll

Câu trả lời:


18

Điều tương đối dễ dàng - bạn chỉ cần thêm một bước nữa.

Các FOREIGN KEYcột phải tồn tại để làm cho nó trở thành một FK. Tôi đã làm như sau (từ đây và các tài liệu ):

CREATE TABLE x(t INT PRIMARY KEY);

CREATE TABLE y(s INT);

ALTER TABLE y ADD COLUMN z INT;    

ALTER TABLE y
  ADD CONSTRAINT y_x_fkey FOREIGN KEY (z)
      REFERENCES x (t)
      ON UPDATE CASCADE ON DELETE CASCADE;

Một vài điểm cần lưu ý:

LUÔN LUÔN cung cấp cho các khóa ngoại của bạn tên có ý nghĩa. Được thông báo rằng khóa "SYS_C00308108" đang bị vi phạm là không hữu ích. Xem fiddle ở đây để biết hành vi của Oracle trong các trường hợp này, tên khóa sẽ thay đổi từ fiddle sang fiddle, nhưng là một chuỗi tùy ý bắt đầu bằng SYS _...)

Xem xét tuyên bố của bạn:

ALTER TABLE message ADD FOREIGN KEY (sender) REFERENCES users;

Sẽ là "dễ có" nếu RDBMS có thể tự động tạo trường bạn muốn với kiểu dữ liệu khớp với trường được tham chiếu. Tất cả những gì tôi muốn nói là việc thay đổi DDL là (hoặc ít nhất nên là) một hoạt động hiếm khi được sử dụng và không phải là điều mà bạn muốn thực hiện thường xuyên. Nó cũng có nguy cơ thêm vào một tài liệu khá lớn.

Ít nhất PostgreSQL cố gắng làm điều gì đó hợp lý - nó ghép tên bảng, tên FOREIGN KEYtrường _fkeyvà thậm chí thêm vào DETAIL: Key (sender_id)=(56) is not present in table "user_".để đưa ra một cái gì đó có ý nghĩa với con người - xem fiddle ở đây .


2
Tôi không bao giờ đặt tên khóa ngoại của tôi. Chúng được tự động hóa và chúng thường khá hữu ích. Ví dụ, tên mặc định trong bối cảnh đó là "y_z_fkey". Tôi cho rằng đó là một cái tên tốt hơn y_x_fkeyvì vi phạm của bạn không cho bạn biết cột bạn đang chèn vào đó gây ra lỗi. Tôi quan tâm ít hơn về nơi nó chỉ. Theo nguyên tắc chung, bạn KHÔNG BAO GIỜ nên đặt tên cho con lừa của mình và để mặc định của PostgreQuery xử lý nó.
Evan Carroll

Ngoài ra, bạn có thể không muốn ghi đè mặc định ON UPDATE CASCADE ON DELETE CASCADE;trong một ví dụ, đặc biệt là không có lý do. Nó làm cho ví dụ phức tạp hơn và bạn không cần phải giải thích nó là gì. Tôi cho một người thường không muốn xóa để xếp tầng.
Evan Carroll

1
Tôi luôn đặt tên FK, theo quy ước mà công ty / dự án đã quyết định. Nó không quan trọng hơn nhiều nếu nó là y_x_fkeyhay y_z_fkeyhay x__y_FK, miễn là nó phù hợp.
ypercubeᵀᴹ

Tôi rất đồng ý với điều này nếu bạn ký hợp đồng - chọn một quy ước và tuân thủ và / hoặc đảm bảo rằng bạn tuân thủ (các) quy ước đã / được sử dụng với hệ thống trước đó.
Vérace

@EvanCarroll - nếu quy ước của PostgreQuery là của dự án hoặc trước đây đã quyết định về các hệ thống có thể không phải là PostgreQuery - một hệ thống có thể đã bắt đầu, ví dụ, Oracle hoặc hệ thống khác có thể không có (các) quy ước của PostgreQuery. Bạn có thể lập luận rằng x_y_z_fk có thể cung cấp thông tin tối đa có thể trong trường hợp xảy ra lỗi! Chọn một cái gì đó và tuân theo nó là phương châm của tôi, nhưng đừng để một RDBMS (dù tốt đến đâu) quyết định các quy ước cho bạn!
Vérace

8

Tôi không chắc tại sao mọi người nói với bạn rằng bạn phải làm điều này theo hai bước. Trong thực tế, bạn không . Bạn đã cố gắng thêm một FOREIGN KEYgiả định, theo thiết kế, cột ở đó và ném lỗi đó nếu cột không có ở đó. Nếu bạn thêm COLUMN, bạn có thể biến nó thành một FOREIGN KEYsáng tạo với REFERENCES,

ALTER TABLE message
  ADD COLUMN sender INT
  REFERENCES users;  -- or REFERENCES table(unique_column)

Sẽ làm việc tốt. Bạn có thể xem cú pháp ALTER TABLEở đây,

ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
action [, ... ]

Với "hành động" là,

ADD [ COLUMN ] [ IF NOT EXISTS ] column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ]

Những ví dụ này thậm chí là trong các tài liệu,

ALTER TABLE distributors
  ADD CONSTRAINT distfk
  FOREIGN KEY (address)
  REFERENCES addresses (address);

ALTER TABLE distributors
  ADD CONSTRAINT distfk
  FOREIGN KEY (address)
  REFERENCES addresses (address)
  NOT VALID;

Nhưng tất cả những gì không cần thiết bởi vì chúng ta có thể dựa vào tự động chuyển đổi và độ phân giải của khóa chính (nếu chỉ tên bảng được chỉ định thì bạn đang tham chiếu khóa chính).


0

CASE1: Nếu bạn cần tạo khóa ngoại trong khi tạo bảng mới

CREATE TABLE table1(
id SERIAL PRIMARY KEY,
column1 varchar(n) NOT NULL,
table2_id SMALLINT REFERENCES table2(id)
); 

Các lệnh trên sẽ tạo một bảng có tên 'bảng1' và ba cột có tên 'id' (Khóa chính), 'cột1', 'bảng2_id' (khóa ngoài của bảng1 tham chiếu cột id của bảng2).

DATATYPE 'serial' sẽ tạo cột sử dụng kiểu dữ liệu này làm cột được tạo tự động, khi chèn các giá trị vào bảng bạn không cần đề cập đến cột này, hoặc bạn có thể đưa ra 'mặc định' mà không có dấu ngoặc kép ở vị trí giá trị.

Một cột khóa chính luôn được thêm vào chỉ mục của bảng với giá trị 'tablename_pkey'.

Nếu khóa ngoại được thêm vào lúc tạo bảng, CONSTRAINT được thêm bằng mẫu '(Present_table_name) _ (Foreign_key_id_name) _fkey'.

Khi thêm khóa ngoại, chúng ta phải nhập từ khóa 'TÀI LIỆU THAM KHẢO' bên cạnh tên cột vì chúng ta muốn nói với các postgres rằng cột này tham chiếu một bảng và sau đó bên cạnh các tham chiếu, chúng ta phải đưa ra bảng để tham khảo và trong ngoặc cho tên cột của bảng được tham chiếu, thông thường các khóa ngoại được cung cấp dưới dạng các cột khóa chính.

TRƯỜNG HỢP 2: Nếu bạn muốn khóa ngoại vào bảng hiện có trên cột hiện có

ALTER TABLE table1
ADD CONSTRAINT table1_table2_id_id_fkey
FOREIGN KEY (table2_id) REFERENCES table2(id);

LƯU Ý: ngoặc '()' sau tab NGOẠI TỆ và TÀI LIỆU THAM KHẢO tabel2 là bắt buộc nếu không các postgres sẽ ném lỗi.


0

Tôi biết vấn đề. Tên cột là khác nhau. Có thể trong một cột, có một khoảng trắng được thêm vào sau tên cột của bạn, vì vậy vui lòng đảm bảo cẩn thận tên cột của bạn được đặt tên giống hệt nhau.


1
OP hỏi: Tuyên bố này không tạo ra cột là tốt? Vì vậy, điều hiển nhiên là anh ấy mong đợi điều đó sẽ xảy ra.
Laurenz Albe
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.