Theo mô tả của bạn của môi trường kinh doanh đang được xem xét, tồn tại một supertype-kiểu phụ cấu trúc bao gồm mục -the supertype- và mỗi phần tử Categories , tức là, xe , thuyền và máy bay (cùng với hai hơn mà không khiến biết) - các tiểu loại trên mạng.
Tôi sẽ trình bày chi tiết bên dưới phương pháp tôi sẽ làm theo để quản lý một kịch bản như vậy.
Quy tắc kinh doanh
Để bắt đầu phân định lược đồ khái niệm có liên quan , một số quy tắc kinh doanh quan trọng nhất được xác định cho đến nay (chỉ giới hạn phân tích trong ba Danh mục được tiết lộ , để giữ mọi thứ ngắn gọn nhất có thể) có thể được xây dựng như sau:
- Một tài khoản sở hữu zero-một-hoặc-nhiều Items
- Một Mục được sở hữu bởi chính xác một Người dùng tại một thời điểm cụ thể
- Một Mục có thể được sở hữu bởi một-nhiều Người dùng tại các thời điểm khác nhau
- Một mục được phân loại theo chính xác một Danh mục
- Một mục là, mọi lúc,
- hoặc một chiếc xe hơi
- hoặc một chiếc thuyền
- hoặc một chiếc máy bay
Sơ đồ minh họa IDEF1X
Hình 1 hiển thị sơ đồ IDEF1X 1 mà tôi đã tạo để nhóm các công thức trước đó cùng với các quy tắc kinh doanh khác xuất hiện thích hợp:
Siêu nhân
Một mặt, Item , supertype, trình bày các thuộc tính † hoặc các thuộc tính chung cho tất cả các Danh mục , nghĩa là,
- CategoryCode đã được chỉ định là một FOREIGN KEY (FK) tham chiếu Category.C CategoryCode và hoạt động như một trình phân biệt kiểu con , nghĩa là, nó chỉ ra Danh mục chính xác của kiểu con mà nó đã cho mục phải connected-,
- Chủ sở hữuId đã được phân loại là FK trỏ đến Người dùng. Người dùng , nhưng tôi đã gán cho nó một tên vai trò 2 để phản ánh ý nghĩa đặc biệt của nó chính xác hơn,
- Foo ,
- Quán ba ,
- Bô và
- CreatedDateTime .
Tiểu loại
Mặt khác, các thuộc tính ‡ rằng gắn liền với mỗi đặc biệt loại , tức là,
- Qux và quân đoàn ;
- Grault , Garply và Plugh ;
- Xyzzy , Thud , Wibble và Flob ;
được hiển thị trong hộp phụ tương ứng.
Định danh
Sau đó, KEY.ItemId PRIMARY KEY (PK) đã di chuyển 3 sang các kiểu con với các tên vai trò khác nhau, nghĩa là,
- Xe ,
- Thuyền và
- Máy bayId .
Hiệp hội loại trừ lẫn nhau
Như được mô tả, có một mối liên hệ hoặc mối quan hệ của một-một (1: 1) giữa (a) mỗi lần xuất hiện siêu kiểu và (b) trường hợp phụ của nó.
Các kiểu phụ độc quyền biểu tượng miêu tả một thực tế rằng các phân nhóm loại trừ lẫn nhau, ví dụ, một bê tông mục xảy ra có thể được bổ sung bằng chỉ một trường hợp kiểu phụ duy nhất: một trong hai xe , hoặc một máy bay , hoặc một thuyền (không bao giờ bởi hai hoặc nhiều hơn).
† , ‡ tôi sử dụng tên giữ chỗ cổ điển để cho phép một số thuộc tính loại thực thể, như mệnh giá thực tế của họ đã không được cung cấp trong câu hỏi.
Bố cục mức logic
Do đó, để thảo luận về thiết kế logic lưu trữ, tôi đã rút ra các câu lệnh SQL-DDL sau dựa trên sơ đồ IDEF1X được hiển thị và mô tả ở trên:
-- You should determine which are the most fitting
-- data types and sizes for all your table columns
-- depending on your business context characteristics.
-- Also, you should make accurate tests to define the
-- most convenient INDEX strategies based on the exact
-- data manipulation tendencies of your business context.
-- As one would expect, you are free to utilize
-- your preferred (or required) naming conventions.
CREATE TABLE UserProfile (
UserId INT NOT NULL,
FirstName CHAR(30) NOT NULL,
LastName CHAR(30) NOT NULL,
BirthDate DATE NOT NULL,
GenderCode CHAR(3) NOT NULL,
Username CHAR(20) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT UserProfile_PK PRIMARY KEY (UserId),
CONSTRAINT UserProfile_AK1 UNIQUE ( -- Composite ALTERNATE KEY.
FirstName,
LastName,
GenderCode,
BirthDate
),
CONSTRAINT UserProfile_AK2 UNIQUE (Username) -- ALTERNATE KEY.
);
CREATE TABLE Category (
CategoryCode CHAR(1) NOT NULL, -- Meant to contain meaningful, short and stable values, e.g.; 'C' for 'Car'; 'B' for 'Boat'; 'P' for 'Plane'.
Name CHAR(30) NOT NULL,
--
CONSTRAINT Category_PK PRIMARY KEY (CategoryCode),
CONSTRAINT Category_AK UNIQUE (Name) -- ALTERNATE KEY.
);
CREATE TABLE Item ( -- Stands for the supertype.
ItemId INT NOT NULL,
OwnerId INT NOT NULL,
CategoryCode CHAR(1) NOT NULL, -- Denotes the subtype discriminator.
Foo CHAR(30) NOT NULL,
Bar CHAR(30) NOT NULL,
Baz CHAR(30) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Item_PK PRIMARY KEY (ItemId),
CONSTRAINT Item_to_Category_FK FOREIGN KEY (CategoryCode)
REFERENCES Category (CategoryCode),
CONSTRAINT Item_to_User_FK FOREIGN KEY (OwnerId)
REFERENCES UserProfile (UserId)
);
CREATE TABLE Car ( -- Represents one of the subtypes.
CarId INT NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
Qux CHAR(30) NOT NULL,
Corge CHAR(30) NOT NULL,
--
CONSTRAINT Car_PK PRIMARY KEY (CarId),
CONSTRAINT Car_to_Item_FK FOREIGN KEY (CarId)
REFERENCES Item (ItemId)
);
CREATE TABLE Boat ( -- Stands for one of the subtypes.
BoatId INT NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
Grault CHAR(30) NOT NULL,
Garply CHAR(30) NOT NULL,
Plugh CHAR(30) NOT NULL,
--
CONSTRAINT Boat_PK PRIMARY KEY (BoatId),
CONSTRAINT Boat_to_Item_FK FOREIGN KEY (BoatId)
REFERENCES Item (ItemId)
);
CREATE TABLE Plane ( -- Denotes one of the subtypes.
PlaneId INT NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
Xyzzy CHAR(30) NOT NULL,
Thud CHAR(30) NOT NULL,
Wibble CHAR(30) NOT NULL,
Flob CHAR(30) NOT NULL,
--
CONSTRAINT Plane_PK PRIMARY KEY (PlaneId),
CONSTRAINT Plane_to_Item_PK FOREIGN KEY (PlaneId)
REFERENCES Item (ItemId)
);
Như đã trình bày, loại siêu hạng và từng loại thuộc tính được thể hiện bằng bảng cơ sở tương ứng .
Các cột CarId
, BoatId
và PlaneId
, bị ràng buộc như các PK của các bảng thích hợp, giúp biểu diễn liên kết một-một-cấp theo khái niệm bằng các ràng buộc FK § trỏ đến ItemId
cột, được ràng buộc như PK của Item
bảng. Điều này biểu thị rằng, trong một cặp Cặp thực tế, cả hai hàng siêu kiểu và hàng phụ được xác định bởi cùng một giá trị PK; do đó, nó là nhiều hơn cơ hội để đề cập rằng
- (a) đính kèm một cột phụ để giữ các giá trị thay thế được kiểm soát bởi hệ thống ‖ đến (b) các bảng biểu thị cho các kiểu con là (c) hoàn toàn không cần thiết .
§ Để ngăn chặn các vấn đề và lỗi liên quan (đặc biệt là NGOẠI HỐI) Các định nghĩa ràng buộc KEY Các phần tử mà bạn đã đề cập trong các bình luận, điều rất quan trọng là phải tính đến sự phụ thuộc tồn tại giữa các bảng khác nhau, như được minh họa trong thứ tự khai báo của các bảng trong cấu trúc DDL lưu trữ, mà tôi đã cung cấp trong SQL Fiddle này .
‖ Ví dụ: nối thêm một cột với thuộc tính AUTO_INCREMENT vào bảng cơ sở dữ liệu được xây dựng trên MySQL.
Cân nhắc tính toàn vẹn và nhất quán
Điều rất quan trọng là chỉ ra rằng, trong môi trường kinh doanh của bạn, bạn phải (1) đảm bảo rằng mỗi hàng siêu siêu phẩm của Cấm luôn luôn được bổ sung bởi đối tác phụ của nó, và lần lượt, (2) đảm bảo rằng Hàng subtype của YouTube có thể tương thích với giá trị được chứa trong cột phân biệt đối xử của YouTube.
Sẽ rất thanh lịch khi thực thi các trường hợp như vậy theo cách khai báo , nhưng thật không may, không có nền tảng SQL chính nào cung cấp các cơ chế phù hợp để làm như vậy, theo như tôi biết. Do đó, sử dụng mã thủ tục trong GIAO DỊCH ACID khá thuận tiện để các điều kiện này luôn được đáp ứng trong cơ sở dữ liệu của bạn. Tùy chọn khác sẽ sử dụng TRIGGERS, nhưng họ có xu hướng làm cho mọi thứ không gọn gàng, để nói.
Tuyên bố quan điểm hữu ích
Có một thiết kế logic như đã giải thích ở trên, sẽ rất thực tế khi tạo một hoặc nhiều khung nhìn, tức là các bảng dẫn xuất bao gồm các cột thuộc hai hoặc nhiều bảng cơ sở có liên quan . Theo cách này, bạn có thể, ví dụ: CHỌN trực tiếp TỪ các chế độ xem đó mà không phải viết tất cả các THAM GIA mỗi khi bạn phải truy xuất thông tin kết hợp của Hồi.
Dữ liệu mẫu
Về mặt này, chúng ta hãy nói rằng các bảng cơ sở là dân cư đông đúc với dữ liệu mẫu được hiển thị bên dưới:
--
INSERT INTO UserProfile
(UserId, FirstName, LastName, BirthDate, GenderCode, Username, CreatedDateTime)
VALUES
(1, 'Edgar', 'Codd', '1923-08-19', 'M', 'ted.codd', CURDATE()),
(2, 'Michelangelo', 'Buonarroti', '1475-03-06', 'M', 'michelangelo', CURDATE()),
(3, 'Diego', 'Velázquez', '1599-06-06', 'M', 'd.velazquez', CURDATE());
INSERT INTO Category
(CategoryCode, Name)
VALUES
('C', 'Car'), ('B', 'Boat'), ('P', 'Plane');
-- 1. ‘Full’ Car INSERTion
-- 1.1
INSERT INTO Item
(ItemId, OwnerId, CategoryCode, Foo, Bar, Baz, CreatedDateTime)
VALUES
(1, 1, 'C', 'This datum', 'That datum', 'Other datum', CURDATE());
-- 1.2
INSERT INTO Car
(CarId, Qux, Corge)
VALUES
(1, 'Fantastic Car', 'Powerful engine pre-update!');
-- 2. ‘Full’ Boat INSERTion
-- 2.1
INSERT INTO Item
(ItemId, OwnerId, CategoryCode, Foo, Bar, Baz, CreatedDateTime)
VALUES
(2, 2, 'B', 'This datum', 'That datum', 'Other datum', CURDATE());
-- 2.2
INSERT INTO Boat
(BoatId, Grault, Garply, Plugh)
VALUES
(2, 'Excellent boat', 'Use it to sail', 'Everyday!');
-- 3 ‘Full’ Plane INSERTion
-- 3.1
INSERT INTO Item
(ItemId, OwnerId, CategoryCode, Foo, Bar, Baz, CreatedDateTime)
VALUES
(3, 3, 'P', 'This datum', 'That datum', 'Other datum', CURDATE());
-- 3.2
INSERT INTO Plane
(PlaneId, Xyzzy, Thud, Wibble, Flob)
VALUES
(3, 'Extraordinary plane', 'Traverses the sky', 'Free', 'Like a bird!');
--
Sau đó, một cái nhìn thuận lợi là một trong đó tập hợp các cột từ Item
, Car
và UserProfile
:
--
CREATE VIEW CarAndOwner AS
SELECT C.CarId,
I.Foo,
I.Bar,
I.Baz,
C.Qux,
C.Corge,
U.FirstName AS OwnerFirstName,
U.LastName AS OwnerLastName
FROM Item I
JOIN Car C
ON C.CarId = I.ItemId
JOIN UserProfile U
ON U.UserId = I.OwnerId;
--
Một cách tự nhiên, một cách tiếp cận tương tự có thể được thực hiện để bạn cũng có thể CHỌN đầy đủ các tên lửa Boat
và Plane
thông tin trực tiếp TỪ một bảng duy nhất (trong một trường hợp xuất phát, trong những trường hợp này).
Sau đó -Nếu bạn không nhớ về sự hiện diện của dấu NULL trong kết quả sets- với định nghĩa XEM sau đây, bạn có thể, ví dụ, “thu thập” các cột từ bảng Item
, Car
, Boat
, Plane
và UserProfile
:
--
CREATE VIEW FullItemAndOwner AS
SELECT I.ItemId,
I.Foo, -- Common to all Categories.
I.Bar, -- Common to all Categories.
I.Baz, -- Common to all Categories.
IC.Name AS Category,
C.Qux, -- Applies to Cars only.
C.Corge, -- Applies to Cars only.
--
B.Grault, -- Applies to Boats only.
B.Garply, -- Applies to Boats only.
B.Plugh, -- Applies to Boats only.
--
P.Xyzzy, -- Applies to Planes only.
P.Thud, -- Applies to Planes only.
P.Wibble, -- Applies to Planes only.
P.Flob, -- Applies to Planes only.
U.FirstName AS OwnerFirstName,
U.LastName AS OwnerLastName
FROM Item I
JOIN Category IC
ON I.CategoryCode = IC.CategoryCode
LEFT JOIN Car C
ON C.CarId = I.ItemId
LEFT JOIN Boat B
ON B.BoatId = I.ItemId
LEFT JOIN Plane P
ON P.PlaneId = I.ItemId
JOIN UserProfile U
ON U.UserId = I.OwnerId;
--
Mã của các khung nhìn ở đây hiển thị chỉ mang tính minh họa. Tất nhiên, thực hiện một số bài tập kiểm tra và sửa đổi có thể giúp tăng tốc thực hiện (vật lý) các truy vấn trong tầm tay. Ngoài ra, bạn có thể cần phải xóa hoặc thêm các cột vào các chế độ xem khi doanh nghiệp cần ra lệnh.
Dữ liệu mẫu và tất cả các định nghĩa khung nhìn được tích hợp vào Fiddle SQL này để chúng có thể được quan sát thấy trong hành động.
Thao tác dữ liệu: Mã chương trình ứng dụng và bí danh cột
Việc sử dụng mã chương trình ứng dụng (nếu đó là ý nghĩa của mã cụ thể phía máy chủ của Cameron) và bí danh cột là những điểm quan trọng khác mà bạn đưa ra trong các nhận xét tiếp theo:
Tôi đã cố gắng giải quyết vấn đề [THAM GIA] với mã cụ thể phía máy chủ, nhưng tôi thực sự không muốn làm điều đó - việc thêm bí danh vào tất cả các cột có thể gây "căng thẳng".
Giải thích rất tốt, cảm ơn bạn rất nhiều. Tuy nhiên, như tôi nghi ngờ, tôi sẽ phải thao tác tập kết quả khi liệt kê tất cả dữ liệu vì sự tương đồng với một số cột, vì tôi không muốn sử dụng một số bí danh để giữ cho câu lệnh sạch hơn.
Có thể chỉ ra rằng trong khi sử dụng mã chương trình ứng dụng là một tài nguyên rất phù hợp để xử lý các tính năng trình bày (hoặc đồ họa) của các tập kết quả, tránh việc truy xuất dữ liệu trên cơ sở từng hàng là tối quan trọng để ngăn chặn các vấn đề về tốc độ thực thi. Mục tiêu nên là để tìm nạp các bộ dữ liệu thích hợp trong các công cụ xử lý dữ liệu mạnh mẽ được cung cấp bởi công cụ thiết lập (chính xác) của nền tảng SQL để bạn có thể tối ưu hóa hành vi của hệ thống.
Hơn nữa, việc sử dụng các bí danh để đổi tên một hoặc nhiều cột trong một phạm vi nhất định có thể gây căng thẳng nhưng, cá nhân tôi thấy tài nguyên đó là một công cụ rất mạnh giúp (i) bối cảnh hóa và (ii) phân biệt ý nghĩa và ý định được gán cho liên quan cột; do đó, đây là một khía cạnh cần được suy nghĩ thấu đáo về việc thao túng dữ liệu quan tâm.
Kịch bản tương tự
Bạn cũng có thể tìm thấy sự giúp đỡ của loạt bài đăng này và nhóm bài đăng này có chứa tôi về hai trường hợp khác bao gồm các hiệp hội siêu kiểu phụ với các kiểu con loại trừ lẫn nhau.
Tôi cũng đã đề xuất một giải pháp cho một môi trường kinh doanh liên quan đến cụm siêu kiểu phụ trong đó các kiểu con không loại trừ lẫn nhau trong câu trả lời (mới hơn) này .
Chú thích
1 Định nghĩa tích hợp cho mô hình hóa thông tin ( IDEF1X ) là một kỹ thuật mô hình hóa dữ liệu rất được khuyến khích, được thành lập như một tiêu chuẩn vào tháng 12 năm 1993 bởi Viện Tiêu chuẩn và Công nghệ Quốc gia Hoa Kỳ(NIST). Nó hoàn toàn dựa trên (a) một số công trình lý thuyết được tác giả bởi người khởi tạo duy nhất của mô hình quan hệ , ví dụ, Tiến sĩ EF Codd ; trên (b) quan điểm về mối quan hệ thực thể , được phát triển bởi Tiến sĩ PP Chen ; và cũng trên (c) Kỹ thuật thiết kế cơ sở dữ liệu logic, được tạo bởi Robert G. Brown.
2 Trong IDEF1X, tên vai trò là nhãn đặc biệt được gán cho thuộc tính (hoặc thuộc tính) FK để thể hiện ý nghĩa mà nó giữ trong phạm vi của loại thực thể tương ứng.
3 Tiêu chuẩn IDEF1X định nghĩa di chuyển khóa là Quy trình mô hình hóa việc đặt khóa chính của cha mẹ hoặc thực thể chung trong thực thể con hoặc thực thể của nó làm khóa ngoại khóa.
Item
bảng bao gồm mộtCategoryCode
cột. Như đã đề cập trong phần có tiêu đề Tính toàn vẹn và tính nhất quán của