6

Tôi có một cơ sở dữ liệu thiết lập với nhiều bảng và tất cả sẽ tốt ngoài một chút ...Làm thế nào để tạo nhiều 1-1 của

Inventory Table <*-----1> Storage Table <1-----1> Van Table 
          ^
           1 
           |-------1> Warehouse Table 

Bảng lưu trữ được sử dụng kể từ khi Vân và Kho bảng là tương tự nhưng làm cách nào để tạo mối quan hệ giữa lưu trữ và bảng lưu trữ/bảng? Nó sẽ có ý nghĩa họ cần phải được 1 đến 1 như một đối tượng lưu trữ chỉ có thể được 1 nơi lưu trữ và loại. Tôi đã có liên kết bảng Van/Warehouse với khóa chính StorageId và sau đó thêm một ràng buộc để đảm bảo các bảng Van và Warehouse không có cùng một StorageId, nhưng điều này có vẻ như nó có thể được thực hiện một cách tốt hơn.

Tôi có thể thấy một số cách để thực hiện điều này nhưng tất cả đều có vẻ sai, vì vậy mọi trợ giúp sẽ tốt!

+0

Hãy đánh giá kỹ nếu bạn thực sự cần mối quan hệ 1-1. Hầu hết thời gian khi bạn nghĩ rằng bạn cần một, bạn thực sự không. –

+0

Sử dụng EER. Chìa khóa ở đây là để xác định loại mối quan hệ 'là a',' has'/'thuộc về', hoặc chúng là các kiểu con của cùng một siêu kiểu. Sau đó, giảm các thực thể của bạn xuống các bảng. – Oybek

+0

Ahh ok, sau đó Bảng lưu trữ là một siêu lớp và Bảng Vạn/Kho là các kiểu con, nhưng bây giờ thì sao? lol – Luckyl337

Trả lời

15

Bạn đang sử dụng thừa kế (còn được gọi trong mô hình mối quan hệ thực thể là "phân lớp" hoặc "danh mục"). Nói chung, có 3 cách để biểu diễn nó trong cơ sở dữ liệu:

  1. "Tất cả các lớp trong một bảng": Có chỉ là một bảng "bao gồm" tất cả các lớp con phụ huynh và (tức là với tất cả cha mẹ và con cột), với ràng buộc CHECK để đảm bảo tập con đúng của trường là không NULL (tức là hai con khác nhau không "trộn").
  2. "Lớp bê tông trên mỗi bảng": Có bảng khác nhau cho từng trẻ, nhưng không có bảng cha. Điều này đòi hỏi mối quan hệ của cha mẹ (trong trường hợp của bạn Hàng tồn kho < - Lưu trữ) được lặp đi lặp lại ở tất cả trẻ em.
  3. "Lớp học trên mỗi bảng": Có bảng cha và bảng riêng cho từng trẻ em, đó là những gì bạn đang cố gắng làm. Điều này là sạch nhất, nhưng có thể tốn một số hiệu suất (chủ yếu là khi sửa đổi dữ liệu, không quá nhiều khi truy vấn vì bạn có thể tham gia trực tiếp từ con và bỏ qua phụ huynh).

Tôi thường thích cách tiếp cận thứ 3, nhưng thực thi cả hiện diệnđộc quyền của một đứa trẻ ở cấp ứng dụng. Việc thực hiện cả hai ở cấp độ cơ sở dữ liệu là một chút cồng kềnh, nhưng có thể được thực hiện nếu DBMS hỗ trợ các ràng buộc hoãn lại. Ví dụ:

enter image description here

CHECK (
    (
     (VAN_ID IS NOT NULL AND VAN_ID = STORAGE_ID) 
     AND WAREHOUSE_ID IS NULL 
    ) 
    OR (
     VAN_ID IS NULL 
     AND (WAREHOUSE_ID IS NOT NULL AND WAREHOUSE_ID = STORAGE_ID) 
    ) 
) 

này sẽ thực thi cả độc quyền (do CHECK) và sự hiện diện (do sự kết hợp của CHECKFK1/FK2) của trẻ.

Thật không may, MS SQL Server does not support deferred constraints, nhưng bạn có thể "ẩn" toàn bộ hoạt động sau các thủ tục được lưu trữ và cấm khách hàng sửa đổi trực tiếp các bảng.


Chỉ cần độc quyền có thể được áp dụng mà không hạn chế chậm:

enter image description here

Các STORAGE_TYPE là một loại phân biệt, thường là một số nguyên để tiết kiệm không gian (trong ví dụ trên, 0 và 1 là " được biết đến "để ứng dụng của bạn và diễn giải cho phù hợp).

Các cột VAN.STORAGE_TYPEWAREHOUSE.STORAGE_TYPE có thể được tính toán (còn gọi là "được tính toán") để lưu trữ và tránh sự cần thiết cho số CHECK s.

--- EDIT ---

cột Điện Toán sẽ làm việc dưới SQL Server như thế này:

CREATE TABLE STORAGE (
    STORAGE_ID int PRIMARY KEY, 
    STORAGE_TYPE tinyint NOT NULL, 
    UNIQUE (STORAGE_ID, STORAGE_TYPE) 
); 

CREATE TABLE VAN (
    STORAGE_ID int PRIMARY KEY, 
    STORAGE_TYPE AS CAST(0 as tinyint) PERSISTED, 
    FOREIGN KEY (STORAGE_ID, STORAGE_TYPE) REFERENCES STORAGE(STORAGE_ID, STORAGE_TYPE) 
); 

CREATE TABLE WAREHOUSE (
    STORAGE_ID int PRIMARY KEY, 
    STORAGE_TYPE AS CAST(1 as tinyint) PERSISTED, 
    FOREIGN KEY (STORAGE_ID, STORAGE_TYPE) REFERENCES STORAGE(STORAGE_ID, STORAGE_TYPE) 
); 

-- We can make a new van. 
INSERT INTO STORAGE VALUES (100, 0); 
INSERT INTO VAN VALUES (100); 

-- But we cannot make it a warehouse too. 
INSERT INTO WAREHOUSE VALUES (100); 
-- Msg 547, Level 16, State 0, Line 24 
-- The INSERT statement conflicted with the FOREIGN KEY constraint "FK__WAREHOUSE__695C9DA1". The conflict occurred in database "master", table "dbo.STORAGE". 

Thật không may, SQL Server đòi hỏi cho một cột tính được sử dụng bằng ngoại khóa được CHẤP NHẬN. Các cơ sở dữ liệu khác có thể không có giới hạn này (ví dụ: các cột ảo của Oracle), có thể tiết kiệm một số không gian lưu trữ.

+0

Xin chào @Branko, cảm ơn vì câu trả lời tuyệt vời. Tôi đã, tuy nhiên, bối rối bởi những câu cuối cùng của câu trả lời của bạn. Bạn có nhớ xây dựng trên: (1) tại sao, trong biểu đồ cuối cùng của bạn, các bảng VAN và WAREHOUSE có một cột STORAGE_TYPE (tôi tưởng tượng, tất cả đều có cùng giá trị: 0 cho VAN và 1 cho WAREHOUSE), (2) chính xác là gì có nghĩa vụ phải đi trong nội dung của các cột tính toán/tính toán (tôi đang bối rối như những gì đang được tính toán ở đây)? Nhiều nghĩa vụ :) – youngrrrr

+1

@youngrrrr VAN và WAREHOUSE có STORAGE_TYPE để họ có thể khai báo KIỂM TRA trên đó. Bằng cách đó, nếu một hàng STORAGE là một phụ huynh của một hàng VAN, nó _cannot_ cũng là một phụ huynh của hàng WAREHOUSE (vì STORAGE.STORAGE_TYPE là 0, không KIỂM TRA trong kho). Điều ngược lại cũng đúng: nếu STORAGE là KHOÁNG, STORAGE TYPE là 1, có nghĩa là KIỂM TRA trong VAN sẽ thất bại nếu ai đó cố gắng chèn một hàng tương ứng ở đó. Cột được tính toán đơn giản là để tiết kiệm không gian - vì nó luôn có cùng giá trị trong bảng đã cho, nên không cần lặp lại vật lý giá trị đó trong mỗi hàng. –

+1

@youngrrrr Xin lưu ý rằng có một FK trên VAN (STORAGE_ID, STORAGE) tham chiếu STORAGE (STORAGE_ID, STORAGE_TYPE). Và tương tự trên kho. Bằng cách đó, hàng paren (trong STORAGE) và hàng con (trong VAN hoặc WAREHOUSE, nhưng không phải cả hai) luôn có cùng STORAGE_TYPE. –

1

Như bạn nói, có nhiều giải pháp. Tôi khuyên bạn nên bắt đầu với giải pháp đơn giản nhất, sau đó tối ưu hóa sau nếu hiệu suất hoặc bộ nhớ trở thành vấn đề. Giải pháp đơn giản nhất (nhưng không tối ưu về lưu trữ) sẽ là có một bảng lưu trữ có một cột cho kiểu lưu trữ (cho biết hàng có đại diện cho một van hay kho), cộng với các cột cho thuộc tính Van cũng như thuộc tính Warehouse. Trong một hàng đại diện cho một Van, các cột cho thuộc tính Warehouse sẽ là null. Trong một hàng đại diện cho một Warehouse, các cột cho các thuộc tính Van sẽ là null.

Bằng cách đó, bạn cắt giảm số lượng bảng và giữ cho các truy vấn của bạn trở nên đẹp và đơn giản. Hãy chuẩn bị để xem xét lại quyết định của bạn nếu lưu trữ trở nên chặt chẽ.

1

Bằng cách nào đó dường như với tôi rằng các mặt hàng tồn kho có thể thay đổi vị trí, vì vậy tôi sẽ đi với một cái gì đó như thế này.

enter image description here