다른 속성 세트를 가질 수있는 엔티티 유형을 모델링하는 방법은 무엇입니까?


11

UsersItems 사이의 일대 다 (1 : M) 관계로 데이터베이스를 다시 작성하는 데 문제가 있습니다.

이것은 매우 간단합니다. 그러나 각 항목 은 특정 범주 (예 : Car , Boat 또는 Plane )에 속하며 각 범주 에는 다음과 같은 특정 수의 속성이 있습니다.

Car 구조:

+----+--------------+--------------+
| PK | Attribute #1 | Attribute #2 |
+----+--------------+--------------+

Boat 구조:

+----+--------------+--------------+--------------+
| PK | Attribute #1 | Attribute #2 | Attribute #3 |
+----+--------------+--------------+--------------+

Plane 구조:

+----+--------------+--------------+--------------+--------------+
| PK | Attribute #1 | Attribute #2 | Attribute #3 | Attribute #4 |
+----+--------------+--------------+--------------+--------------+

속성 (열)의 수가 다양하기 때문에 처음에는 각 Category 에 대해 하나의 별도 테이블을 만드는 것이 좋습니다. 따라서 여러 개의 NULL을 피하고 인덱싱을 더 잘 사용합니다.

처음에는 훌륭해 보였지만 데이터베이스 관리자로서의 겸손한 경험으로는 외래 키를 만들 때 데이터베이스를 통해 항목범주 사이의 관계를 만드는 방법을 찾을 수 없었습니다. 테이블 이름과 열

결국, 나는 모든 데이터를 저장하는 견고한 구조를 원하지만 사용자 가 가질 수있는 모든 항목 의 모든 속성을 하나의 쿼리 로 나열하는 모든 수단을 갖추고 있습니다.

서버 측 언어로 동적 쿼리하드 코딩 할 수는 있지만 이것이 잘못되고 최적이 아니라고 생각합니다.

추가 정보

이들은 MDCCL 의견에 대한 나의 답변입니다.

1. 비즈니스 컨텍스트에 3 개 (예 : 자동차 , 보트비행기 ) 이상의 관심 항목 항목이 몇 개 있습니까?

실제로 매우 간단합니다. 총 5 개의 범주 만 있습니다 .

2. 동일한 품목이 항상 동일한 사용자에게 속합니까 (즉, 주어진 품목 이 특정 사용자 에게 "지정된" 후에는 변경할 수 없음)?

아니요, 그들은 변할 수 있습니다. 질문의 가상 시나리오에서 사용자 A가 사용자 B의 항목 # 1을 판매하는 것과 같으 므로 소유권을 반영해야합니다.

3. 일부 또는 모든 카테고리 가 공유하는 속성이 있습니까?

공유되지는 않지만 메모리에서 모든 카테고리 에 3 개 이상의 속성이 있음을 알 수 있습니다 .

4. 사용자항목 간의 관계의 카디널리티가 일대 다 (1 : M) 대신 다 대다 (M : N) 일 가능성이 있습니까? 예를 들어, 비즈니스 규칙을 다음의 경우 : A User owns zero-one-or-many ItemsAn Item is owned by one-to-many Users

아니요, 아이템 은 물리적 객체를 설명 하기 때문 입니다. 사용자 는 각각 고유 한 GUID v4로 식별 된 가상 사본을 갖게됩니다.

5. 질문 의견 중 하나에 대한 다음 응답에 대해 :

"질문의 가상 시나리오에서 사용자 A가 사용자 B에 대한 항목 # 1을 판매하는 것과 같으 므로 소유권을 반영해야합니다."

말하자면 항목 소유권 진화를 추적 할 계획 인 것 같습니다 . 이런 식으로 이러한 현상에 대해 어떤 속성을 저장 하시겠습니까? 특정 항목소유자 인 특정 사용자 를 나타내는 속성 만 수정 합니까?

아니 정말. 소유권이 변경 될 수 있습니다,하지만 난 이전의 트랙을 보관할 필요가없는 소유자 .

답변:


18

고려중인 비즈니스 환경에 대한 설명에 따르면, 항목 (수퍼 타입)과 각 범주 (예 : Car , Boat and Plane) (알 수없는 두 개 이상)를 포함 하는 수퍼 타입 ​​하위 유형 구조가 있습니다. 하위 유형 —.

이러한 시나리오를 관리하기 위해 수행 할 방법을 아래에서 자세히 설명하겠습니다.

비즈니스 규칙

관련 개념 스키마를 설명 하기 위해 지금까지 결정된 가장 중요한 비즈니스 규칙 중 일부 (분석을 세 가지 범주 로만 제한하고 가능한 한 간략하게 유지)는 다음과 같이 공식화 할 수 있습니다.

  • 사용자가 제로 일 또는 일대 다 소유 한 항목
  • 항목은 정확히-하나가 소유하고 사용자 의 특정 순간에
  • 항목 일대에 의해 소유 될 수 있습니다 사용자 시간에 서로 다른 지점에서
  • 항목은 정확히 하나 개에 의해 분류 카테고리
  • 항목 , 항상이다
    • 중 하나
    • 또는 보트
    • 또는 비행기

예시적인 IDEF1X 다이어그램

그림 1 은 이전 공식을 그룹화하기 위해 생성 한 IDEF1X 1 다이어그램과 관련이있는 다른 비즈니스 규칙을 보여줍니다.

그림 1-항목 및 범주 수퍼 타입 ​​하위 유형 구조

수퍼 타입

한편,에 항목 , 상위 유형, 선물 속성 모두에 공통 또는 속성 카테고리 , 즉,

  • CategoryCode은 외국 키 (FK)를 참조과 -specified Category.CategoryCode 서브 타입 등 및 기능을 판별 즉, 그것은 정확한 표시 카테고리 주어진있는 하위 유형의 항목 connected-이어야합니다,
  • OwnerId —User.UserId를 가리키는 FK로 구분되었지만 , 특별한 의미를보다 정확하게 반영하기 위해 역할 이름 2 를 할당했습니다.
  • ,
  • ,
  • 바즈
  • CreatedDateTime 입니다.

하위 유형

한편, 속성 모든 특정에 해당하는 것으로 분류 , 즉,

  • QuxCorge ;
  • Grault , GarplyPlugh ;
  • Xyzzy , Thud , WibbleFlob ;

해당 하위 유형 상자에 표시됩니다.

식별자

그런 다음 Item.ItemId PRIMARY KEY (PK)는 역할 이름이 다른 하위 유형으로 3 을 마이그레이션했습니다 .

  • CarId ,
  • BoatId
  • PlaneId .

상호 배타적 협회

도시 된 바와 같이, (a) 각각의 수퍼 타입 ​​발생과 (b) 상보적인 서브 타입 인스턴스간에 카디널리티 일대일 (1 : 1) 의 연관 또는 관계가있다 .

전용 하위 유형의 기호가 서브 타입, 즉, 상호 배타적 인 사실을 묘사하고, 구체적인 항목의 발생은 단 하나의 하위 유형 인스턴스에 의해 보충 할 수 있습니다 중 하나 자동차 , 또는 하나의 평면 , 또는 1 보트 (결코 두 이상).

, 실제 교단이 질문에 공급되지 않은 것처럼 나는 엔터티 형식의 속성 중 일부 권리를 부여하는 고전적인 자리 표시 자 이름을 고용했다.

설명 논리 레벨 레이아웃

결과적으로 설명 적 논리 설계를 논의하기 위해 위에서 표시되고 설명 된 IDEF1X 다이어그램을 기반으로 다음과 같은 SQL-DDL 문을 도출했습니다.

-- 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, BoatIdPlaneId해당 테이블의 PK와 같은 제약, FK 제약로서 개념적 레벨 일대일 관계를 나타내는 도움 § 것을 가리키고 ItemId의 PK로 구속 컬럼 Item테이블. 이는 실제 "쌍"에서 상위 유형과 하위 유형 행이 모두 동일한 PK 값으로 식별됨을 나타냅니다. 따라서 언급하는 것이 이상합니다

  • (a) 시스템 제어 대리 값을 보유하기 위해 여분의 열을 첨부하는 것 ~ (b) 하위 유형을 나타내는 테이블은 (c) 전적으로 불필요한 것 입니다.

§ 주석에서 언급 한 상황 (특히 FOREIGN) KEY 제약 조건 정의와 관련된 문제와 오류를 방지하려면 다음 표에 설명 된대로 현재 사용중인 여러 테이블간에 존재하는 종속성 을 고려해야합니다 . 이 SQL Fiddle 에서도 제공 한 설명 DDL 구조에서 테이블의 선언 순서

예를 들어, AUTO_INCREMENT 속성이있는 추가 열 을 MySQL 기반의 데이터베이스 테이블에 추가합니다.

무결성 및 일관성 고려 사항

비즈니스 환경에서 (1) 각 "슈퍼 타입"행이 항상 해당 "서브 타입"대응 항목으로 보완되는지 확인하고 (2) "subtype"행은 "supertype"행의 "판별 자"열에 포함 된 값과 호환됩니다.

그러한 상황을 선언 적인 방식으로 시행하는 것은 매우 우아 하지만 불행히도 주요 SQL 플랫폼 중 어느 것도 내가 아는 한 그렇게하는 적절한 메커니즘을 제공하지 못했습니다. 따라서 ACID TRANSACTIONS 내에서 절차 코드 를 사용하면 이러한 조건이 항상 데이터베이스에서 충족되도록하는 것이 매우 편리합니다. 다른 옵션은 TRIGGERS를 사용하는 것이지만, 말을하기 어려운 것을 만드는 경향이 있습니다.

유용한 견해 선언

위에서 설명한 것과 같은 논리적 디자인을 가지면 하나 이상의 뷰, 즉 둘 이상의 관련 기본 테이블에 속하는 열을 포함하는 파생 테이블 을 만드는 것이 매우 실용적 입니다. 이러한 방식으로, 예를 들어 "결합 된"정보를 검색 할 때마다 모든 JOIN을 작성하지 않고도 해당 뷰에서 직접 SELECT를 수행 할 수 있습니다.

샘플 데이터

이와 관련하여 기본 테이블이 아래에 표시된 샘플 데이터로 "채워진다"고 가정합니다.

--

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, CarUserProfile:

--

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;

--

물론, 비슷한 접근 방식은 당신이뿐만 아니라 "전체"선택할 수 있도록 올 수 있습니다 BoatPlane정보 똑바로 하나 개의 테이블 (a는 이러한 경우에, 하나의 파생).

당신 -if 그 다음 VIEW 정의와 결과 세트 -에서 NULL 마크의 존재에 대해 신경 쓰지 않는 한, 당신이 할 수있는, 예를 들어, "수집"테이블의 열 Item, Car, Boat, PlaneUserProfile:

--

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에 통합되어 "작동 중"으로 관찰 될 수 있습니다.

데이터 조작 : 응용 프로그램 코드 및 열 별명

응용 프로그램 코드 (“서버 측 특정 코드”의 의미 인 경우) 및 열 별칭의 사용은 다음 주석에서 제기 한 다른 중요한 사항입니다.

  • 서버 측 특정 코드에 대한 해결 방법 [조인] 문제를 해결했지만 실제로는 그렇게하고 싶지 않습니다. 모든 열에 별칭을 추가하면 "스트레스"가 될 수 있습니다.

  • 잘 설명했습니다. 대단히 감사합니다. 그러나 의심 한 것처럼 일부 열과의 유사성으로 인해 모든 데이터를 나열 할 때 결과 집합을 조작해야합니다. 여러 별칭을 사용하여 명령문을 깨끗하게 유지하고 싶지 않기 때문입니다.

애플리케이션 프로그램 코드를 사용하는 것은 결과 세트의 프리젠 테이션 (또는 그래픽) 기능을 처리하는 데 매우 적합한 자원이지만 행 단위로 데이터 검색을 피하는 것이 실행 속도 문제를 방지하는 데 가장 중요하다는 것을 나타내는 것이 좋습니다. 시스템의 동작을 최적화 할 수 있도록 SQL 플랫폼의 (정확하게) 설정된 엔진이 제공하는 강력한 데이터 조작 도구를 사용하여 관련 데이터 세트를 가져 오는 것이 목표입니다.

또한 별명을 사용하여 특정 범위 내에서 하나 이상의 열 이름을 바꾸는 것은 스트레스로 보일 수 있지만 개인적으로 (i) 상황화 및 (ii) 관련 의미의도를 명확하게하는 데 도움이되는 매우 강력한 도구라고 생각합니다. 열; 그러므로, 이것은 관심있는 데이터의 조작과 관련하여 철저히 숙고해야 할 측면입니다.

비슷한 시나리오

상호 배타적 인 하위 유형과의 수퍼 유형 하위 유형 연결을 포함하는 다른 두 가지 경우에 대한 내 일련의 게시물게시물 그룹에 대한 도움을 얻을 수도 있습니다 .

또한 하위 유형 이이 (최신) 답변 에서 상호 배타적이지 않은 수퍼 유형 하위 유형 클러스터와 관련된 비즈니스 환경에 대한 솔루션을 제안했습니다 .


미주

1 정보 모델링을위한 통합 정의 ( IDEF1X )는1993 년 12 월 미국 표준 기술 연구소 (NIST)에서 표준 으로 확립 한 권장 데이터 모델링 기술입니다. 그것은 단단하게 이론적 인 작품의 일부는 저술의 (a)를 기반으로 유일한 발신자 관계형 모델 즉, 박사 EF 커드 ; (b) PP Chen 박사에 의해 개발 된 실체 관계 관점 ; 또한 (c) Robert G. Brown이 만든 논리적 데이터베이스 디자인 기법.

2 IDEF1X에서 역할 이름 은 해당 엔터티 유형의 범위 내에서 유지되는 의미를 표현하기 위해 FK 속성 (또는 특성)에 할당 된 고유 레이블입니다.

3 IDEF1X 표준은 키 마이그레이션 을 "부모 또는 일반 엔터티의 기본 키를 자식 또는 범주 엔터티에 외래 키로 배치하는 모델링 프로세스"로정의합니다.


1
문의 내용을 잘 모르겠지만 DDL 레이아웃에 설명 된대로 Item표에 CategoryCode열이 포함되어 있습니다. “무결성 및 일관성 고려 사항”섹션에서 언급 한 바와 같이
MDCCL

1
비즈니스 환경에서 (1) 각 "슈퍼 타입"행이 항상 해당 "서브 타입"대응 항목으로 보완되는지 확인하고 (2) "subtype"행은 "supertype"행의 "판별 자"열에 포함 된 값과 호환됩니다.
MDCCL

1
그러한 상황을 선언적인 방식으로 시행하는 것은 매우 우아하지만 불행히도 주요 SQL 플랫폼 중 어느 것도 내가 아는 한 그렇게하는 적절한 메커니즘을 제공하지 못했습니다. 따라서 ACID TRANSACTIONS 내에서 절차 코드를 사용하면 이러한 조건이 항상 데이터베이스에서 충족되도록하는 것이 매우 편리합니다. 다른 옵션은 TRIGGERS를 사용하는 것이지만, 말을하기 어려운 것을 만드는 경향이 있습니다.
MDCCL

1
문제의 핵심은 SQL 구현 (MySQL 방언 포함)이 ASSERTIONS, 절차 적 접근 (TRANSACTIONS 또는 TRIGGERS)에 의지하지 않거나 중복 된 방식으로 작업 공간을 피하는 데 도움이되는 강력하고 우아한 선언 도구를 올바르게 지원하지 않는다는 것입니다 예를 들어, CategoryColumn서브 타입을 나타내는 테이블에서 불필요하게 반복 한다 (논리적 [예, 변형 이상] 및 물리적 추상화 레벨 (예를 들어, 여분의 인덱스, 더 큰 구조 등)에서의 모든 의미와 함께).
MDCCL

2
데이터베이스 관리 시스템 공급 업체 / 개발자 중 한 명이 ASSERTIONS (이 작업에 적합한 도구)를 제공 할 때까지 (a) 절차 적 접근 방식 (트랜잭션 또는 트리거)은 (b) 중복 작업 과정보다 (b) 개인적으로 권장하지 않는 가능성입니다. 물론 DBA는 관련 데이터베이스에서 실행할 수있는 유효한 데이터 조작 작업에 대한 권한을 신중하게 관리해야하므로 데이터 무결성을 유지 관리하는 데 많은 도움이됩니다.
MDCCL

0

메인 테이블 제품을 호출 할 수 있습니다. 공유 속성을 호스팅합니다. 그런 다음 Car 테이블, Plane 테이블 및 Boat 테이블이 있다고 가정 해 봅시다. 이 세 테이블에는 Product 테이블의 ID 행에 FK 제약 조건이있는 ProductID 키가 있습니다. 모두 원한다면 가입하십시오. 자동차 만 원한다면 왼쪽 제품과 자동차를 조인하십시오 (또는 오른쪽 제품과 자동차를 조인하지만 항상 왼쪽 조인을 사용하는 것을 선호합니다).

이것을 계층 적 데이터 모델이라고합니다. 서브 테이블 수가 적 으면 긴 테이블 (수백만 개의 제품)에서 의미가있을 수 있습니다.


그런 다음 제품으로 사용자를 가입 시키나요?
user5613506

1
일반적으로 제품 목록을 프런트 엔드로 반환 할 때는 사용자 정보가 필요하지 않으며 제품 정보가 필요합니다. 사용자 및 제품에 가입하고 반환 된 각 제품 행에 대해 동일한 사용자 정보를 반환하는 것은 의미가 없습니다. 따라서 먼저 products 테이블과 해당 하위 테이블 (Car, Boat ...)을 결합하여 제품 유형별로 필터링 한 다음 WHERE 절을 사용하여 사용자별로 필터링합니다. 일반적으로 Products 테이블에 OwnerID가 있어야합니다 (User 테이블의 ID 열에 FK). 따라서 WHERE Owner = [Request.User]를 추가합니다.
neManiac
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.