ตามคำอธิบายของคุณของสภาพแวดล้อมทางธุรกิจภายใต้การพิจารณามีอยู่supertype-ย่อยโครงสร้างที่ครอบคลุมรายการ -The supertype- และแต่ละของหมวดหมู่เช่นรถยนต์ , เรือและเครื่องบิน (พร้อมกับอีกสองคนที่ไม่ได้ถูกทำให้เป็นที่รู้จัก) - ชนิดย่อย -
ฉันจะให้รายละเอียดด้านล่างวิธีที่ฉันจะติดตามเพื่อจัดการสถานการณ์ดังกล่าว
กฎเกณฑ์ทางธุรกิจ
เพื่อเริ่มต้นการวิเคราะห์โครงสร้างแนวคิดที่เกี่ยวข้องกฎเกณฑ์ทางธุรกิจที่สำคัญที่สุดบางข้อได้รับการพิจารณาจนถึงตอนนี้ (จำกัด การวิเคราะห์หมวดที่เปิดเผยทั้งสามเท่านั้นเพื่อให้สิ่งที่สั้นที่สุด) สามารถกำหนดได้ดังนี้:
- ผู้ใช้เป็นเจ้าของศูนย์หนึ่งหรือหลายรายการ
- รายการเป็นเจ้าของโดยหนึ่งว่าผู้ใช้ที่ทันทีที่เฉพาะเจาะจง
- รายการอาจจะเป็นเจ้าของโดยหนึ่งต่อหลายผู้ใช้ที่จุดที่แตกต่างกันในเวลาที่
- รายการจำแนกตามตรงหนึ่งหมวดหมู่
- รายการคือทุกครั้ง
- ทั้งรถยนต์
- หรือเรือ
- หรือเครื่องบิน
แผนภาพ IDEF1X ที่เป็นตัวอย่าง
รูปที่ 1แสดงไดอะแกรมIDEF1X 1ที่ฉันสร้างขึ้นเพื่อจัดกลุ่มสูตรก่อนหน้าพร้อมกับกฎธุรกิจอื่น ๆ ที่ปรากฏขึ้นที่เกี่ยวข้อง:
supertype
ในมือข้างหนึ่ง, รายการ , supertype, จะแสดงคุณสมบัติ†หรือคุณลักษณะที่ใช้ร่วมกันในทุกหมวดหมู่เช่น
- CategoryCode - ที่ระบุว่าเป็น KEY ต่างประเทศ (FK) ที่อ้างถึงCategory.CategoryCodeและฟังก์ชั่นเป็นdiscriminatorชนิดย่อยกล่าวคือเป็นการระบุหมวดหมู่ของประเภทย่อยที่แน่นอนซึ่งรายการที่กำหนดจะต้องเชื่อมต่อ -
- OwnerId—แยกแยะว่าเป็น FK ที่ชี้ไปที่User.UserIdแต่ฉันกำหนดชื่อบทบาท2เพื่อให้สะท้อนถึงความหมายพิเศษได้อย่างแม่นยำยิ่งขึ้น -
- foo ,
- บาร์ ,
- Bazและ
- สร้างวันที่เวลา
ชนิดย่อย
ในทางกลับกันคุณสมบัติ‡ที่เกี่ยวข้องกับหมวดหมู่เฉพาะเช่น
- QuxและCorge ;
- Grault , GarplyและPlugh ;
- Xyzzy , Thud , WibbleและFlob ;
จะแสดงในกล่องย่อยที่สอดคล้องกัน
ตัวบ่งชี้
จากนั้นItem.ItemIdคีย์หลัก (PK) ได้ย้าย3ไปยังประเภทย่อยที่มีชื่อบทบาทที่แตกต่างกันคือ
- CARiD ,
- BoatIdและ
- PlaneId
ความสัมพันธ์ที่ไม่เหมือนกัน
ดังที่ปรากฎมีการเชื่อมโยงหรือความสัมพันธ์ของความเป็นหนึ่งเดียวต่อหนึ่ง (1: 1) ระหว่าง (ก) การเกิดแต่ละชนิดของซูเปอร์ไทป์และ (b) อินสแตนซ์ย่อยย่อยเสริม
ย่อยพิเศษสัญลักษณ์ portrays ความจริงที่ว่าเชื้อเป็นพิเศษร่วมกันเช่นคอนกรีตรายการที่เกิดขึ้นสามารถเสริมด้วยเช่นเดียวย่อยเท่านั้น: คนใดคนหนึ่งรถยนต์หรือหนึ่งเครื่องบินหรือหนึ่งเรือ (ไม่เคยสองหรือมากกว่า)
† , ‡ฉันใช้ชื่อตัวยึดแบบคลาสสิกเพื่อให้สิทธิ์คุณสมบัติประเภทเอนทิตี้บางอย่างเนื่องจากไม่มีการระบุตัวตนจริงในคำถาม
โครงร่างระดับตรรกะของที่เก็บข้อมูล
ดังนั้นเพื่อหารือเกี่ยวกับการออกแบบเชิงตรรกะของที่เก็บฉันได้รับข้อความสั่ง SQL-DDL ต่อไปนี้ตามแผนภาพ IDEF1X ที่แสดงและอธิบายไว้ข้างต้น:
-- 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)
);
ดังที่แสดงให้เห็นว่าประเภทความยิ่งใหญ่และประเภทย่อยแต่ละประเภทจะถูกแสดงด้วยตารางฐานที่สอดคล้องกัน
คอลัมน์CarId
, BoatId
และPlaneId
, จำกัด เป็นปลากัดสวยงามของตารางที่เหมาะสมช่วยในการเป็นตัวแทนสมาคมแนวความคิดในระดับหนึ่งต่อหนึ่งโดยวิธีการ จำกัด FK §ที่ชี้ไปItemId
คอลัมน์ซึ่งเป็นข้อ จำกัด เป็น PK ของItem
ตาราง นี่หมายความว่าใน“ คู่” ที่แท้จริงทั้งแถว supertype และแถวย่อยจะถูกระบุด้วยค่า PK เดียวกัน ดังนั้นจึงเป็นมากกว่าโอกาสที่จะพูดถึง
- (ก) การแนบพิเศษคอลัมน์เพื่อเก็บค่าตัวแทนระบบควบคุม‖ไป (ข) ตารางยืนเชื้อเป็น (c) ฟุ่มเฟือยอย่างสิ้นเชิง
§เพื่อป้องกันปัญหาและข้อผิดพลาดเกี่ยวกับคำจำกัดความของข้อ จำกัด ที่สำคัญ (โดยเฉพาะอย่างยิ่งต่างประเทศ) - สถานการณ์ที่คุณอ้างถึงในความคิดเห็น - เป็นสิ่งสำคัญมากที่จะต้องคำนึงถึงการพึ่งพาอาศัยอยู่ที่เกิดขึ้นในตารางต่างๆ ลำดับการประกาศของตารางในโครงสร้าง DDL ของที่เก็บซึ่งฉันให้ไว้ในSQL Fiddleนี้ด้วย
‖เช่นเพิ่มคอลัมน์เพิ่มเติมด้วยคุณสมบัติAUTO_INCREMENTในตารางของฐานข้อมูลที่สร้างบน MySQL
ข้อพิจารณาด้านความซื่อสัตย์และความมั่นคง
สิ่งสำคัญคือต้องชี้ให้เห็นว่าในสภาพแวดล้อมทางธุรกิจของคุณคุณต้อง (1) ตรวจสอบให้แน่ใจว่าแถว "supertype" แต่ละแถวนั้นถูกเติมเต็มด้วยคู่ "ย่อย" ที่สอดคล้องกันและในทางกลับกัน (2) รับประกันว่า แถว“ ประเภทย่อย” เข้ากันได้กับค่าที่อยู่ในคอลัมน์“ discriminator” ของแถว“ supertype”
มันจะสง่างามมากในการบังคับใช้สถานการณ์ดังกล่าวในลักษณะที่เปิดเผยแต่น่าเสียดายที่ไม่มีแพลตฟอร์ม SQL ที่สำคัญใด ๆ ที่ได้จัดเตรียมกลไกที่เหมาะสมในการทำเช่นนั้นเท่าที่ฉันรู้ ดังนั้นการหันไปใช้รหัสขั้นตอนภายในการทำธุรกรรมกรดมันค่อนข้างสะดวกเพื่อให้เงื่อนไขเหล่านี้มักจะพบในฐานข้อมูลของคุณ ตัวเลือกอื่นจะจ้างทริกเกอร์ แต่พวกเขามักจะทำสิ่งที่ไม่เป็นระเบียบดังนั้นควรพูด
ประกาศมุมมองที่เป็นประโยชน์
มีการออกแบบเชิงตรรกะเหมือนที่อธิบายไว้ข้างต้นมันจะเป็นประโยชน์อย่างมากในการสร้างมุมมองอย่างน้อยหนึ่งมุมมองเช่นตารางที่ได้รับซึ่งประกอบด้วยคอลัมน์ที่อยู่ในตารางฐานที่เกี่ยวข้องสองตารางขึ้นไป ด้วยวิธีนี้คุณสามารถทำได้เช่นเลือกโดยตรงจากมุมมองเหล่านั้นโดยไม่ต้องเขียน JOIN ทั้งหมดทุกครั้งที่คุณต้องดึงข้อมูล“ รวม”
ข้อมูลตัวอย่าง
ในส่วนนี้ขอให้เราบอกว่าตารางฐานนั้นมี“ ประชากร” พร้อมด้วยข้อมูลตัวอย่างที่แสดงด้านล่าง:
--
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!');
--
จากนั้นมีมุมมองที่ได้เปรียบเป็นหนึ่งที่รวบรวมจากคอลัมน์Item
, Car
และ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;
--
โดยปกติแล้ววิธีการที่คล้ายกันสามารถปฏิบัติตามเพื่อให้คุณสามารถเลือก "เต็ม" Boat
และPlane
ข้อมูลตรงจากตารางเดียวหนึ่ง (ที่ได้รับมาในกรณีเหล่านี้)
หลังจากนั้นหากคุณไม่ทราบเกี่ยวกับการปรากฏตัวของเครื่องหมายโมฆะผล sets- กับคำจำกัดความมุมมองต่อไปนี้คุณสามารถเช่น“เก็บ” คอลัมน์จากตารางItem
, Car
, Boat
, Plane
และ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;
--
รหัสของมุมมองที่แสดงที่นี่เป็นเพียงตัวอย่างเท่านั้น แน่นอนว่าการทำแบบฝึกหัดการทดสอบและการดัดแปลงอาจช่วยเร่งความเร็วในการประมวลผลคำสั่ง (ทางกายภาพ) นอกจากนี้คุณอาจต้องลบหรือเพิ่มคอลัมน์เพื่อดูมุมมองดังกล่าวเนื่องจากธุรกิจจำเป็นต้องกำหนด
ข้อมูลตัวอย่างและคำจำกัดความมุมมองทั้งหมดจะรวมอยู่ในSQL Fiddle นี้เพื่อให้สามารถสังเกตได้ว่า "กำลังดำเนินการ"
การจัดการข้อมูล: รหัสแอปพลิเคชันโปรแกรมและชื่อแทนคอลัมน์
การใช้รหัสแอปพลิเคชัน (ถ้านั่นคือสิ่งที่คุณหมายถึงโดย "รหัสเฉพาะฝั่งเซิร์ฟเวอร์") และชื่อแทนคอลัมน์เป็นจุดสำคัญอื่น ๆ ที่คุณนำมาแสดงในความคิดเห็นถัดไป:
ฉันจัดการเพื่อแก้ไขปัญหา [เข้าร่วม] ด้วยรหัสเฉพาะฝั่งเซิร์ฟเวอร์ แต่ฉันไม่ต้องการทำเช่นนั้น - และ - การเพิ่มชื่อแทนในคอลัมน์ทั้งหมดอาจเป็นการ "เน้น"
อธิบายได้ดีมากขอบคุณมาก อย่างไรก็ตามอย่างที่ฉันสงสัยฉันจะต้องจัดการกับชุดผลลัพธ์เมื่อแสดงรายการข้อมูลทั้งหมดเนื่องจากมีความคล้ายคลึงกับบางคอลัมน์เนื่องจากฉันไม่ต้องการใช้นามแฝงหลายตัวเพื่อรักษาคำสั่งให้สะอาด
มันเป็นโอกาสที่ดีที่จะระบุว่าในขณะที่ใช้รหัสโปรแกรมแอปพลิเคชันเป็นทรัพยากรที่เหมาะสมมากในการจัดการคุณสมบัติการนำเสนอ (หรือกราฟิก) ของชุดผลลัพธ์การหลีกเลี่ยงการดึงข้อมูลในแต่ละแถวนั้นเป็นสิ่งสำคัญยิ่ง วัตถุประสงค์ควรจะ "ดึง" ชุดข้อมูลที่เกี่ยวข้องใน toto โดยเครื่องมือจัดการข้อมูลที่มีประสิทธิภาพซึ่งจัดทำโดย (ตั้งค่าอย่างแม่นยำ) ตั้งค่าเอ็นจิ้นของแพลตฟอร์ม SQL เพื่อให้คุณสามารถปรับการทำงานของระบบของคุณให้เหมาะสมที่สุด
นอกจากนี้การใช้ชื่อแทนเพื่อเปลี่ยนชื่อคอลัมน์หนึ่งคอลัมน์หรือมากกว่าภายในขอบเขตที่กำหนดอาจปรากฏขึ้น แต่โดยส่วนตัวแล้วฉันเห็นว่าทรัพยากรดังกล่าวเป็นเครื่องมือที่มีประสิทธิภาพมากที่ช่วยในการ (i) บริบทและ (ii) ตีความความหมายและเจตนาตามที่เกี่ยวข้อง คอลัมน์; ดังนั้นนี่คือแง่มุมที่ควรไตร่ตรองอย่างถี่ถ้วนเกี่ยวกับการจัดการข้อมูลที่น่าสนใจ
สถานการณ์ที่คล้ายกัน
คุณอาจได้รับความช่วยเหลือเช่นเดียวกับการโพสต์ชุดนี้และกลุ่มโพสต์นี้ซึ่งมีการใช้ของฉันในสองกรณีอื่น ๆ ที่มีการเชื่อมโยง supertype-subtype พร้อมกับชนิดย่อยที่ไม่เกิดร่วมกัน
ฉันยังเสนอวิธีแก้ไขปัญหาสำหรับสภาพแวดล้อมทางธุรกิจที่เกี่ยวข้องกับคลัสเตอร์ supertype-subtype โดยที่ชนิดย่อยนั้นไม่ได้เกิดร่วมกันในคำตอบ (ใหม่)นี้
เชิงอรรถ
1 นิยามการผนวกรวมสำหรับการสร้างแบบจำลองข้อมูล ( IDEF1X ) เป็นเทคนิคการสร้างแบบจำลองข้อมูลที่แนะนำอย่างสูงซึ่งก่อตั้งขึ้นเป็นมาตรฐานในเดือนธันวาคม 1993 โดยสถาบันมาตรฐานและเทคโนโลยีแห่งชาติของสหรัฐอเมริกา(NIST) มันขึ้นอยู่กับ (a) บางส่วนของงานทางทฤษฎีที่ประพันธ์โดยผู้สร้าง แต่เพียงผู้เดียวของรูปแบบเชิงสัมพันธ์คือดร. EF Codd ; บน (b)มุมมองความสัมพันธ์เอนทิตีที่พัฒนาโดย Dr. PP Chen ; และ (c) เทคนิคการออกแบบฐานข้อมูลแบบลอจิคัลสร้างโดย Robert G. Brown
2ใน IDEF1Xชื่อบทบาทคือป้ายกำกับที่กำหนดให้คุณสมบัติ FK (หรือแอตทริบิวต์) เพื่อแสดงความหมายที่อยู่ภายในขอบเขตของประเภทเอนทิตีที่เกี่ยวข้อง
3มาตรฐาน IDEF1X กำหนดการโอนย้ายคีย์เป็น“ กระบวนการสร้างแบบจำลองของการวางคีย์หลักของพาเรนต์หรือเอนทิตีทั่วไปในเอนทิตีลูกหรือหมวดหมู่เป็นคีย์ต่างประเทศ "
Item
ตารางรวมCategoryCode
คอลัมน์ ตามที่กล่าวไว้ในหัวข้อเรื่อง“ การพิจารณาความซื่อสัตย์และความมั่นคง”: