2012-06-05 30 views
8

Có thể trong PostgreSQL có điều kiện thêm khoá ngoại không?Khoá ngoài có điều kiện PostgreSQL

Cái gì như: ALTER TABLE table1 ADD FOREIGN KEY (some_id) REFERENCES other_table WHERE some_id NOT IN (0,-1) AND some_id IS NOT NULL;

Cụ thể, bảng tham chiếu của tôi có tất cả các số nguyên dương (1+) nhưng bảng tôi cần phải thêm khóa ngoại để có thể chứa không (0), null và tiêu cực một (-1) thay vào đó, tất cả đều có ý nghĩa khác.

Ghi chú:

tôi hoàn toàn nhận thức được rằng đây là bảng thiết kế nghèo, nhưng đó là một thủ thuật thông minh xây dựng 10+ năm trước, khi các tính năng và các nguồn lực, chúng tôi đã có sẵn tại thời điểm này không tồn tại . Hệ thống này đang chạy hàng trăm cửa hàng bán lẻ để quay trở lại và thay đổi phương pháp tại thời điểm này có thể mất vài tháng mà chúng tôi không có.

Tôi không thể sử dụng trình kích hoạt, này PHẢI được thực hiện bằng khóa ngoài.

Trả lời

1

Bạn có thể thêm một "cái bóng" cột để table1 nắm giữ các giá trị làm sạch (ví dụ: tất cả mọi thứ nhưng 0-1). Sử dụng cột này để kiểm tra tính toàn vẹn tham chiếu. Cột bóng này được cập nhật/điền bằng một trình kích hoạt đơn giản trên table1 ghi tất cả các giá trị nhưng 0-1 vào cột bóng. Cả hai 0-1 có thể được ánh xạ tới null.

Sau đó, bạn có toàn vẹn tham chiếu và cột gốc không thay đổi của mình. Nhược điểm: Bạn cũng có một kích hoạt nhỏ và một số dữ liệu dư thừa. Nhưng than ôi, đây là số phận của một lược đồ cũ!

+0

Genius! Bạn nói đúng rằng nó hơi xấu xí, nhưng cơ sở dữ liệu vẫn tự quản lý, vì vậy nó nên làm điều đó! – trex005

+0

AH, bạn đã bao giờ làm việc trên nguồn postgres chưa? Đây có thể là một tính năng tuyệt vời mà bạn có thể thêm bằng cách thực hiện chính xác điều này đằng sau hậu trường. – trex005

+1

@ trex005: Tôi chưa làm việc trên các nguồn PG. Nhưng leeching trên danh sách của hacker mỗi bây giờ và sau đó ấn tượng của tôi là, rằng một tính năng như vậy sẽ không được chào đón. Nếu bạn khái quát _your_ ví dụ (khớp với bất kỳ thứ gì nhưng '0' và' -1') và suy nghĩ về một cú pháp chung bao quát tất cả các trường hợp có thể bạn sẽ nhận được một cấu trúc cú pháp khá phức tạp. Ở phía bên kia của quy mô: Không có gì bạn không thể làm với các công cụ hiện có rồi. Kết quả thực: Các nguồn tài nguyên khan hiếm (thời gian/ngân sách của nhà phát triển) sẽ trả hết hơn cho các mặt hàng TODO khác. Nhưng đó chỉ là ấn tượng của tôi. Đã rơi tự do để liên lạc với họ. –

2

Câu trả lời ngắn gọn là không, Postgres không có điều kiện khóa ngoại. Một số tùy chọn mà bạn có thể xem xét là:

  1. Chỉ không có ràng buộc FK. Di chuyển logic này vào lớp truy cập dữ liệu và sống mà không có tính toàn vẹn tham chiếu.
  2. Cho phép NULL trong cột, hoàn toàn hợp lệ ngay cả với ràng buộc FK. Sau đó, sử dụng cột khác để lưu trữ bất kỳ ý nghĩa nào của 0-1 là.
  3. Thêm hàng giả trong bảng được tham chiếu cho 0-1. Ngay cả khi nó chỉ có dữ liệu không có thật, nó sẽ thỏa mãn ràng buộc FK.

Hy vọng điều này sẽ hữu ích!

+1

Đó là khá nhiều các tùy chọn tôi đã mong đợi. Tôi sẽ để lại câu hỏi trong một thời gian với hy vọng rằng chúng ta sai. :) – trex005

+2

Tùy chọn 4 luôn thay đổi mã Postgres, nó * là * mã nguồn mở bạn biết :) –

+0

rất VẤT đúng ..... giá thầu của bạn là gì? : o) – trex005

1

yêu cầu của bạn là tương đương với hạn chế việc kiểm tra này:

create table t (a float check (a >= -1 and a = floor(a) or a is null)); 
+0

Đúng, nhưng ràng buộc kiểm tra không thể kiểm tra sự tồn tại của một hàng trong bảng khác. –

+0

@MikeChristensen Câu hỏi cho biết bảng tham chiếu _has tất cả các số nguyên dương (1 +) _. Tôi biết điều đó là không thể nhưng tôi đoán anh ấy có nghĩa là nó có tất cả các số nguyên mà không có khoảng trống lên đến một giới hạn nhất định. Điều đó sẽ được đề cập đến việc bổ sung một điều kiện khác vào kiểm tra (a <= n). –

+1

Có thể, tôi chỉ giả định OP thực sự muốn có một khóa ngoại thực sự. –

0

Đây là một khả năng khác. Sử dụng quyền thừa kế PG để thực thi phân vùng của bảng thành +1 trong cột cờ và ngược lại. (Quy tắc/kích hoạt thông thường để duy trì điều này.) Sau đó có mối quan hệ FK giữa chỉ bảng con Has_PLUS_ONE và bảng được tham chiếu.

+0

Sử dụng quyền thừa kế PG gần như không bao giờ là giải pháp phù hợp cho bất kỳ thứ gì. Họ chỉ là quá hạn chế và kỳ quặc. – cliffordheath

0

Bạn có thể thực hiện điều này với ràng buộc kiểm tra và khóa ngoại.

CREATE TABLE table1 (some_id INT, some_id_fkey INT REFERENCES other_table(other_id), CHECK (some_id IN (0,-1) OR some_id IS NOT DISTINCT FROM some_id_fkey)); 

(không kiểm tra)

Các vấn đề liên quan