복붙노트

[SQL] 하나의 레코드에 대한 제약은 기본값으로 표시

SQL

하나의 레코드에 대한 제약은 기본값으로 표시

어떻게 1 레코드 만 하나 때문에이 그 isDefault 비트 필드 세트 테이블에 제약 조건을 설정할 수 있습니다?

제약은 FormID에 의해 지정된 테이블 범위하지만, 행 세트 당 하나 개의 기본 아니다.

해결법

  1. ==============================

    1.여기 FormID 당 하나 개의 기본을 허용 Damien_The_Unbeliever의 솔루션의 수정이다.

    여기 FormID 당 하나 개의 기본을 허용 Damien_The_Unbeliever의 솔루션의 수정이다.

    CREATE VIEW form_defaults
    AS
    SELECT FormID
    FROM whatever
    WHERE isDefault = 1
    GO
    CREATE UNIQUE CLUSTERED INDEX ix_form_defaults on form_defaults (FormID)
    GO
    

    하지만이 정보를 알려드립니다 심각한 관계형 사람들은 또 다른 테이블에 있어야합니다.

    CREATE TABLE form
    FormID int NOT NULL PRIMARY KEY
    DefaultWhateverID int FOREIGN KEY REFERENCES Whatever(ID)
    
  2. ==============================

    2.SQL Server 2008에서 이상 당신은 단순히 고유 필터링 된 인덱스를 사용할 수 있습니다

    SQL Server 2008에서 이상 당신은 단순히 고유 필터링 된 인덱스를 사용할 수 있습니다

    CREATE UNIQUE INDEX IX_TableName_FormID_isDefault
        ON TableName(FormID)
        WHERE isDefault = 1
    

    어디 테이블 인

    CREATE TABLE TableName(
        FormID INT NOT NULL,
        isDefault BIT NOT NULL
    )
    

    예를 들어, 당신은이 오류가있을 것이다 일에 동일한 FormId 및 isDefault 세트로 여러 행을 삽입하려고하면 :

    출처 : http://technet.microsoft.com/en-us/library/cc280372.aspx

  3. ==============================

    3.정규화 관점에서,이 하나의 사실을 저장하는 비효율적 인 방법이 될 것입니다.

    정규화 관점에서,이 하나의 사실을 저장하는 비효율적 인 방법이 될 것입니다.

    I는 (다른 테이블) 디폴트로 간주되는 로우의 식별자와 외부 키를 저장하여, 높은 수준의 정보를 보유하도록 선택할 수있다.

    CREATE TABLE [dbo].[Foo](
        [Id] [int] NOT NULL,
     CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    ) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    
    CREATE TABLE [dbo].[DefaultSettings](
        [DefaultFoo] [int] NULL
    ) ON [PRIMARY]
    
    GO
    
    ALTER TABLE [dbo].[DefaultSettings]  WITH CHECK ADD  CONSTRAINT [FK_DefaultSettings_Foo] FOREIGN KEY([DefaultFoo])
    REFERENCES [dbo].[Foo] ([Id])
    GO
    
    ALTER TABLE [dbo].[DefaultSettings] CHECK CONSTRAINT [FK_DefaultSettings_Foo]
    GO
    
  4. ==============================

    4.당신은 삽입 / 업데이트 트리거를 사용할 수 있습니다.

    당신은 삽입 / 업데이트 트리거를 사용할 수 있습니다.

    isDefault = 1 행의 개수가 1 개 이상 인 경우 삽입 또는 업데이트 후 트리거 내에서 다음 트랜잭션을 롤백.

  5. ==============================

    5.

    CREATE VIEW vOnlyOneDefault
    AS
      SELECT 1 as Lock
      FROM <underlying table>
      WHERE Default = 1
    GO
    CREATE UNIQUE CLUSTERED INDEX IX_vOnlyOneDefault on vOnlyOneDefault (Lock)
    GO
    

    이에 대해 설정 올바른 ANSI 설정을해야합니다.

  6. ==============================

    6.하지 않을 경우 오라클에, 나는이 번역 될 수 있기를 바랍니다 것처럼 함수 기반 인덱스를 지원하는 경우 미안, SQLServer.But에 대해 알고하지 않습니다.

    하지 않을 경우 오라클에, 나는이 번역 될 수 있기를 바랍니다 것처럼 함수 기반 인덱스를 지원하는 경우 미안, SQLServer.But에 대해 알고하지 않습니다.

    기본값은 1234입니다 suposed에 당신은이 같은 인덱스를 할 수있는 열은 DEFAULT_COLUMN하고 ID_COLUMN는 기본 키입니다 :

    CREATE 
    UNIQUE 
     INDEX only_one_default 
        ON my_table
         ( DECODE(DEFAULT_COLUMN, 1234, -1, ID_COLUMN) )
    

    이 DDL은 고유 인덱스 색인을 생성 DEFAULT_COLUMN -1의 값이 1234과 다른 경우 ID_COLUMN 경우. 두 개의 열이 DEFAULT_COLUMN 값이 있다면, 그것은 예외를 발생시킵니다.

  7. ==============================

    7.문제는 당신이 어떤 자식 레코드를 가지고 있으며, 그 자식 레코드 중 하나가 기본 기록 될 것입니다 기본 테이블이 나에게 의미한다. 주소와 여기에 별도의 기본 테이블을 사용하면 3 정규형을 사용하는 일이 있는지 확인하는 방법의 예입니다. 물론 너무 오래 무언가를 대답 할 가치가 있는지 모르겠지만 내 공상을 쳤다.

    문제는 당신이 어떤 자식 레코드를 가지고 있으며, 그 자식 레코드 중 하나가 기본 기록 될 것입니다 기본 테이블이 나에게 의미한다. 주소와 여기에 별도의 기본 테이블을 사용하면 3 정규형을 사용하는 일이 있는지 확인하는 방법의 예입니다. 물론 너무 오래 무언가를 대답 할 가치가 있는지 모르겠지만 내 공상을 쳤다.

    --drop table dev.defaultAddress;
    --drop table dev.addresses;
    --drop table dev.people;
    
    CREATE TABLE [dev].[people](
        [Id] [int] identity primary key,
        name char(20)
    )
    GO
    
    CREATE TABLE [dev].[Addresses](
        id int identity primary key,
        peopleId int foreign key references dev.people(id),
        address varchar(100)
    ) ON [PRIMARY]
    
    GO
    CREATE TABLE [dev].[defaultAddress](
        id int identity primary key,
        peopleId int foreign key references dev.people(id),
        addressesId int foreign key references dev.addresses(id))
    go
    create unique index defaultAddress on dev.defaultAddress (peopleId)
    go
    create unique index idx_addr_id_person on dev.addresses(peopleid,id);
    go
    ALTER TABLE dev.defaultAddress
       ADD CONSTRAINT FK_Def_People_Address
       FOREIGN KEY(peopleID, addressesID)
       REFERENCES dev.Addresses(peopleId, id)
    go
    insert into dev.people (name) 
        select 'Bill' union 
        select 'John' union 
        select 'Harry'
    insert into dev.Addresses (peopleid, address) 
        select 1, '123 someplace' union 
        select 1,'work place' union
        select 2,'home address' union
        select 3,'some address'
    insert into dev.defaultaddress (peopleId, addressesid)
        select 1,1 union
        select 2,3 
    -- so two home addresses are default now
    -- try adding another default address to Bill and you get an error
    select * from dev.people 
        join dev.addresses on people.id = addresses.peopleid
        left join dev.defaultAddress on defaultAddress.peopleid = people.id and defaultaddress.addressesid = addresses.id 
    insert into dev.defaultaddress (peopleId, addressesId)
        select 1,2 
    
    GO
    
  8. ==============================

    8.대신 트리거의를 통해 그것을 할, 또는 당신이 제약 조건으로 원하는 경우 제약 조건을 참조하는 함수를 만들 수있는 1 기본 세트가있는 행에 대한 검사

    대신 트리거의를 통해 그것을 할, 또는 당신이 제약 조건으로 원하는 경우 제약 조건을 참조하는 함수를 만들 수있는 1 기본 세트가있는 행에 대한 검사

    편집 죄송 <= 할 필요

    Create table mytable(id1 int, defaultX bit not null default(0))
    go
    
    create Function dbo.fx_DefaultExists()
    returns int as 
    Begin
        Declare @Ret int
        Set @ret = 0
        Select @ret = count(1) from mytable 
        Where defaultX = 1
    
        Return @ret
    End
    GO
    Alter table mytable add
    CONSTRAINT  [CHK_DEFAULT_SET] CHECK 
     (([dbo].fx_DefaultExists()<=(1)))
    GO
    Insert into mytable (id1, defaultX) values (1,1)
    
    Insert into mytable (id1, defaultX) values (2,1)
    
  9. ==============================

    9.이것은 간단한 제약을 통해 처리 할 수없는 매우 복잡한 과정이다.

    이것은 간단한 제약을 통해 처리 할 수없는 매우 복잡한 과정이다.

    우리는 트리거를 통해이 작업을 수행. 당신이 방아쇠를 쓰기 그러나 전에 몇 가지 대답 할 수 있어야합니다 :

    기본이있는 경우 우리가 삽입 실패하고 싶어, 1 대신 0으로 변경하거나 0으로 기존의 기본을 변경하고 1 등이 하나를 남겨? 우리는 기본 레코드가 삭제되고 다른 비 기본 레코드가 여전히있을 경우 무엇을 원하는가? 우리가 어떤 일을 결정 어떻게 그렇다면, 우리는 하나의 기본 어떻게해야합니까?

    당신은 또한 트리거 손잡이 다중 행 처리를 할 매우 조심해야합니다. 예를 들어 클라이언트는 특정 유형의 모든 레코드가 기본이 될 것을 결정할 수 있습니다. 이 트리거가 처리 할 수 ​​있어야합니다, 그래서 당신은 한 번에 만 개 기록 하나를 변경하지 않을 것입니다. 또한 루프 또는 커서를 사용하지 않고 (당신이 정말로 거래의 유형이 시간 테이블을 전체 시간을 잠금 걸릴 위에서 언급하지 않음) 것을 처리해야합니다.

    이 라이브되기 전에 당신은 또한이 트리거에 대한 매우 광범위한 tesing 시나리오가 필요합니다. 당신은 테스트해야합니다 : 기본값은 없습니다 기록을 추가하며 해당 고객에 대한 최초의 기록이다 기본값은 기록을 추가하며 해당 고객에 대한 최초의 기록이다 기본값은 없습니다 기록을 추가하며 해당 고객에 대한 첫 번째 기록하지 않 기본값은 기록을 추가하며 해당 고객에 대한 첫 번째 기록하지 않 다른 기록이가 없을 때 기본을 가지고 기록을 갱신 (항상 deafault로 설정할 수에 하나 개의 레코드를 필요로하지 않는 가정) 기록을 갱신하는 것은 기본을 제거합니다 deafult와 기록을 삭제 기본없이 기록 삭제 개별 레코드 삽입을 실행할 때 모두 1 isdefault 세트를 가지고 있고 모든 상황이 시험 두 개의 레코드를 포함하는 데이터의 여러 상황과 대량 삽입을 수행 개별 레코드 업데이트를 실행하는 경우 모두 1 isdefault 세트를 가지고 있고 모든 상황이 시험 두 개의 레코드를 포함하는 데이터의 여러 상황을 대량 업데이트 수행 질량 개별 기록 삭제를 실행하는 경우 모두 1 isdefault 세트를 가지고 있고 모든 상황이 시험 두 개의 레코드를 포함하는 데이터의 여러 상황에 삭제 수행

  10. ==============================

    10.@Andy 존스는 나의 가장 가까운 위의 대답을했다,하지만 마음에 세 가지의 규칙 베어링, 나는 저장된 프로 시저 업데이트가이 테이블에 직접 논리를 배치했다. 이것은 나의 간단한 해결책이었다. 내가 다른 곳에서 테이블을 업데이트해야하는 경우, 나는 트리거에 논리를 이동합니다. 한 기본 규칙은 FormID과 ConfigID에 의해 지정된 레코드의 각 세트에 적용

    @Andy 존스는 나의 가장 가까운 위의 대답을했다,하지만 마음에 세 가지의 규칙 베어링, 나는 저장된 프로 시저 업데이트가이 테이블에 직접 논리를 배치했다. 이것은 나의 간단한 해결책이었다. 내가 다른 곳에서 테이블을 업데이트해야하는 경우, 나는 트리거에 논리를 이동합니다. 한 기본 규칙은 FormID과 ConfigID에 의해 지정된 레코드의 각 세트에 적용

    ALTER proc [dbo].[cpForm_UpdateLinkedReport]
        @reportLinkId int,
        @defaultYN bit,
        @linkName nvarchar(150)
    as
    if @defaultYN = 1
    begin
        declare @formId int, @configId int
        select @formId = FormID, @configId = ConfigID from csReportLink where ReportLinkID = @reportLinkId
        update csReportLink set DefaultYN = 0 where isnull(ConfigID,  @configId) = @configId and FormID = @formId
    end
    update
        csReportLink
     set
        DefaultYN = @defaultYN,
        LinkName = @linkName
    where
        ReportLinkID = @reportLinkId
    
  11. from https://stackoverflow.com/questions/637894/constraint-for-only-one-record-marked-as-default by cc-by-sa and MIT license