Có DBMS nào cho phép Khóa ngoài tham chiếu Chế độ xem (và không chỉ các bảng cơ sở) không?


22

Lấy cảm hứng từ một câu hỏi mô hình hóa Django: Mô hình hóa cơ sở dữ liệu với nhiều mối quan hệ nhiều-nhiều trong Django . Thiết kế db là một cái gì đó như:

CREATE TABLE Book
( BookID INT NOT NULL
, BookTitle VARCHAR(200) NOT NULL
, PRIMARY KEY (BookID)
) ;

CREATE TABLE Tag
( TagID INT NOT NULL
, TagName VARCHAR(50) NOT NULL
, PRIMARY KEY (TagID)
) ;

CREATE TABLE BookTag
( BookID INT NOT NULL
, TagID INT NOT NULL
, PRIMARY KEY (BookID, TagID)
, FOREIGN KEY (BookID)  REFERENCES Book (BookID)
, FOREIGN KEY (TagID)   REFERENCES Tag (TagID)
) ;

CREATE TABLE Aspect
( AspectID INT NOT NULL
, AspectName VARCHAR(50) NOT NULL
, PRIMARY KEY (AspectID)
) ;

CREATE TABLE TagAspect
( TagID INT NOT NULL
, AspectID INT NOT NULL
, PRIMARY KEY (TagID, AspectID) 
, FOREIGN KEY (TagID)   REFERENCES Tag (TagID)
, FOREIGN KEY (AspectID)  REFERENCES Aspect (AspectID)
) ;

sơ đồ db

và vấn đề là làm thế nào để xác định BookAspectRatingbảng và để thực thi tính toàn vẹn tham chiếu, do đó người ta không thể thêm xếp hạng cho một (Book, Aspect)kết hợp không hợp lệ.

AFAIK, các CHECKràng buộc phức tạp (hoặc ASSERTIONS) liên quan đến các truy vấn con và nhiều hơn một bảng, có thể giải quyết điều này, không có sẵn trong bất kỳ DBMS nào.

Một ý tưởng khác là sử dụng (mã giả) một khung nhìn:

CREATE VIEW BookAspect_view
  AS
SELECT DISTINCT
    bt.BookId
  , ta.AspectId
FROM 
    BookTag AS bt
  JOIN 
    Tag AS t  ON t.TagID = bt.TagID
  JOIN 
    TagAspect AS ta  ON ta.TagID = bt.TagID 
WITH PRIMARY KEY (BookId, AspectId) ;

và một bảng có Khóa ngoài cho Chế độ xem ở trên:

CREATE TABLE BookAspectRating
( BookID INT NOT NULL
, AspectID INT NOT NULL
, PersonID INT NOT NULL
, Rating INT NOT NULL
, PRIMARY KEY (BookID, AspectID, PersonID)
, FOREIGN KEY (PersonID)   REFERENCES Person (PersonID)
, FOREIGN KEY (BookID, AspectID) 
    REFERENCES BookAspect_view (BookID, AspectID)
) ;

Ba câu hỏi:

  • Có DBMS cho phép một (có thể được vật chất hóa) VIEWvới một PRIMARY KEY?

  • Có DBMS cho phép một FOREIGN KEYREFERENCESmột VIEW(và không chỉ là một cơ sở TABLE)?

  • Vấn đề toàn vẹn này có thể được giải quyết bằng cách khác - với các tính năng DBMS có sẵn?


Làm rõ:

Vì có lẽ không có giải pháp thỏa mãn 100% - và câu hỏi Django thậm chí không phải là của tôi! - Tôi quan tâm nhiều hơn đến một chiến lược chung về khả năng tấn công vào vấn đề, chứ không phải là một giải pháp chi tiết. Vì vậy, một câu trả lời như "trong DBMS-X điều này có thể được thực hiện với các kích hoạt trên bảng A" là hoàn toàn chấp nhận được.


Đăng bài dưới dạng nhận xét cho hai câu hỏi đầu tiên của bạn - và không nhất thiết phải dành cho bạn, vì tôi chắc chắn bạn đã biết - nhưng SQL Server không hỗ trợ khóa chính hoặc khóa ngoài cho lượt xem.
Aaron Bertrand

@Aaron: vâng, cảm ơn bạn. Tôi đã đọc rằng Oracle hỗ trợ chi phí PK trong lượt xem. Nhưng không chắc chắn nếu nó sẽ làm việc trong tình huống này. Và câu trả lời cho câu hỏi thứ 2 (về FKs cho lượt xem) có lẽ là tiêu cực trong Oracle.
ypercubeᵀᴹ

Nhưng tôi muốn tìm hiểu xem có giải pháp nào khác không (kích hoạt, Kiểm tra chi phí hoặc kết hợp khác)
ypercubeᵀᴹ

Câu trả lời:


9

Quy tắc kinh doanh này có thể được thi hành trong mô hình chỉ sử dụng các ràng buộc. Bảng dưới đây sẽ giải quyết vấn đề của bạn. Sử dụng nó thay vì quan điểm của bạn:

    CREATE TABLE BookAspectCommonTagLink
    (  BookID INT NOT NULL
    , AspectID INT NOT NULL
    , TagID INT NOT NULL
--TagID is deliberately left out of PK
    , PRIMARY KEY (BookID, AspectID)
    , FOREIGN KEY (BookID, TagID) 
        REFERENCES BookTag (BookID, TagID)
    , FOREIGN KEY (AspectID, TagID) 
        REFERENCES AspectTag (AspectID, TagID)
    ) ;

Ồ tốt đẹp Vấn đề duy nhất tôi có thể nghĩ là sự phức tạp được giới thiệu trong việc chèn / xóa BookTags và TagAspects. Ví dụ, mỗi khi một BookTag mới (hoặc TagAspect) bị xóa, một tìm kiếm phải được thực hiện để xóa các hàng tương ứng trong bảng này và / hoặc thay đổi TagIDThẻ khác có liên quan đến cùng một kết hợp BookAspect.
ypercubeᵀᴹ

Và tìm kiếm tương tự sẽ phải được thực hiện để chèn vào 2 bảng đó. Nhưng các quy tắc phức tạp đòi hỏi các thủ tục phức tạp, vì vậy điều này có vẻ thực sự tốt.
ypercubeᵀᴹ

@ypercube Khi bạn xóa một thẻ, bạn cần kiểm tra và có thể chuyển sang một thẻ khác liên kết cùng Sách và Khía cạnh. Tuy nhiên, khi bạn chèn các thẻ mới, không cần thực hiện bất kỳ kiểm tra nào cho đến khi bạn cần chèn xếp hạng.
AK

1
Nếu người khắc phục sự cố và người nhập dữ liệu là cùng một người hoặc nếu bạn để lộ thông báo lỗi cho người dùng cuối, chắc chắn. Bạn đang suy nghĩ quá nhiều về các cửa hàng một người, nơi bạn đang làm mọi thứ.
Aaron Bertrand

4
@AaronBertrand Bạn vừa giúp tôi rất nhiều. Tôi đang hoàn thiện một bài viết có tên "Phát triển cơ sở dữ liệu bảo trì thấp" và tôi quên đề cập rằng các máy chủ ứng dụng phải ghi lại các thông báo lỗi ban đầu đến từ cơ sở dữ liệu. Tôi chỉ cần thêm nó. Cảm ơn bạn đã nhắc nhở;)
AK

8

Tôi nghĩ rằng bạn sẽ thấy rằng trong rất nhiều trường hợp, các quy tắc kinh doanh phức tạp không thể được thực thi thông qua mô hình. Đây là một trong những trường hợp, ít nhất là trong SQL Server, tôi nghĩ rằng một trình kích hoạt (tốt nhất là thay vì kích hoạt) phục vụ tốt hơn cho mục đích của bạn.


Này Aaron, bạn có thể giải thích tại sao trong trường hợp này, một bộ kích hoạt là lựa chọn tốt hơn một thực thể và một vài ràng buộc không?
AK

2
@AlexKuznetsov Chắc chắn, vì tôi đã không dành 17 giờ để suy nghĩ về cách thực hiện điều này với nhiều khóa ngoại nhiều cột và tất cả logic bổ sung có thể được yêu cầu để xử lý xác thực và xử lý lỗi?
Aaron Bertrand

2
Hãy cẩn thận về các điều kiện chủng tộc mà việc triển khai ngây thơ có thể gây ra. Ví dụ: một giao dịch có thể ngắt kết nối một cuốn sách khỏi thẻ và một giao dịch khác vẫn cho rằng việc kết nối với khía cạnh tương ứng là ổn, đơn giản vì giao dịch đầu tiên chưa được cam kết. Độ phức tạp được giới thiệu bởi câu trả lời @AlexKuznetsov có lẽ ít hơn độ phức tạp và dễ vỡ của "giao thức" khóa cần thiết để ngăn chặn điều kiện chủng tộc trong các kích hoạt, IMHO.
Branko Dimitrijevic

8

Trong Oracle, một cách để thực thi loại ràng buộc này theo kiểu khai báo sẽ là tạo một khung nhìn cụ thể được đặt để làm mới nhanh trên cam kết có truy vấn xác định tất cả các hàng không hợp lệ (nghĩa là BookAspectRatingcác hàng không khớp BookAspect_view). Sau đó, bạn có thể tạo một ràng buộc tầm thường đối với chế độ xem cụ thể hóa đó sẽ bị vi phạm nếu có bất kỳ hàng nào trong chế độ xem cụ thể hóa. Điều này có lợi ích là giảm thiểu lượng dữ liệu mà bạn phải nhân đôi trong chế độ xem cụ thể hóa. Tuy nhiên, điều này có thể gây ra sự cố do ràng buộc chỉ được thi hành tại thời điểm bạn thực hiện giao dịch-- nhiều ứng dụng không được viết để mong rằng hoạt động cam kết có thể thất bại-- và vì vi phạm ràng buộc có thể hơi khó để liên kết với một hàng cụ thể hoặc một bảng cụ thể.


4

SIRA_PRISE cho phép điều đó.

Mặc dù FK không còn được gọi là "FK" nữa, nhưng chỉ là "ràng buộc cơ sở dữ liệu" và "khung nhìn" trên thực tế thậm chí không phải được định nghĩa là dạng xem, bạn chỉ có thể bao gồm dạng xem xác định biểu thức bên trong khai báo của cơ sở dữ liệu hạn chế.

Ràng buộc của bạn sẽ trông giống như

SEMIMINUS(BOOKASPECT , JOIN(BOOKTAG , TAGASPECT))

và bạn đã hoàn thành.

Tuy nhiên, trong hầu hết các DBMS SQL, bạn phải thực hiện công việc phân tích theo ràng buộc của mình, xác định cách nó có thể bị vi phạm và thực hiện tất cả các kích hoạt cần thiết.


Tôi biết. Nó phản ánh những gì tôi nghĩ là quan trọng tại thời điểm viết.
Erwin Smout

3

Trong PostgreSQL, tôi không thể tưởng tượng ra một giải pháp mà không liên quan đến các trình kích hoạt, nhưng chắc chắn nó có thể được giải quyết theo cách đó (có thể là duy trì một cái nhìn cụ thể hóa của một loại nào đó hoặc trước khi kích hoạt BookAspectRating). Không có khóa ngoại tham chiếu một khung nhìn ( ERROR: referenced relation "v_munkalap" is not a table), chứ chưa nói đến khóa chính.

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.