IT

기본 키가 아닌 외래 키

lottoking 2020. 7. 22. 07:48
반응형

기본 키가 아닌 외래 키


데이터를 보유하는 테이블이 해당 행 중 하나가 다른 테이블에 있어야합니다. 따라서 참조 무결성을 유지하기 위해 외래 키를 원합니다.

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

반응형