기본 키가 아닌 외래 키
데이터를 보유하는 테이블이 해당 행 중 하나가 다른 테이블에 있어야합니다. 따라서 참조 무결성을 유지하기 위해 외래 키를 원합니다.
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가 아닙니다. 이 외래 키를 만드는 방법이, 아니면이 참조를 유지하는 더 좋은 방법이 있습니까?
기본이 아닌 키에 외래 키를 만들려면 한 제약 조건이있는 열이어야합니다.
에서 온라인 :
FOREIGN KEY 제약 조건은 다른 테이블의 PRIMARY KEY 제약 조건에만 연결될 수 있습니다. 다른 테이블에서 UNIQUE 제약 조건의 열을 참조하도록 정의 할 수도 있습니다.
따라서 귀하의 경우에 AnotherID
독특하게 만들면 허용됩니다. 고유 한 제약 조건을 적용 할 수 있지만 운이 좋지 않지만 생각하면 말이됩니다.
언급했듯이, 후보 키로 완벽하게 좋은 기본 키가 있고 사용하지 않는 이유는 무엇입니까?
다른 사람들이 지적했듯이 외래 키는 기본 키 (일반적으로 IDENTITY 열)에 대한 참조로 생성되는 것이입니다. 그러나 우리는 그런 세상에 살 고급 거기 효과를 스키마에 대한 "작은"변경조차도 응용 프로그램 논리에 큰 파입니다.
SSN 열 (및 벙어리 기본 키)이있는 고객 테이블과 SSN 열도 포함하는 Claim 테이블 (고객 데이터의 비즈니스 논리에 의해 채워지지만 FK는없는 경우)을 고려하십시오. 사용되어 왔으며 3 개의 다른 응용 프로그램이 스키마에 구축되었습니다. Claim.SSN을 제거하고 실제 PK-FK를 맺는 것이 관계 이상적 일 것임은 분명 하지만, 또한 대대적 인 점검이 될을 구석으로 입니다. 반면에 Customer.SSN에 UNIQUE 제약 조건을 적용하고 Claim.SSN에 FK를 추가하면 응용 프로그램에 거의 영향을 미치도록 서 참조 무결성을 제공 할 수 있습니다.
나를 잘못 이해하지 마라, 나는 정상화에 대한 모든 것이지만 실용주의가 이상주의보다 승리한다. 반창고로 평범한 디자인을 활용할 수 있습니다.
괴롭힘.
누군가가 여기에 도착하면 고유하지 않은 키가 포함 된 테이블의 열에 외래 키가 필요합니다.
문제는 해당가있는 경우 데이터베이스 스키마가 비정규 화 된 것입니다.
예를 들어 room-uid 기본 키, DateFrom 및 DateTo 필드 및 다른 uid (여기서는 룸을 추적하기위한 RM_ApertureID) 및 RM_Status와 같은 소프트 삭제 필드를 사용하여 테이블에 룸을 유지하고 있습니다. 여기서 99는 '삭제됨'을 의미하고 <> 99는 '활성'을 의미합니다.
따라서 첫 번째 방을 만들 때 RM_UID와 동일한 값으로 RM_UID 및 RM_ApertureID를 삽입합니다. 그런 다음 날짜를 날짜로 종료하고 새 범위로 다시 설정하면 RM_UID는 newid ()이며 이전 항목의 RM_ApertureID는 새로운 RM_ApertureID가됩니다.
따라서 RM_Aperture ID는 고유하지 않은 필드에 다른 테이블에서 외래 키를 수 없습니다.
그리고 외래 키를 고유하지 않은 열 / 보안 설정하는 방법은 없습니다 (예 : T_ZO_REM_AP_Raum_Reinigung (WHERE 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
기본 키는 항상 고유해야하며 외래 키는 테이블이 일대 다 관계인 경우 고유하지 않은 값을 허용해야합니다. 테이블이 일대 다 관계가 아닌 일대일 관계로 사용할 경우 외래 키를 기본 키로 사용하는 것이 좋습니다.
FOREIGN KEY 제약 조건은 다른 테이블의 PRIMARY KEY 제약 조건에만 연결될 수 있습니다. 다른 테이블에서 UNIQUE 제약 조건의 열을 참조하도록 정의 할 수도 있습니다.
참고 URL : https://stackoverflow.com/questions/18435065/foreign-key-to-non-primary-key
'IT' 카테고리의 다른 글
동일한 YAML 파일의 다른 곳에서 YAML "설정"을 참조하는 방법은 무엇입니까? (0) | 2020.07.22 |
---|---|
Node.JS에서 서버 측 이미지 조작에 어떤 라이브러리를 가지고 있습니까? (0) | 2020.07.22 |
IFS = $ '\ n'의 정확한 의미는 무엇입니까? (0) | 2020.07.22 |
어떤 프로세스가 모든 디스크 IO를 사용하고 있습니까? (0) | 2020.07.22 |
리플렉션을 통해 사유 재산을 접근 할 수 있습니까? (0) | 2020.07.22 |