문제

모든 종류의 제품을 저장할 수 있는 애플리케이션이 있다고 가정해 보겠습니다.각 제품에는 최소한 ID 그리고 Name 그러나 다른 모든 속성은 사용자가 직접 정의할 수 있습니다.

  1. 예:그는 제품 그룹을 만들 수 있었습니다 아이팟 속성을 포함하는 용량 그리고 세대
  2. 예:그는 제품 그룹을 만들 수 있었습니다 티셔츠 속성으로 크기 그리고 색상
  3. 제품의 정의와 구체적인 제품 자체를 저장해야 합니다.
  4. 우리는 제품 속성별로 쉽게 집계(GROUP BY)할 수 있도록 하려고 합니다.예:각 세대의 iPod에 대한 총 용량 합계를 선택하세요.
  5. 솔루션에는 스키마 변경이 필요하지 않아야 합니다(Bill Karwin의 입력으로 인해 요구 사항이 추가되었습니다. 그의 답변도 참조하세요!)

위의 요구 사항과 관련하여 스키마를 어떻게 모델링하시겠습니까?

메모: 요구사항 4.중요하다!

접근 방식에 기여하고 토론해 주신 모든 분들께 감사드립니다.나는 과거에 이 문제에 대한 몇 가지 해결책을 보았지만 그 중 어느 것도 쉽게 그룹화할 수 없었습니다. :(

도움이 되었습니까?

해결책

"색상"에 어떤 집계 연산자를 사용할 예정이므로 그룹화가 쉽지 않을 것입니다.사례 2에서는 요구 사항 4를 사용할 수 없습니다.

어쨌든 집계는 데이터 유형의 변화 때문에 어려울 뿐이며 사과와 오렌지를 추가하는 것이 결코 의미가 없다는 것을 알고 보다 유형 안전한 방식으로 접근함으로써 완화될 수 있습니다.

이것은 고전적인 EAV 모델이며 신중하게 설계된 데이터베이스에 자리잡고 있습니다.좀 더 유형을 안전하게 만들기 위해 단일 자유 형식 varchar 열 대신 유형이 안전한 테이블에 값이 저장되는 경우를 보았습니다.

값 대신:

EntityID int
,AttributeID int
,Value varchar(255)

여러 개의 테이블이 있습니다.

EntityID int
,AttributeID int
,ValueMoney money

EntityID int
,AttributeID int
,ValueInt int

etc.

그런 다음 세대당 iPod 용량을 확인하려면 다음 단계를 따르세요.

SELECT vG.ValueVarChar AS Generation, SUM(vC.ValueDecimal) AS TotalCapacity
FROM Products AS p
INNER JOIN Attributes AS aG
    ON aG.AttributeName = 'generation'
INNER JOIN ValueVarChar AS vG
    ON vG.EntityID = p.ProductID
    AND vG.AttributeID = aG.AttributeID
INNER JOIN Attributes AS aC
    ON aC.AttributeName = 'capacity'
INNER JOIN ValueDecimal AS vC
    ON vC.EntityID = p.ProductID
    AND vC.AttributeID = aC.AttributeID
GROUP BY vG.ValueVarChar

다른 팁

나는 둘 중 하나를 추천하고 싶습니다 콘크리트 테이블 상속 아니면 그 클래스 테이블 상속 디자인.두 디자인 모두 네 가지 기준을 모두 충족합니다.

콘크리트 테이블 상속에서:

  1. 아이팟은 테이블에 저장됩니다 product_ipods 기둥이 있는 ID, Name, Capacity, Generation.
  2. 티셔츠는 테이블에 보관되어 있습니다 product_tshirts 기둥이 있는 ID, Name, Size, Color.
  3. 구체적인 제품 유형의 정의는 다음의 메타데이터(테이블 정의)에 있습니다. product_ipods 그리고 product_tshirts.
  4. SELECT SUM(Capacity) FROM product_ipods GROUP BY Generation;

클래스 테이블 상속에서:

  1. 일반 제품 속성은 테이블에 저장됩니다. Products 기둥이 있는 ID, Name.

    아이팟은 테이블에 저장됩니다 product_ipods 기둥이 있는 product_id (외부 키 Products.ID), Capacity, Generation.

  2. 티셔츠는 테이블에 보관되어 있습니다 product_tshirts 기둥이 있는 product_id (외부 키 Products.ID), Size, Color.
  3. 구체적인 제품 유형의 정의는 다음의 메타데이터(테이블 정의)에 있습니다. products, product_ipods, 그리고 product_tshirts.
  4. SELECT SUM(Capacity) FROM product_ipods GROUP BY Generation;

"에 대한 내 답변도 참조하세요.제품 테이블, 다양한 종류의 제품, 각 제품에는 많은 매개변수가 있습니다." 여기서는 귀하가 설명하는 문제 유형에 대한 몇 가지 솔루션을 설명합니다.저도 자세히 설명드리지만 EAV가 깨진 디자인인 이유.


@dcolumbus의 댓글:

CTI를 사용하면 product_ipods의 각 행이 자체 가격에 따라 변형됩니까?

가격 열이 products 모든 유형의 제품에 가격이 있는 경우 테이블입니다.CTI를 사용하면 제품 유형 테이블에는 일반적으로 해당 제품 유형에만 관련된 속성에 대한 열만 있습니다.모든 제품 유형에 공통적인 속성은 상위 테이블의 열을 가져옵니다.

또한 주문 품목을 저장할 때 product_ipods의 행을 품목으로 저장하시겠습니까?

라인 항목 테이블에 제품 ID를 저장합니다. 이 ID는 두 항목 모두에서 동일한 값이어야 합니다. products 테이블과 product_ipods 테이블.


@dcolumbus의 댓글:

그것은 나에게 너무 중복되는 것 같습니다 ...이 시나리오에서는 하위 테이블의 요점이 표시되지 않습니다.그러나 하위 테이블이 의미가 있다고 하더라도 연결은 무엇입니까? id?

하위 테이블의 요점은 다른 모든 제품 유형에 필요하지 않은 열을 저장하는 것입니다.

연결 ID는 자동 증가 숫자일 수 있습니다.하위 유형 테이블은 슈퍼 테이블에서 생성된 값만 사용할 수 있으므로 자체 ID를 자동 증가시킬 필요가 없습니다.

CREATE TABLE products (
  product_id INT AUTO_INCREMENT PRIMARY KEY,
  sku VARCHAR(30) NOT NULL,
  name VARCHAR(100) NOT NULL,
  price NUMERIC(9,2) NOT NULL
);

CREATE TABLE product_ipods (
  product_id INT PRIMARY KEY,
  size TINYINT DEFAULT 16,
  color VARCHAR(10) DEFAULT 'silver',
  FOREIGN KEY (product_id) REFERENCES products(product_id)
);

INSERT INTO products (sku, name, price) VALUES ('IPODS1C1', 'iPod Touch', 229.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 16, 'silver');
INSERT INTO products (sku, name, price) VALUES ('IPODS1C2', 'iPod Touch', 229.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 16, 'black');
INSERT INTO products (sku, name, price) VALUES ('IPODS1C3', 'iPod Touch', 229.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 16, 'red');
INSERT INTO products (sku, name, price) VALUES ('IPODS2C1', 'iPod Touch', 299.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 32, 'silver');
INSERT INTO products (sku, name, price) VALUES ('IPODS2C2', 'iPod Touch', 299.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 32, 'silver');
INSERT INTO products (sku, name, price) VALUES ('IPODS2C3', 'iPod Touch', 299.00);
INSERT INTO product_ipods VALUES (LAST_INSERT_ID(), 32, 'red');

사용자가 작업을 수행할 때 열을 추가/제거하여 신제품에 대한 CREATE TABLE 및 ALTER TABLE을 수행합니다.스키마를 사용하여 각 제품의 속성을 알아보세요.이는 네 가지 요구 사항을 모두 충족합니다.

또한 다른 테이블 이름을 저장하거나 테이블의 sysobject에 대해 쿼리할 수 있는 항목을 테이블 앞에 붙일 테이블이 필요합니다.

select [name] from sysobjects where [name] like 'product_%' AND xtype='U'

제품 카탈로그 데이터베이스를 디자인하려는 것 같습니다.

나는 이 접근법을 추천한다. http://edocs.bea.com/wlp/docs40/catalog/schemcat.htm

EAV의 대안으로 BLOB 패턴을 사용할 때 발생하는 문제를 어떻게 극복할 수 있는지 궁금합니다.예를 들어 tihis와 같은 JSON의 문자열로 엔터티의 모든 사용자 정의 필드를 하나의 필드에 저장할 수 있다고 가정해 보겠습니다.{customField1:값1, 맞춤 필드2:value2,…, Customfieldn :값N}

다음 문제를 극복하는 방법:1.예를 들어 custField1 = value1 AND customField2 = value2 조건을 사용하여 엔터티를 찾기 위해 별도의 사용자 정의 필드로 검색하는 방법은 무엇입니까?2.데이터 무결성을 유지하는 방법(예: 엔터티에 대한 사용자 정의 필드를 삭제하는 경우) 엔터티에서 이러한 사용자 정의 필드의 모든 값을 삭제하는 방법입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top