การออกแบบที่ดีที่สุดในการอ้างอิงหลายตารางจากคอลัมน์เดียว?


18

สคีมาที่เสนอ

ก่อนอื่นนี่คือตัวอย่างของสคีมาที่ฉันเสนอเพื่ออ้างอิงตลอดโพสต์ของฉัน:

Clothes
---------- 
ClothesID (PK) INT NOT NULL
Name VARCHAR(50) NOT NULL
Color VARCHAR(50) NOT NULL
Price DECIMAL(5,2) NOT NULL
BrandID INT NOT NULL
...

Brand_1
--------
ClothesID (FK/PK) int NOT NULL
ViewingUrl VARCHAR(50) NOT NULL
SomeOtherBrand1SpecificAttr VARCHAR(50) NOT NULL

Brand_2
--------
ClothesID (FK/PK) int NOT NULL
PhotoUrl VARCHAR(50) NOT NULL
SomeOtherBrand2SpecificAttr VARCHAR(50) NOT NULL

Brand_X
--------
ClothesID (FK/PK) int NOT NULL
SomeOtherBrandXSpecificAttr VARCHAR(50) NOT NULL

คำชี้แจงปัญหา

ฉันมีโต๊ะเสื้อผ้าที่มีคอลัมน์เช่นชื่อ, สี, ราคา, แบรนด์และอื่น ๆ เพื่ออธิบายคุณสมบัติสำหรับเสื้อผ้าแต่ละรายการ

นี่คือปัญหาของฉัน:เสื้อผ้าแบรนด์ต่างๆ ต้องการข้อมูลที่ต่างกัน แนวปฏิบัติที่ดีที่สุดสำหรับการจัดการกับปัญหาเช่นนี้คืออะไร?

โปรดทราบว่าเพื่อจุดประสงค์ของฉันมีความจำเป็นต้องค้นหาข้อมูลเฉพาะแบรนด์ที่เริ่มต้นจากรายการเสื้อผ้า นี่เป็นเพราะฉันแสดงข้อมูลจากรายการเสื้อผ้าให้กับผู้ใช้เป็นครั้งแรกหลังจากนั้นฉันจะต้องใช้ข้อมูลเฉพาะแบรนด์เพื่อซื้อสินค้า โดยสรุปจะต้องมีความสัมพันธ์ระหว่างเสื้อผ้า (จาก) และตารางbrand_x

ข้อเสนอ / วิธีแก้ปัญหาในปัจจุบัน

เพื่อรับมือกับสิ่งนี้ฉันได้คิดถึงรูปแบบการออกแบบต่อไปนี้:

เสื้อผ้าโต๊ะจะมีแบรนด์คอลัมน์ที่อาจมีค่า ID ตั้งแต่ 1 ถึง x ซึ่งสอดคล้อง ID โดยเฉพาะอย่างยิ่งกับตารางแบรนด์ที่เฉพาะเจาะจง ตัวอย่างเช่นค่า id 1 จะสอดคล้องกับตารางbrand_1 (ซึ่งอาจมีคอลัมน์URL ) id 2 จะสอดคล้องกับbrand_2 (ซึ่งอาจมีคอลัมน์ผู้จัดหา ) เป็นต้น

ดังนั้นในการเชื่อมโยงรายการเสื้อผ้าเข้ากับข้อมูลเฉพาะของแบรนด์ฉันคิดว่าตรรกะในระดับแอปพลิเคชันจะมีลักษณะดังนี้:

clothesId = <some value>
brand = query("SELECT brand FROM clothes WHERE id = clothesId")

if (brand == 1) {
    // get brand_1 attributes for given clothesId
} else if (brand == 2) {
    // get brand_2 attributes for given clothesId
} ... etc.

ความคิดเห็นและความคิดอื่น ๆ

ฉันพยายามทำให้ฐานข้อมูลทั้งหมดของฉันเป็นแบบปกติใน BCNF และแม้ว่านี่จะเป็นสิ่งที่ฉันคิดไว้ แต่รหัสแอปพลิเคชันที่ได้ทำให้ฉันรู้สึกกังวลมาก ไม่มีวิธีในการบังคับใช้ความสัมพันธ์ยกเว้นในระดับแอปพลิเคชันและทำให้การออกแบบรู้สึกแฮ็คมากและฉันคาดว่าจะเกิดข้อผิดพลาดได้ง่าย

การวิจัย

ฉันแน่ใจว่าได้ตรวจสอบรายการก่อนหน้าก่อนโพสต์ นี่คือโพสต์ที่มีปัญหาใกล้เคียงที่ฉันจัดการเพื่อค้นหา ฉันทำโพสต์นี้ต่อไปเพราะดูเหมือนว่าคำตอบเดียวที่ให้ไว้ไม่มี SQL หรือโซลูชันที่ใช้การออกแบบ (เช่นมันกล่าวถึง OOP การสืบทอดและอินเทอร์เฟซ)

ฉันยังเป็นสามเณรเมื่อพูดถึงการออกแบบฐานข้อมูลและดังนั้นฉันจึงขอขอบคุณข้อมูลเชิงลึกใด ๆ


ดูเหมือนว่าจะมีคำตอบที่เป็นประโยชน์เพิ่มเติมเกี่ยวกับ Stack Overflow:

ฉันได้อ้างถึงวิธีแก้ปัญหาที่นั่นและแนะนำให้ผู้อื่นค้นหาคำถามของฉันเช่นกัน

แม้จะมีลิงก์ที่ให้ไว้ข้างต้น แต่ฉันก็ยังคงมองหาคำตอบที่นี่และจะขอบคุณโซลูชั่นที่ให้ไว้!

ฉันใช้ PostgreSQL

คำตอบ:


7

โดยส่วนตัวฉันไม่ชอบใช้สคีมาหลายตารางเพื่อจุดประสงค์นี้

  • มันยากที่จะรับรองความถูกต้อง
  • มันยากที่จะรักษา
  • การกรองผลลัพธ์ทำได้ยาก

ฉันได้ตั้งตัวอย่าง dbfiddleตัวอย่าง

สคีมาของตารางที่ฉันเสนอ:

CREATE TABLE #Brands
(
BrandId int NOT NULL PRIMARY KEY,
BrandName nvarchar(100) NOT NULL 
);

CREATE TABLE #Clothes
(
ClothesId int NOT NULL PRIMARY KEY,
ClothesName nvarchar(100) NOT NULL 
);

-- Lookup table for known attributes
--
CREATE TABLE #Attributes
(
AttrId int NOT NULL PRIMARY KEY,
AttrName nvarchar(100) NOT NULL 
);

-- holds common propeties, url, price, etc.
--
CREATE TABLE #BrandsClothes
(
BrandId int NOT NULL REFERENCES #Brands(BrandId),
ClothesId int NOT NULL REFERENCES #Clothes(ClothesId),
VievingUrl nvarchar(300) NOT NULL,
Price money NOT NULL,
PRIMARY KEY CLUSTERED (BrandId, ClothesId),
INDEX IX_BrandsClothes NONCLUSTERED (ClothesId, BrandId)
);

-- holds specific and unlimited attributes 
--
CREATE TABLE #BCAttributes
(
BrandId int NOT NULL REFERENCES #Brands(BrandId),
ClothesId int NOT NULL REFERENCES #Clothes(ClothesId),
AttrId int NOT NULL REFERENCES #Attributes(AttrId),
AttrValue nvarchar(300) NOT NULL,
PRIMARY KEY CLUSTERED (BrandId, ClothesId, AttrId),
INDEX IX_BCAttributes NONCLUSTERED (ClothesId, BrandId, AttrId)
);

ให้ฉันแทรกข้อมูลบางส่วน:

INSERT INTO #Brands VALUES 
(1, 'Brand1'), (2, 'Brand2');

INSERT INTO #Clothes VALUES 
(1, 'Pants'), (2, 'T-Shirt');

INSERT INTO #Attributes VALUES
(1, 'Color'), (2, 'Size'), (3, 'Shape'), (4, 'Provider'), (0, 'Custom');

INSERT INTO #BrandsClothes VALUES
(1, 1, 'http://mysite.com?B=1&C=1', 123.99),
(1, 2, 'http://mysite.com?B=1&C=2', 110.99),
(2, 1, 'http://mysite.com?B=2&C=1', 75.99),
(2, 2, 'http://mysite.com?B=2&C=2', 85.99);

INSERT INTO #BCAttributes VALUES
(1, 1, 1, 'Blue, Red, White'),
(1, 1, 2, '32, 33, 34'),
(1, 2, 1, 'Pearl, Black widow'),
(1, 2, 2, 'M, L, XL'),
(2, 1, 4, 'Levis, G-Star, Armani'),
(2, 1, 3, 'Slim fit, Regular fit, Custom fit'),
(2, 2, 4, 'G-Star, Armani'),
(2, 2, 3, 'Slim fit, Regular fit'),
(2, 2, 0, '15% Discount');

หากคุณต้องการดึงแอตทริบิวต์ทั่วไป:

SELECT     b.BrandName, c.ClothesName, bc.VievingUrl, bc.Price
FROM       #BrandsClothes bc
INNER JOIN #Brands b
ON         b.BrandId = bc.BrandId
INNER JOIN #Clothes c
ON         c.ClothesId = bc.ClothesId
ORDER BY   bc.BrandId, bc.ClothesId;

BrandName   ClothesName   VievingUrl                  Price
---------   -----------   -------------------------   ------
Brand1      Pants         http://mysite.com?B=1&C=1   123.99
Brand1      T-Shirt       http://mysite.com?B=1&C=2   110.99
Brand2      Pants         http://mysite.com?B=2&C=1    75.99
Brand2      T-Shirt       http://mysite.com?B=2&C=2    85.99

หรือคุณสามารถหาเสื้อผ้าตามยี่ห้อ:

มอบเสื้อผ้ายี่ห้อ Brand2 ให้ฉันทั้งหมด

SELECT     c.ClothesName, b.BrandName, a.AttrName, bca.AttrValue
FROM       #BCAttributes bca
INNER JOIN #BrandsClothes bc
ON         bc.BrandId = bca.BrandId
AND        bc.ClothesId = bca.ClothesId
INNER JOIN #Brands b
ON         b.BrandId = bc.BrandId
INNER JOIN #Clothes c
ON         c.ClothesId = bc.ClothesId
INNER JOIN #Attributes a
ON         a.AttrId = bca.AttrId
WHERE      bca.ClothesId = 2
ORDER BY   bca.ClothesId, bca.BrandId, bca.AttrId;

ClothesName   BrandName   AttrName   AttrValue
-----------   ---------   --------   ---------------------
T-Shirt       Brand1      Color      Pearl, Black widow
T-Shirt       Brand1      Size       M, L, XL
T-Shirt       Brand2      Custom     15% Discount
T-Shirt       Brand2      Shape      Slim fit, Regular fit
T-Shirt       Brand2      Provider   G-Star, Armani

แต่สำหรับฉันหนึ่งในดีที่สุดของสคีมานี้คือคุณสามารถกรองโดย Attibutes:

ให้เสื้อผ้าทั้งหมดที่มีคุณสมบัติ: ขนาด

SELECT     c.ClothesName, b.BrandName, a.AttrName, bca.AttrValue
FROM       #BCAttributes bca
INNER JOIN #BrandsClothes bc
ON         bc.BrandId = bca.BrandId
AND        bc.ClothesId = bca.ClothesId
INNER JOIN #Brands b
ON         b.BrandId = bc.BrandId
INNER JOIN #Clothes c
ON         c.ClothesId = bc.ClothesId
INNER JOIN #Attributes a
ON         a.AttrId = bca.AttrId
WHERE      bca.AttrId = 2
ORDER BY   bca.ClothesId, bca.BrandId, bca.AttrId;

ClothesName   BrandName   AttrName   AttrValue
-----------   ---------   --------   ----------
Pants         Brand1      Size       32, 33, 34
T-Shirt       Brand1      Size       M, L, XL

การใช้สคีมาหลายตารางไม่ว่าคิวรีใดก่อนหน้านี้จะต้องการจัดการกับตารางไม่ จำกัด จำนวนหรือด้วยฟิลด์ XML หรือ JSON

ตัวเลือกอื่นที่มีสคีมานี้คือคุณสามารถกำหนดเทมเพลตได้เช่นคุณสามารถเพิ่มตารางใหม่ BrandAttrTemplates ทุกครั้งที่คุณเพิ่มระเบียนใหม่คุณสามารถใช้ทริกเกอร์หรือ SP เพื่อสร้างชุดของแอตทริบิวต์ที่กำหนดไว้ล่วงหน้าสำหรับสาขานี้

ฉันขอโทษที่ฉันต้องการขยายคำอธิบายของฉันโดยฉันคิดว่ามันชัดเจนกว่าภาษาอังกฤษของฉัน

ปรับปรุง

คำตอบปัจจุบันของฉันควรทำงานไม่ว่า RDBMS ใด ตามความคิดเห็นของคุณหากคุณต้องการกรองค่าแอตทริบิวต์ฉันขอแนะนำให้ทำการเปลี่ยนแปลงเล็กน้อย

เท่าที่ MS-Sql ไม่อนุญาตให้ใช้อาร์เรย์ฉันได้ตั้งค่าตัวอย่าง schema ของตารางใหม่ แต่เปลี่ยน AttrValue เป็นประเภทเขตข้อมูล ARRAY

อันที่จริงแล้วการใช้ POSTGRES คุณสามารถใช้ประโยชน์จากอาร์เรย์นี้โดยใช้ดัชนี GIN

(ให้ฉันบอกว่า @EvanCarrol มีความรู้ที่ดีเกี่ยวกับ Postgres ดีกว่าฉันอย่างแน่นอน แต่ให้ฉันเพิ่มบิตของฉัน)

CREATE TABLE BCAttributes
(
BrandId int NOT NULL REFERENCES Brands(BrandId),
ClothesId int NOT NULL REFERENCES Clothes(ClothesId),
AttrId int NOT NULL REFERENCES Attrib(AttrId),
AttrValue text[],
PRIMARY KEY (BrandId, ClothesId, AttrId)
);

CREATE INDEX ix_attributes on BCAttributes(ClothesId, BrandId, AttrId);
CREATE INDEX ix_gin_attributes on BCAttributes using GIN (AttrValue);


INSERT INTO BCAttributes VALUES
(1, 1, 1, '{Blue, Red, White}'),
(1, 1, 2, '{32, 33, 34}'),
(1, 2, 1, '{Pearl, Black widow}'),
(1, 2, 2, '{M, L, XL}'),
(2, 1, 4, '{Levis, G-Star, Armani}'),
(2, 1, 3, '{Slim fit, Regular fit, Custom fit}'),
(2, 2, 4, '{G-Star, Armani}'),
(2, 2, 3, '{Slim fit, Regular fit}'),
(2, 2, 0, '{15% Discount}');

ตอนนี้คุณสามารถค้นหาเพิ่มเติมโดยใช้ค่าแอตทริบิวต์แต่ละรายการเช่น:

ส่งรายการกางเกงทั้งหมดให้ฉันขนาด: 33

AttribId = 2 AND ARRAY['33'] && bca.AttrValue

SELECT     c.ClothesName, b.BrandName, a.AttrName, array_to_string(bca.AttrValue, ', ')
FROM       BCAttributes bca
INNER JOIN BrandsClothes bc
ON         bc.BrandId = bca.BrandId
AND        bc.ClothesId = bca.ClothesId
INNER JOIN Brands b
ON         b.BrandId = bc.BrandId
INNER JOIN Clothes c
ON         c.ClothesId = bc.ClothesId
INNER JOIN Attrib a
ON         a.AttrId = bca.AttrId
WHERE      bca.AttrId = 2
AND        ARRAY['33'] && bca.AttrValue
ORDER BY   bca.ClothesId, bca.BrandId, bca.AttrId;

นี่คือผลลัพธ์ที่ได้:

clothes name | brand name | attribute | values 
------------- ------------ ----------  ---------------- 
Pants          Brand1       Size        32, 33, 34

ฉันชอบคำอธิบายนี้มาก แต่ดูเหมือนว่าเราเพิ่งทำการปิดสคีมาหลายตารางเพื่อให้มี CSV หลาย ๆ อันในคอลัมน์เดียว - ถ้ามันสมเหตุสมผล ในทางกลับกันฉันรู้สึกว่าฉันชอบวิธีนี้ดีกว่าเพราะมันไม่ต้องเปลี่ยนสคีมา แต่มันก็รู้สึกเหมือนว่าเรากำลังผลักปัญหานี้ไปที่อื่น นี่อาจเป็นปัญหา ถ้าฉันต้องการสอบถามกางเกงขนาด 3 ในฐานข้อมูลล่ะ อาจไม่มีวิธีแก้ปัญหาที่ดีและสะอาดสำหรับปัญหาประเภทนี้ มีชื่อสำหรับแนวคิดนี้เพื่อที่ฉันจะได้มองมันมากกว่านี้หรือไม่?
youngrrrr

จริงๆแล้ว ... เพื่อตอบปัญหาที่ฉันโพสต์บางทีคำตอบสามารถยืมได้จากโซลูชันของ @ EvanCarroll: คือโดยใช้ประเภท jsonb แทนที่จะเป็นเพียง TEXT / STRINGS ในรูปแบบ CSV แต่อีกครั้ง - หากมีชื่อสำหรับแนวคิดนี้โปรดแจ้งให้เราทราบ!
youngrrrr

1
เป็นโซลูชันประเภทเอนทิตีมูลค่า ไม่ใช่การประนีประนอมระหว่างประสิทธิภาพกับการออกแบบที่ดี มันเป็นข้อเสียเปรียบ คุณแลกเปลี่ยนประสิทธิภาพบางอย่างเพื่อการออกแบบที่สะอาดตาไม่ทิ้งขยะด้วยตาราง "Brand_X" ที่ไม่มีที่สิ้นสุด โทษของการปฏิบัติงานที่ไปจากทิศทางที่คุณระบุไว้ส่วนใหญ่ควรจะน้อยที่สุด การไปทางอื่นจะเจ็บปวดมากกว่า แต่นั่นคือการประนีประนอม en.wikipedia.org/wiki/…
Jonathan Fite

4

สิ่งที่คุณกำลังอธิบายคือแคตตาล็อกผลิตภัณฑ์อย่างน้อยก็บางส่วน คุณมีคุณสมบัติหลายอย่างซึ่งเป็นเรื่องปกติสำหรับผลิตภัณฑ์ทั้งหมด เหล่านี้อยู่ในตารางปกติดี

นอกเหนือจากนั้นคุณมีชุดของคุณลักษณะที่เป็นแบรนด์เฉพาะ (และฉันคาดว่าอาจเป็นผลิตภัณฑ์เฉพาะ) ระบบของคุณต้องทำอะไรกับคุณลักษณะเฉพาะเหล่านี้ คุณมีตรรกะทางธุรกิจที่ขึ้นอยู่กับสคีมาของแอททริบิวต์เหล่านี้หรือคุณเพียงแค่แสดงรายการเหล่านี้ในชุดของ "เลเบล": "ค่า"

คำตอบอื่น ๆ จะบอกโดยใช้สิ่งที่เป็นหลักวิธีการ CSV (ไม่ว่าจะเป็นJSONหรือARRAYหรืออื่น ๆ ) - เหล่านี้วิธีนำการจัดการโดยการย้ายสคีออกจาก metadata และเป็นข้อมูลที่ตัวเองสคีสัมพันธ์ปกติ

มีรูปแบบการออกแบบแบบพกพาสำหรับสิ่งนี้ซึ่งเหมาะกับฐานข้อมูลเชิงสัมพันธ์ได้เป็นอย่างดี มันคือ EAV (เอนทิตี - แอตทริบิวต์ - ค่า) ฉันแน่ใจว่าคุณได้อ่านในหลาย ๆ ที่ที่ "EAV is Evil" (และเป็น) อย่างไรก็ตามมีแอปพลิเคชั่นหนึ่งที่ปัญหาของ EAV ไม่สำคัญและนั่นคือแคตตาล็อกผลิตภัณฑ์

ข้อโต้แย้งตามปกติทั้งหมดกับ EAV ไม่ได้ใช้กับแคตตาล็อกคุณลักษณะของผลิตภัณฑ์เนื่องจากค่าคุณลักษณะของผลิตภัณฑ์มักจะสำรอกลงในรายการหรือกรณีที่เลวร้ายที่สุดในตารางเปรียบเทียบ

การใช้JSONชนิดคอลัมน์ทำให้คุณสามารถบังคับใช้ข้อ จำกัด ของข้อมูลใด ๆ ออกจากฐานข้อมูลและบังคับให้มันลงในตรรกะแอปพลิเคชันของคุณ นอกจากนี้การใช้ตารางคุณลักษณะหนึ่งตารางสำหรับทุกยี่ห้อมีข้อเสียดังต่อไปนี้:

  • มันไม่ได้ปรับขนาดได้ถ้าในที่สุดคุณมีหลายร้อยแบรนด์ (หรือมากกว่านั้น)
  • หากคุณเปลี่ยนแอตทริบิวต์ที่อนุญาตให้ใช้กับแบรนด์คุณต้องเปลี่ยนคำจำกัดความของตารางแทนที่จะเพิ่มหรือลบแถวในตารางควบคุมฟิลด์แบรนด์
  • คุณอาจสิ้นสุดด้วยตารางที่มีประชากรเบาบางหากแบรนด์มีคุณสมบัติที่เป็นไปได้จำนวนมากซึ่งเป็นที่รู้จักกันเพียงส่วนย่อยเท่านั้น

ไม่ยากที่จะเรียกคืนข้อมูลเกี่ยวกับผลิตภัณฑ์ที่มีคุณสมบัติเฉพาะแบรนด์ การสร้าง SQL แบบไดนามิกนั้นง่ายขึ้นโดยใช้โมเดล EAV ซึ่งง่ายกว่าการใช้โมเดลตารางต่อหมวดหมู่ ในตารางต่อหมวดหมู่คุณต้องมีการสะท้อน (หรือของคุณJSON) เพื่อค้นหาว่าชื่อคอลัมน์คุณลักษณะคืออะไร จากนั้นคุณสามารถสร้างรายการของรายการสำหรับส่วนคำสั่งที่ ในรูปแบบ EAV การWHERE X AND Y AND Zกลายเป็นINNER JOIN X INNER JOIN Y INNER JOIN Zดังนั้นแบบสอบถามมีความซับซ้อนมากขึ้นเล็กน้อย แต่ตรรกะในการสร้างแบบสอบถามยังคงขับเคลื่อนด้วยตารางทั้งหมดและจะสามารถปรับขนาดได้มากกว่าหากคุณมีดัชนีที่เหมาะสม

มีเหตุผลมากมายที่จะไม่ใช้ EAV เป็นวิธีการทั่วไป เหตุผลเหล่านั้นไม่ได้ใช้กับแคตตาล็อกคุณลักษณะของผลิตภัณฑ์ดังนั้นจึงไม่มีอะไรผิดปกติกับ EAV ในแอปพลิเคชันเฉพาะนี้

เพื่อให้แน่ใจว่านี่เป็นคำตอบสั้น ๆ สำหรับหัวข้อที่ซับซ้อนและขัดแย้ง ฉันได้ตอบคำถามที่คล้ายกันก่อนและลงรายละเอียดเพิ่มเติมเกี่ยวกับความเกลียดชังทั่วไปต่อ EAV ตัวอย่างเช่น:

ฉันจะบอกว่าใช้ EAV น้อยกว่าเมื่อเร็ว ๆ นี้มันเคยเป็นด้วยเหตุผลที่ดีส่วนใหญ่ อย่างไรก็ตามฉันคิดว่ามันก็ไม่เข้าใจเช่นกัน


3

นี่คือปัญหาของฉัน: เสื้อผ้าแบรนด์ต่าง ๆ ต้องการข้อมูลที่แตกต่างกัน แนวปฏิบัติที่ดีที่สุดสำหรับการจัดการกับปัญหาเช่นนี้คืออะไร?

ใช้ JSON และ PostgreSQL

ฉันคิดว่าคุณกำลังทำสิ่งนี้ยากกว่าที่ควรจะเป็นและคุณจะถูกกัดในภายหลัง คุณไม่ต้องการโมเดลเอนทิตี้ - คุณลักษณะ - ค่า ยกเว้นว่าคุณต้องการ EAV

CREATE TABLE brands (
  brand_id     serial PRIMARY KEY,
  brand_name   text,
  attributes   jsonb
);
CREATE TABLE clothes (
  clothes_id   serial        PRIMARY KEY,
  brand_id     int           NOT NULL REFERENCES brands,
  clothes_name text          NOT NULL,
  color        text,
  price        numeric(5,2)  NOT NULL
);

ไม่มีอะไรผิดปกติกับสคีมานี้

INSERT INTO brands (brand_name, attributes)
VALUES
  ( 'Gucci', $${"luxury": true, "products": ["purses", "tawdry bougie thing"]}$$ ),
  ( 'Hugo Boss', $${"origin": "Germany", "known_for": "Designing uniforms"}$$ ),
  ( 'Louis Vuitton', $${"origin": "France", "known_for": "Designer Purses"}$$ ),
  ( 'Coco Chanel', $${"known_for": "Spying", "smells_like": "Banana", "luxury": true}$$ )
;

INSERT INTO clothes (brand_id, clothes_name, color, price) VALUES
  ( 1, 'Purse', 'orange', 100 ),
  ( 2, 'Underwear', 'Gray', 10 ),
  ( 2, 'Boxers', 'Gray', 10 ),
  ( 3, 'Purse with Roman Numbers', 'Brown', 10 ),
  ( 4, 'Spray', 'Clear', 100 )
;

ตอนนี้คุณสามารถค้นหาได้โดยใช้การเข้าร่วมที่เรียบง่าย

SELECT *
FROM brands
JOIN clothes
  USING (brand_id);

และตัวดำเนินการ JSONใดก็ได้ทำงานในตำแหน่งที่ประโยค

SELECT *
FROM brands
JOIN clothes
  USING (brand_id)
WHERE attributes->>'known_for' ILIKE '%Design%';

ในฐานะที่เป็นบันทึกย่อด้านอย่าใส่ URL ในฐานข้อมูล พวกเขาเปลี่ยนไปตามกาลเวลา เพียงแค่สร้างฟังก์ชั่นที่จะพาพวกเขาไป

generate_url_brand( brand_id );
generate_url_clothes( clothes_id );

หรืออะไรก็ตาม หากคุณใช้ PostgreSQL คุณสามารถใช้แฮชidsได้เช่นกันได้เช่นกัน

ยังมีข้อความพิเศษ jsonbจะถูกเก็บไว้เป็นไบนารี (เช่น -'b ') และมันยังสามารถสร้างดัชนีได้หรือ SARGable หรืออะไรก็ตามที่เด็ก ๆ เท่ห์ ๆ กำลังเรียกมันว่าวันนี้:CREATE INDEX ON brands USING gin ( attributes );

ความแตกต่างที่นี่คือความง่ายในการค้นหา ..

มอบเสื้อผ้ายี่ห้อ Brand2 ให้ฉันทั้งหมด

SELECT * FROM clothes WHERE brand_id = 2;

ให้เสื้อผ้าทั้งหมดที่มีคุณสมบัติ: ขนาด

SELECT * FROM clothes WHERE attributes ? 'size';

แล้วอันอื่นล่ะ ..

ให้เสื้อผ้าและคุณลักษณะสำหรับเสื้อผ้าที่มีขนาดใหญ่ทั้งหมด

SELECT * FROM clothes WHERE attributes->>'size' = 'large';

ดังนั้นหากฉันเข้าใจอย่างถูกต้องส่วนสำคัญของสิ่งที่คุณพูดคือหากมีความสัมพันธ์ระหว่างแบรนด์และคุณลักษณะ (เช่นมีความถูกต้องหรือไม่) จากนั้นโซลูชันของ McNets จะเป็นที่ต้องการ (แต่คำถามจะแพงกว่าหรือช้ากว่า) ในทางตรงกันข้ามหากความสัมพันธ์นี้ไม่สำคัญ / "ad-hoc" มากกว่านี้ก็อาจจะต้องการโซลูชันของคุณ คุณช่วยอธิบายเพิ่มเติมเล็กน้อยได้จากสิ่งที่คุณตั้งใจเมื่อคุณพูดว่า "ฉันไม่เคยใช้กับ PostgreSQL เลย" ดูเหมือนจะไม่มีคำอธิบายความคิดเห็นนั้น ขออภัยสำหรับคำถามทั้งหมด !! ฉันขอบคุณคำตอบของคุณจริงๆ :)
youngrrrr

1
มีความสัมพันธ์ชัดเจนคำถามเดียวคือคุณต้องจัดการกับมันมากแค่ไหน หากฉันใช้คำที่คลุมเครือเช่นคุณสมบัติ , คุณลักษณะหรือชอบผมมักจะหมายถึงจะบอกว่ามันสวยมาก Ad-hoc หรือไม่มีโครงสร้างสูง สำหรับสิ่งนั้น JSONB นั้นดีกว่าเพราะมันง่ายกว่า คุณอาจพบโพสต์นี้ให้ข้อมูลcoussej.github.io/2016/01/14/ …
Evan Carroll

-1

ทางออกที่ง่ายอย่างหนึ่งคือการรวมแอตทริบิวต์ที่เป็นไปได้ทั้งหมดไว้เป็นคอลัมน์บนตารางเสื้อผ้าหลักและทำให้คอลัมน์เฉพาะทั้งหมดเป็นโมฆะ โซลูชันนี้แบ่งการทำให้เป็นมาตรฐานของฐานข้อมูล แต่ใช้งานง่ายมาก


ฉันคิดว่า .. ฉันมีความคิดเกี่ยวกับสิ่งที่คุณกำลังพูด แต่อาจเป็นประโยชน์ในการรวมรายละเอียดเพิ่มเติมและอาจเป็นตัวอย่างได้เช่นกัน
youngrrrr
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.