개인적 으로이 목적을 위해 다중 테이블 스키마를 사용하는 것을 좋아하지 않습니다.
- 무결성을 보장하기가 어렵습니다.
- 유지하기가 어렵습니다.
- 결과를 필터링하기가 어렵습니다.
dbfiddle sample을 설정했습니다 .
내 제안 된 테이블 스키마 :
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로 필터링 할 수 있다는 것입니다.
Size 속성을 가진 모든 옷을 줘
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이 배열을 허용하지 않는 한 동일한 테이블 스키마를 유지하면서 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