2010-03-11 4 views
5

"ID"(고유하지 않은 반복적 인) 열이 여러 테이블에 걸쳐있을 수 있습니까? 예를 들어 책과 저자라는 두 개의 표가 있다고 가정 해 보겠습니다.SQL Server에서 ID 필드를 여러 테이블로 확장 할 수 있습니까?

Authors 
    AuthorID 
    AuthorName 
Books 
    BookID 
    BookTitle 

BookID 열과 AuthorID 열은 ID 열입니다. ID 부분이 두 열 모두에 걸쳐 있기를 원합니다. 따라서 값이 123 인 AuthorID가 있으면 값이 123 인 BookID를 사용할 수 없으며 반대의 경우도 마찬가지입니다.

나는 그것이 의미가 있기를 바랍니다.

이것이 가능합니까?

감사합니다.

왜 이것을하고 싶습니까? 나는 APS.NET MVC 애플 리케이션을 쓰고있다. 나는 코멘트 섹션을 만들고 있습니다. 저자는 의견을 가질 수 있습니다. 책에 댓글이 달릴 수 있습니다. 엔티티 ID (서적 ID 또는 작성자 ID)를 조치에 전달하고 모든 해당 주석을 풀 수있는 조치를 원합니다. 그 행동은 그것이 책이든 저자이든간에 상관하지 않습니다. 합리적인 소리?

답변

2

짧은 대답은 : 아니오, 적어도 (2008 년까지는 MS SQL Server에서) 그렇게 할 수 없습니다.

"CommentableEntity"라는 새 테이블을 만들고 거기에 ID 열을 꽂은 다음 Authors 및 Books에서 외래 키를 정의하여 상위 테이블로 참조 할 수 있습니다. 그런 다음 여러 트릭 중 하나를 수행하여 주어진 ID 값이 두 테이블 모두에 할당되지 않았습니다 ...그러나 작성한 데이터 모델은 작성자와 책이 관련 데이터 종류라는 것을 암시하기 때문에 실제로는 그렇지 않습니다.

별도의 테이블, 설명, ID 열이있을 수 있으며 작성자와 도서에 CommentId 열을 주차 할 수 있습니다. 그러나 각 책과 저자는 단 한 개의 주석으로 제한됩니다.

내 의견 표에 "CommentorType"과 같은 열을 추가하고 주석 소스 (작성자는 "A", 책은 "B")를 나타내는 플래그를 거기에 넣으십시오. "CommentorId + CommentorType"에 기본 키를 작성하면 충분히 잘 작동합니다. 시스템이 확장됨에 따라 추가 유형의 주석 작성자를 추가하는 것은 간단합니다.

+0

두 개의 다른 테이블에 하나의 외래 키를 지정할 수 없습니다. 플래그가있는 경우에도 유용합니다. –

+0

귀하의 제안 ("나는 CommentorType"을 "Comments"와 같이 열을 추가 할 것입니다.)은 게시하기로 결정하기 전에 제가 향한 경로입니다. 더 쉬운 방법은 없었습니다. 감사합니다. – johnnycakes

+0

댓글에 덧글 유형을 추가하는 것은 좋은 해결책이 아닙니다! 이러지 마! 당신은 그것을 후회할 것입니다! 좋아, 기분이 나아 졌어. 계속 전진 해. –

0

제안 사항 - ComentId, EntityId, isBook과 같은 표를 사용하여 주석을 달아보십시오. isBook은 부울 유형이며 얻을 수있는 곳이 많지 않습니다. 개념은 관계형 관점에서 좋지 않습니다.

5

여러 테이블에 식별 시퀀스를 넣을 수있는 경우에도 주석 테이블은 단일 외래 키의 두 열을 모두 참조 할 수 없습니다.

관계형 데이터베이스 디자인 이론에서이 작업을 수행하는 가장 좋은 방법은 두 개의 주석 테이블을 만드는 것입니다. 하지만 분명히 코드를 다시 사용하는 이유 때문에이를 피하기를 원할 것입니다.

가장 직접적인 실용적인 접근법은 주석 테이블에 두 개의 외래 키 열을 넣고 각각의 설명에 대해 하나의 null과 null을 만들면됩니다.

가장 좋은 방법은 다른 방법입니다. 질문에서 "엔티티 ID"를 참조하십시오. 그래서 엔티티 테이블을 만드십시오! 그렇다면 저자와 서적 및 의견은 모두 을 참조하여 표를 참조 할 수 있습니다.

편집 추가 :

필립 켈리, 레이, 그리고 (내가 생각하는) 북극 모든 중 하나 book_id 또는 author_id 및 참조 할 수있는 entity_id을 추가하여 주석 테이블을 수정 제안 이들 중 어느 것이 참조되는지를 나타내는 일종의 플래그 (각각 char(1), tinyintboolean).

실용적 (데이터 무결성,보고, 효율성 포함) 및 이론적 인 두 가지 이유로 좋은 솔루션이 아닙니다.

가장 중요한 문제는 데이터 무결성 문제입니다. 관계형 데이터베이스 시스템은 항상 자체 데이터의 무결성을 유지 관리해야하며, DB가이를 수행하도록 설계된 자연스럽고 선호되는 방법이 있습니다. 이러한 메커니즘 중 가장 중요한 것 중 하나는 외래 키 시스템입니다. comment.entity_id 열이 book.book_idauthor.author_id을 모두 참조하는 경우이 열에 대해 외래 키를 만들 수 없습니다.

확실히, 참조를 검증하기 위해 DML (삽입, 갱신, 삭제) 저장 프로 시저에 점검을 넣을 수 있지만, 세 테이블 모두에 대한 모든 DML 조작이 관련되므로 신속하게 큰 혼란이 될 것입니다.

그러면 효율성 문제가 발생합니다. comment 테이블에 대해 쿼리가 실행될 때마다 author 또는 book 테이블 또는 두 테이블 모두에 대한 조인이 필요합니다. 쿼리 계획 생성 시스템에는 최적화 할 수있는 외래 키가 없으므로 성능이 저하 될 수 있습니다.

그러면보고에서이 체계에 문제가 있습니다. 모든 보고서 생성 시스템은 이런 종류의 시스템에 문제가있을 것입니다. 전문가 프로그래머에게는 이것이 문제가되지 않지만 모든 사용자 특별 보고서는 event_id이 의미하는 바를 뒤집어 논리를 조롱해야하며 매우 나쁜 거래 일 수 있습니다. 어쩌면이 데이터베이스에서 보고서 생성 도구를 사용하지 않을 것입니다. 그러나 다시 한번, 데이터베이스가 궁극적으로 어디에서 사용될 것인지 아무도 모릅니다. 왜 아무것도 허용하도록 시스템과 협력하지 않습니까?

그러면 이론적 인 문제가 발생합니다.

관계형 데이터베이스 이론에서 각 테이블 ("관계 변수")의 각 행 (즉, "튜플")은 실제 세계에 대한 명제를 나타냅니다. 표를 설계하는 것은 그 명제의 형식을 결정하는 것입니다. 이것이 어떻게 작동하는지 몇 가지 예를 살펴 보겠습니다.

comment (comment_id int, comment_type char(1), entity_id int, 
     user_id int, comment_text nvarchar(max), comment_date datetime) 
/* comment_id identifies a comment (comment_text) that a user (user_id) 
    has made about a book (entity_id if comment_type = 'B') or author 
    (entity_id if comment_type = 'A') at a particular date and 
    time (comment_date).*/ 

는 여기 열 (또는 "속성")을 두 번 의무를하고있다 entity_id라는 것은 분명하다. 다른 열에 대한 참조를 제외하고는 실제로 아무 것도 나타내지 않습니다. 이것은 실행 가능하지만 만족스럽지 않습니다.

comment (comment_id int, book_id int, author_id int, user_id int, 
     comment_text nvarchar(max), comment_date datetime) 
/* comment_id identifies a comment (comment_text) that a user (user_id) 
    has made about a book (book_id if not null) or author (author_id if 
    not null) at a particular date and time (comment_date). */ 

이것은 첫 번째 버전에서 가장 많이 누락 된 외래 키를 구입합니다. 그러나 이것은 하나의 주석이 책과 저자 모두를 지칭 할 수 없다면 (여전히 합리적 일 수 있음), 여전히 만족스럽지 않습니다. Nullable 열은 설계에 문제가 있다는 경고 신호이며 여기서도 마찬가지입니다. 점검 제한 조건은 전혀 언급하지 않는 주석을 허용하거나 책과 작성자가 허용되지 않는 경우 모두를 피하기 위해 필요할 수 있습니다. 이론적 관점에서

(따라서, 내 관점 :)) 명확한 최선의 선택이 :

book_comment (book_comment_id int, book_id int, user_id int, 
       comment_text nvarchar(max), comment_date datetime) 
/* book_comment_id identifies a comment (comment_text) that a 
    user (user_id) has made about a book (book_id) at a particular 
    date and time (comment_date). */ 

author_comment (author_comment_id int, author_id int, user_id int, 
       comment_text nvarchar(max), comment_date datetime) 
/* author_comment_id identifies a comment (comment_text) that a 
    user (user_id) has made about an author (author_id) at a particular 
    date and time (comment_date). */ 

보고 최고의 효율성, 데이터 무결성 및 편의성을 제공 할 것이 마지막 옵션을 선택합니다. 그리고 유일한 비용은 DML 저장 프로 시저가 주석을 올바른 테이블에 넣을 필요가 있다는 것입니다. 이는 큰 의미는 아니며 주석이 어쨌든 언급 한 내용을 알아야하기 때문입니다.

도서 또는 작성자의 모든 댓글을 한 번에 다시 읽으려는 계획이라면 다른 디자인을 재현 한 테이블 상단에 쉽게 만들 수 있습니다 (원하는 경우).

create view comments as 
select 
    book_comment_id as comment_id, 
    book_id as entity_id, 
    comment_text, 
    'B' as comment_type 
from book_comment 
union 
select 
    author_comment_id as comment_id, 
    author_id as entity_id, 
    comment_text, 
    'A' as comment_type 
from author_comment 
+0

안녕하세요. Jeffrey, "의견 유형 ID"를 "Entity ID"와 함께 사용하는 것이 좋지 않다고 생각하는 이유는 무엇입니까? 두 가지 제안이 더 좋은 이유는 무엇입니까? 아직 배우고 있습니다! 감사합니다. – johnnycakes

+0

확인. 나는 답을 편집 할 때 질문에 대답했다. –

+0

이것은 IMO가 정답입니다. 이런 유형의 솔루션에 EAV 구조를 사용하는 것은 잘못된 대답이며보고가보기 싫어 질 것입니다. 다른 테이블을 추가하는 것은 실제로 많은 비용이 들지 않지만, 저자 주석이 나중에 책 주석에없는 속성을 가질 수있는 능력을 포함하여 많은 이점을 제공합니다. – Thomas

0

SQL Server는이 기능을 지원하지 않습니다. id 테이블을 사용하여 자신 만의 롤을 만들 수도 있지만, 그것은 가치가있는 것보다 더 많은 작업이 될 것입니다.

나는 당신의 코멘트 테이블은 다음과 같이 제안 : 댓글이 향후 추가 책, 저자, 또는 뭔가에 속하는지

comment_id int identity 
comment_type tinyint 
entity_id int 

comment_type을 지정합니다. entity_id는 책, 저자 등의 ID입니다. 이 스키마에서는 책 또는 저자 ID가 겹치는 지 여부는 중요하지 않습니다. 당신이 오라클로 전환 할 수있는 경우

가 아니면, 실제로 순서 :

1

를 사용 조 셀코 원하는 테이블의 기본 키에 대해 다음과, 데이터베이스에서 사용자 지정 순서를 사용하는 this 블로그에 제안 , 사용자 정의 순서에서 다음 x 호를 얻기 위해 기본값을 지정하십시오. 이것은 여러 테이블에 걸쳐 신원 필드가 MS SQL에서 가능한 말했다되고

CREATE SEQUENCE Service_Ticket_Seq 
AS INTEGER 
START WITH 1 
INCREMENT BY 1 
MINVALUE 1 
MAXVALUE 100 
CYCLE; 

CREATE TABLE Meats 
(ticket_seq INTEGER DEFAULT NEXT VALUE FOR Service_Ticket_Seq 
     PRIMARY KEY, 
meat_type VARCHAR(15) NOT NULL); 

CREATE TABLE Fish 
(ticket_seq INTEGER DEFAULT NEXT VALUE FOR Service_Ticket_Seq 
     PRIMARY KEY, 
fish_type VARCHAR(15) NOT NULL); 

INSERT INTO Meats (meat_type) VALUES ('pig'); 
INSERT INTO Fish (fish_type) VALUES ('squid'); 

select * from Meats 

select * from Fish 

: 여기

는 자신의 블로그에서 코드 샘플입니다.

+0

예, Microsoft SQL Server 2014에서 작동합니다. –