동일한 테이블에서 두 행을 관련시키는 방법


11

행이 서로 관련 될 수있는 테이블이 있으며 논리적으로 관계는 두 행 사이에 기본적으로 방향이 없습니다. (그리고 궁금한 점이 있다면, 이것은 실제로 하나의 테이블이어야합니다. 이것은 정확히 동일한 논리적 엔티티 / 유형의 두 가지입니다.) 이것을 나타내는 몇 가지 방법을 생각할 수 있습니다.

  1. 관계와 그 반대를 저장하십시오
  2. 관계를 한 방법으로 저장하고 데이터베이스를 다른 방법으로 저장하지 못하게하고 FK와 반대 순서로 두 개의 인덱스를 갖습니다 (하나의 인덱스는 PK 인덱스 임)
  3. 관계를 두 가지 색인으로 한 방향으로 저장하고 두 번째 색인을 삽입하십시오 (유쾌한 소리지만 완벽 함)
  4. 일종의 그룹화 테이블을 작성하고 원래 테이블에 FK를 지정하십시오. (많은 질문을 제기합니다. 그룹화 테이블에는 숫자 만 있습니다. 왜 테이블이 있습니까? FK를 NULL로 설정하거나 단일 행이 연결된 그룹이 있습니까?)

이러한 방식의 주요 장단점은 무엇이며, 내가 생각하지 못한 방식이 있습니까?

http://sqlfiddle.com/#!12/7ee1a/1/0 과 함께 사용할 SQLFiddle이 있습니다 . (이것이 내가 사용하는 것이기 때문에 PostgreSQL이 될 수 있지만이 질문은 PostgreSQL에만 국한되지 않는다고 생각합니다.) 현재 관계와 반대를 모두 예를 들어 저장합니다.


주어진 가치가 둘 이상의 서로 관련 될 수 있습니까? 주어진 가치가 항상 다른 것과 관련이 있습니까? 그들은 동일한 다른 공통 데이터를 공유합니까?
Philᵀᴹ

예, 둘 이상의 다른 행과 관련 될 수 있습니다. 아니요, 항상 다른 행과 관련이있는 것은 아닙니다. 공통 데이터가있을 필요는 없습니다. 감사합니다.
jpmc26

죄송합니다. @ 필을 잊었다. 또한 나에게 일어난 잠재적 구조를 추가하기 위해 편집했다.
jpmc26

답변:


9

당신이 디자인 한 것이 좋습니다. 추가해야 할 것은 관계를 무 방향으로 만드는 제약입니다. 따라서 행을 추가 (1,5)하지 않으면 행을 가질 수 없습니다 (5,1).

이 수행 할 수 있습니다 * 다리 테이블에 자기 참조 제약과 함께.

* : Postgres, Oracle, DB2 및 SQL 표준에 설명 된대로 외래 키 제약 조건을 구현 한 모든 DBMS에서 수행 할 수 있습니다 (예 : 트랜잭션이 끝날 때 확인 됨). 진술의 끝에 그들을 확인하는 서버 와이 구성은 여전히 ​​작동합니다. 당신은 MySQL의에서이 작업을 수행 할 수 있기 때문에 "이노 검사 UNIQUE 및 FOREIGN KEY 제약 행 단위" .

따라서 Postgres에서 다음은 요구 사항과 일치합니다.

CREATE TABLE x
(
  x_id SERIAL NOT NULL PRIMARY KEY,
  data VARCHAR(10) NOT NULL
);

CREATE TABLE bridge_x
(
  x_id1 INTEGER NOT NULL REFERENCES x (x_id),
  x_id2 INTEGER NOT NULL REFERENCES x (x_id),
  PRIMARY KEY(x_id1, x_id2),
  CONSTRAINT x_x_directionless
    FOREIGN KEY (x_id2, x_id1)
    REFERENCES bridge_x (x_id1, x_id2)
);

테스트 대상 : SQL-Fiddle

행을 추가하려고하면 (1,5):

INSERT INTO bridge_x VALUES
(1,5) ;

다음과 같이 실패합니다.

오류 : "bridge_x"테이블의 삽입 또는 업데이트가 외래 키 제약 조건 "x_x_directionless"를 위반합니다
. 세부 정보 : Key (x_id2, x_id1) = (5, 1)이 "bridge_x"테이블에 없습니다. :
INSERT INTO bridge_x VALUES (1,5)

또한 행 CHECK을 금지하려는 경우 제약 조건을 추가 할 수 있습니다 (y,y).

ALTER TABLE bridge_x
  ADD CONSTRAINT x_x_self_referencing_items_not_allowed
    CHECK (x_id1 <> x_id2) ;

언급 한대로 열에 하위 ID를 입력 x_id1하고 상위 ID를 강제로 지정하여 관계의 한 방향 (한 행에 두 개가 아닌)을 저장하는 것과 같이 이것을 구현하는 다른 방법이 있습니다 x_id2. 구현하기가 더 쉬워 보이지만 나중에는 더 복잡한 쿼리가 발생합니다.

CREATE TABLE bridge_x
(
  x_id1 INTEGER NOT NULL REFERENCES x (x_id),
  x_id2 INTEGER NOT NULL REFERENCES x (x_id),
  PRIMARY KEY(x_id1, x_id2),
  CONSTRAINT x_x_directionless
    CHECK (x_id1 <= x_id2)                       -- or "<" to forbid `(y,y)` rows
);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.