[SQL] 비 기본 키 외래 키
SQL비 기본 키 외래 키
나는 데이터를 보유하고, 해당 행 중 하나가 다른 테이블에 존재해야하는 테이블이 있습니다. 그래서, 외래 키가 참조 무결성을 유지합니다.
CREATE TABLE table1
(
ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
AnotherID INT NOT NULL,
SomeData VARCHAR(100) NOT NULL
)
CREATE TABLE table2
(
ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
AnotherID INT NOT NULL,
MoreData VARCHAR(30) NOT NULL,
CONSTRAINT fk_table2_table1 FOREIGN KEY (AnotherID) REFERENCES table1 (AnotherID)
)
당신이 볼 수 그러나, 열을 테이블 I 외래 키는 PK 없습니다. 이 외래 키, 아니면이 참조 무결성을 유지하기 위해 더 나은 방법을 만들 수있는 방법이 있습니까?
해결법
-
==============================
1.정말 기본이 아닌 키에 대한 외부 키를 만들려면, 그것의 고유 제한 조건이있는 열 수 있어야한다.
정말 기본이 아닌 키에 대한 외부 키를 만들려면, 그것의 고유 제한 조건이있는 열 수 있어야한다.
온라인에서 :
따라서 귀하의 경우는 AnotherID 독특한 할 경우에는 허용됩니다. 고유 한 제약 조건을 적용 할 수없는 경우에 당신은 운이,하지만 당신이 그것에 대해 생각한다면이 정말 메이크업 감각을한다.
같은 언급되었지만 당신이 후보 키와 완벽하게 좋은 기본 키가있는 경우, 그 이유를 사용하지?
-
==============================
2.다른 사람들이 지적했듯이, 이상적으로, 외래 키는 기본 키 (일반적으로 IDENTITY 열)에 대한 참조로 생성 될 것이다. 그러나, 우리는 이상적인 세계에 거주하지 않는, 때로는 스키마에 "작은"변화는 응용 프로그램 논리에 상당한 파급 효과를 가질 수 있습니다.
다른 사람들이 지적했듯이, 이상적으로, 외래 키는 기본 키 (일반적으로 IDENTITY 열)에 대한 참조로 생성 될 것이다. 그러나, 우리는 이상적인 세계에 거주하지 않는, 때로는 스키마에 "작은"변화는 응용 프로그램 논리에 상당한 파급 효과를 가질 수 있습니다.
SSN을 열 (그리고 바보 기본 키), 또한 SSN 열이 포함 된 청구 테이블 고객 테이블의 경우 고려 (고객 데이터에서 비즈니스 로직에 의해 채워을,하지만 FK는 존재하지 않는다). 디자인은 결함이 있지만, 몇 년 동안 사용되어 왔으며, 세 가지 다른 응용 프로그램은 스키마에 건설되었다. Claim.SSN에서 추출하고 실제 PK-FK 관계에 두는 것이 이상적 일 것입니다 분명해야하지만, 또한 중요한 점검 할 것이다. 반면에, 거의 또는 응용 프로그램에 영향을주지 않고, 참조 무결성을 제공 할 수있다, Customer.SSN에 UNIQUE 제약을 가하고, 그리고 Claim.SSN에 FK를 추가.
오해하지 마세요, 가끔 이상주의를 통해 실용주의의 승리를 정상화에 대한 모든이야,하지만. 평범한 디자인이 반창고와 도움이 될 수있는 경우, 수술을 피할 수 있습니다.
-
==============================
3.Necromancing. 나는 누군가가 여기에 착륙 할 때, 그는 비 고유 키가 들어있는 테이블의 컬럼에 외래 키를 필요로 가정합니다. 문제는 당신이 그 문제가있을 경우, 데이터베이스 스키마가 비정규되어있다.
Necromancing. 나는 누군가가 여기에 착륙 할 때, 그는 비 고유 키가 들어있는 테이블의 컬럼에 외래 키를 필요로 가정합니다. 문제는 당신이 그 문제가있을 경우, 데이터베이스 스키마가 비정규되어있다.
당신은 방 UID 기본 키, 테이블의 예를 유지 객실에 대한있어하는 DateFrom과 DateTo 필드, 다른 UID가 여기에 같은 방을 추적하는 RM_ApertureID 및 소프트 삭제 필드, RM_Status 같은, 여기서 99 수단은 '삭제'와 <> 99 개 수단 '활성'.
그래서 당신은 RM_UID와 같은 값으로 RM_UID 및 RM_ApertureID 삽입을 처음 방을 만들 때. 당신이 날짜로 방을 종료하고 새 날짜 범위를 재 확립 할 때 다음, RM_UID)은 (NEWID이며, 이전 항목에서 RM_ApertureID는 새로운 RM_ApertureID된다.
그런 경우 경우에 따라서, RM_ApertureID는 고유하지 않은 분야이고, 그래서 당신은 다른 테이블의 외래 키를 설정할 수 없습니다.
그리고 고유하지 않은 컬럼 / 인덱스, 예를 들어,에 외래 키를 설정하는 방법은 없습니다 T_ZO_REM_AP_Raum_Reinigung에서 (RM_UID 실제로 RM_ApertureID입니다). 그러나 잘못된 값을 금지, 그렇지 않으면, 데이터 쓰레기가 조속히 결과, 외래 키를 설정해야합니다 ...
이제 당신이 (이 경우 전체 응용 프로그램을 다시 작성의 짧은을) 할 수있는 것은 키의 존재를 확인 스칼라 기능을하는 CHECK-제약 조건을 삽입 할 수 있습니다 :
IF EXISTS (SELECT * FROM sys.check_constraints WHERE object_id = OBJECT_ID(N'[dbo].[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]') AND parent_object_id = OBJECT_ID(N'[dbo].[T_ZO_REM_AP_Raum_Reinigung]')) ALTER TABLE dbo.T_ZO_REM_AP_Raum_Reinigung DROP CONSTRAINT [Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung] GO IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fu_Constaint_ValidRmApertureId]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT')) DROP FUNCTION [dbo].[fu_Constaint_ValidRmApertureId] GO CREATE FUNCTION [dbo].[fu_Constaint_ValidRmApertureId]( @in_RM_ApertureID uniqueidentifier ,@in_DatumVon AS datetime ,@in_DatumBis AS datetime ,@in_Status AS integer ) RETURNS bit AS BEGIN DECLARE @bNoCheckForThisCustomer AS bit DECLARE @bIsInvalidValue AS bit SET @bNoCheckForThisCustomer = 'false' SET @bIsInvalidValue = 'false' IF @in_Status = 99 RETURN 'false' IF @in_DatumVon > @in_DatumBis BEGIN RETURN 'true' END IF @bNoCheckForThisCustomer = 'true' RETURN @bIsInvalidValue IF NOT EXISTS ( SELECT T_Raum.RM_UID ,T_Raum.RM_Status ,T_Raum.RM_DatumVon ,T_Raum.RM_DatumBis ,T_Raum.RM_ApertureID FROM T_Raum WHERE (1=1) AND T_Raum.RM_ApertureID = @in_RM_ApertureID AND @in_DatumVon >= T_Raum.RM_DatumVon AND @in_DatumBis <= T_Raum.RM_DatumBis AND T_Raum.RM_Status <> 99 ) SET @bIsInvalidValue = 'true' -- IF ! RETURN @bIsInvalidValue END GO IF EXISTS (SELECT * FROM sys.check_constraints WHERE object_id = OBJECT_ID(N'[dbo].[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]') AND parent_object_id = OBJECT_ID(N'[dbo].[T_ZO_REM_AP_Raum_Reinigung]')) ALTER TABLE dbo.T_ZO_REM_AP_Raum_Reinigung DROP CONSTRAINT [Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung] GO -- ALTER TABLE dbo.T_AP_Kontakte WITH CHECK ADD CONSTRAINT [Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung] ALTER TABLE dbo.T_ZO_REM_AP_Raum_Reinigung WITH NOCHECK ADD CONSTRAINT [Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung] CHECK ( NOT ( dbo.fu_Constaint_ValidRmApertureId(ZO_RMREM_RM_UID, ZO_RMREM_GueltigVon, ZO_RMREM_GueltigBis, ZO_RMREM_Status) = 1 ) ) GO IF EXISTS (SELECT * FROM sys.check_constraints WHERE object_id = OBJECT_ID(N'[dbo].[Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung]') AND parent_object_id = OBJECT_ID(N'[dbo].[T_ZO_REM_AP_Raum_Reinigung]')) ALTER TABLE dbo.T_ZO_REM_AP_Raum_Reinigung CHECK CONSTRAINT [Check_RM_ApertureIDisValid_T_ZO_REM_AP_Raum_Reinigung] GO
-
==============================
4.항상 고유해야 할 필요가 기본 키, 외래 키 테이블은 일대 다 관계의 경우 고유하지 않은 값을 허용해야합니다. 또한 테이블이 일대일 관계가 아니라 일대 다 관계에 의해 연결되어있는 경우 기본 키로 외부 키를 사용하여 완벽하게 괜찮습니다.
항상 고유해야 할 필요가 기본 키, 외래 키 테이블은 일대 다 관계의 경우 고유하지 않은 값을 허용해야합니다. 또한 테이블이 일대일 관계가 아니라 일대 다 관계에 의해 연결되어있는 경우 기본 키로 외부 키를 사용하여 완벽하게 괜찮습니다.
외래 키 제약 조건은 다른 테이블의 PRIMARY KEY 제약 조건에만 연결 할 필요가 없습니다; 또한, 다른 테이블에 UNIQUE 제약의 열을 참조하도록 정의 될 수있다.
from https://stackoverflow.com/questions/18435065/foreign-key-to-non-primary-key by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] 먼저 특정 필드 값에 의해 주문 (0) | 2020.03.21 |
---|---|
[SQL] PHP 내에서 .SQL 파일로드 (0) | 2020.03.21 |
[SQL] SQL은 - 어떻게 저장하고 탐색 계층 구조가? (0) | 2020.03.21 |
[SQL] BY GROUP은 열 CONCAT / 결합 [중복] (0) | 2020.03.21 |
[SQL] 대부분의 효율적인 T-SQL 패드 방식으로 일정한 길이로 왼쪽에 VARCHAR? (0) | 2020.03.21 |