복붙노트

[SQL] 기본 키가없는 경우 중복 레코드가 SqlBulkCopy의 삽입되지 않도록하는 방법

SQL

기본 키가없는 경우 중복 레코드가 SqlBulkCopy의 삽입되지 않도록하는 방법

나는 각 내가보고 및 결제에 사용하기 위해 내부 데이터베이스에 저장해야하는 비즈니스 트랜잭션되고, 수천 개의 레코드를 포함하는 일상 XML 파일을받을 수 있습니다. 나는 매일의 파일은 고유 한 기록을 포함하지만, 고유의 나의 정의는 정확히 제공 업체의 동일하지 않습니다 것을 발견하는 인상이었다.

이 데이터는 C # 닷넷 3.5 콘솔 응용 프로그램입니다 수입하는 현재의 응용 프로그램은,이 때문에 MS SQL 서버 2008 데이터베이스 테이블에 SqlBulkCopy의를 사용하면 열이 정확하게 XML 레코드의 구조와 일치 않는 경우. 각 레코드는 100 개 이상의 필드가, 나는 복합 키 말까지도 널 (null)을 허용하는 것으로 이해하고 함께 올 수있는 데이터에는 자연 키, 또는 오히려 분야가 없습니다. 현재 테이블이 여러 인덱스,하지만 기본 키를 가지고있다.

기본적으로 전체 행은 고유해야합니다. 하나 개의 필드가 다른 경우 삽입 할 유효한 충분하다. 난하지만 난 대량 복사 작업에 MD5 해시를 얻는 방법을 볼 수 없습니다, 데이터베이스에와 행을 삽입에서 SqlBulkCopy의 방지를 위해 제약 조건을 사용하여 해당 삽입, 전체 행의 MD5 해시를 만들어 보면서 나는 아니에요 반드시 전체 작업이 실패하고 롤 다시 어떤 하나 개의 레코드가 실패 할 경우, 또는 계속하면 것인지.

이 파일은 정말 내가이 일을 할 수있는 볼 수있는 유일한 방법은 아주 많은 레코드가, XML에서 행 단위로가는 모든 필드와 일치하는 레코드에 대한 데이터베이스를 조회 한 다음 삽입에 결정이 포함되어 있습니다. 난 그냥 완전히 응용 프로그램을 다시 작성해야하지 기대했다, 그리고 대량 복사 작업이 훨씬 더 빨리 너무입니다.

기본 키없이, 중복 행을 방지하면서 방법의 사람을 알고는 SqlBulkCopy의를 사용합니까? 아니면 다른 방법에 대한 어떤 제안이 작업을 수행하려면?

해결법

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

    1.나는 그 준비 테이블에 데이터를 업로드 최종 테이블에 복사본 이후 중복 다룰 것입니다.

    나는 그 준비 테이블에 데이터를 업로드 최종 테이블에 복사본 이후 중복 다룰 것입니다.

    예를 들어, "키"로 거래를 준비 테이블에 (고유하지 않은) 인덱스를 만들 수 있습니다

  2. ==============================

    2.당신은 SQL 2008을 사용하고 있음을 감안할 때, 당신은 (전혀 경우) 많은 응용 프로그램을 변경할 필요없이 쉽게 문제를 해결하기 위해 두 가지 옵션이 있습니다.

    당신은 SQL 2008을 사용하고 있음을 감안할 때, 당신은 (전혀 경우) 많은 응용 프로그램을 변경할 필요없이 쉽게 문제를 해결하기 위해 두 가지 옵션이 있습니다.

    첫 번째 가능한 해결책은 처음처럼하지만 대리 신원 키와 당신을 위해 중복 제거의 모든 무거운 리프팅을 할 것 IGNORE_DUP_KEY 옵션을 사용하여 추가 된 고유성 제약 조건 두 번째 테이블을 만드는 것입니다.

    여기에 무슨 일이 일어나고 있는지 볼 수 SSMS에서 실행할 수있는 예입니다 :

    if object_id( 'tempdb..#test1' ) is not null drop table #test1;
    if object_id( 'tempdb..#test2' ) is not null drop table #test2;
    go
    
    
    -- example heap table with duplicate record
    
    create table #test1
    (
         col1 int
        ,col2 varchar(50)
        ,col3 char(3)
    );
    insert #test1( col1, col2, col3 )
    values
         ( 250, 'Joe''s IT Consulting and Bait Shop', null )
        ,( 120, 'Mary''s Dry Cleaning and Taxidermy', 'ACK' )
        ,( 250, 'Joe''s IT Consulting and Bait Shop', null )    -- dup record
        ,( 666, 'The Honest Politician', 'LIE' )
        ,( 100, 'My Invisible Friend', 'WHO' )
    ;
    go
    
    
    -- secondary table for removing duplicates
    
    create table #test2
    (
         sk int not null identity primary key
        ,col1 int
        ,col2 varchar(50)
        ,col3 char(3)
    
        -- add a uniqueness constraint to filter dups
        ,constraint UQ_test2 unique ( col1, col2, col3 ) with ( ignore_dup_key = on )
    );
    go
    
    
    -- insert all records from original table
    -- this should generate a warning if duplicate records were ignored
    
    insert #test2( col1, col2, col3 )
    select col1, col2, col3
    from #test1;
    go
    

    또한, 당신은 또한 두 번째 테이블없이 현재 위치에서 중복을 제거 할 수 있지만 성능은 사용자의 요구에 너무 느릴 수 있습니다. 여기에 SSMS에서 실행 가능한 또한 예를 들어 코드입니다 :

    if object_id( 'tempdb..#test1' ) is not null drop table #test1;
    go
    
    
    -- example heap table with duplicate record
    
    create table #test1
    (
         col1 int
        ,col2 varchar(50)
        ,col3 char(3)
    );
    insert #test1( col1, col2, col3 )
    values
         ( 250, 'Joe''s IT Consulting and Bait Shop', null )
        ,( 120, 'Mary''s Dry Cleaning and Taxidermy', 'ACK' )
        ,( 250, 'Joe''s IT Consulting and Bait Shop', null )    -- dup record
        ,( 666, 'The Honest Politician', 'LIE' )
        ,( 100, 'My Invisible Friend', 'WHO' )
    ;
    go
    
    
    -- add temporary PK and index
    
    alter table #test1 add sk int not null identity constraint PK_test1 primary key clustered;
    create index IX_test1 on #test1( col1, col2, col3 );
    go
    
    
    -- note: rebuilding the indexes may or may not provide a performance benefit
    
    alter index PK_test1 on #test1 rebuild;
    alter index IX_test1 on #test1 rebuild;
    go
    
    
    -- remove duplicates
    
    with ranks as
    (
        select
             sk
            ,ordinal = row_number() over 
             ( 
                -- put all the columns composing uniqueness into the partition
                partition by col1, col2, col3
                order by sk
             )
        from #test1
    )
    delete 
    from ranks
    where ordinal > 1;
    go
    
    
    -- remove added columns
    
    drop index IX_test1 on #test1;
    alter table #test1 drop constraint PK_test1;
    alter table #test1 drop column sk;
    go
    
  3. ==============================

    3.나는 임시 테이블로 대량 복사를하고자 다음 실제 대상 테이블에 그에서 데이터를 밀어 넣습니다. 이러한 방법으로, 당신은과 핸들 중복 확인하기 위해 SQL을 사용할 수 있습니다.

    나는 임시 테이블로 대량 복사를하고자 다음 실제 대상 테이블에 그에서 데이터를 밀어 넣습니다. 이러한 방법으로, 당신은과 핸들 중복 확인하기 위해 SQL을 사용할 수 있습니다.

  4. ==============================

    4.이유는 간단하게, 대신 기본 키의 사용 인덱스 및 세트를 만들 수 없습니다

    이유는 간단하게, 대신 기본 키의 사용 인덱스 및 세트를 만들 수 없습니다

    Ignore Duplicate Keys: YES
    

    이 오류가 발생하는 중복 키를 방지하며, (이미 존재하는)이 작성되지 않습니다.

    나는 완벽 주위 120.000 하루 행과 작품을 삽입하기 위해이 방법을 사용합니다.

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

    5.데이터 볼륨은 무엇인가? 당신은 내가 볼 수있는 두 가지 옵션이 있습니다 :

    데이터 볼륨은 무엇인가? 당신은 내가 볼 수있는 두 가지 옵션이 있습니다 :

    1 : 자신의 IDataReader에 구현하고 데이터에 어떤 해시를 사용하여, 단순히 그들이 TDS에 전달되지는 결코 그렇게 모든 중복을 건너 뛰는하여 소스에서 필터를.

    2 : DB에서 필터; 원시, unsanitised 데이터 - - 그리고 당신이 원하는 경우 아마도 중간 테이블을 사용하여, 실제 테이블에 DISTINCT 데이터를 복사하는 가장 간단한 수준에서, 나는 당신이 수입의 여러 단계가있을 것 같아요. 이 중 일부 CHECKSUM을 사용할 수 있습니다,하지만 따라 달라집니다.

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

    6.그리고 그 테이블을 수정. 어떤 테이블은 이제까지 바람직하게는 PK로, 고유 인덱스없이 없어야합니다. 자연적인 키가 없기 때문에 당신이 대리 키를 추가 할 경우에도 특히 특정 레코드를 식별 할 수 있어야합니다. 그렇지 않으면 방법은 당신이 이미 가지고있는 중복 제거 것인가?

    그리고 그 테이블을 수정. 어떤 테이블은 이제까지 바람직하게는 PK로, 고유 인덱스없이 없어야합니다. 자연적인 키가 없기 때문에 당신이 대리 키를 추가 할 경우에도 특히 특정 레코드를 식별 할 수 있어야합니다. 그렇지 않으면 방법은 당신이 이미 가지고있는 중복 제거 것인가?

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

    7.나는이 많은 청소기라고 생각합니다.

    나는이 많은 청소기라고 생각합니다.

    var dtcolumns = new string[] { "Col1", "Col2", "Col3"};
    
    var dtDistinct = dt.DefaultView.ToTable(true, dtcolumns);
    
    using (SqlConnection cn = new SqlConnection(cn) 
    {
                    copy.ColumnMappings.Add(0, 0);
                    copy.ColumnMappings.Add(1, 1);
                    copy.ColumnMappings.Add(2, 2);
                    copy.DestinationTableName = "TableNameToMapTo";
                    copy.WriteToServer(dtDistinct );
    
    }
    

    이 방법은 하나 개의 데이터베이스 테이블을 필요로하고 코드에서 비즈니스 로직을 유지할 수 있습니다.

  8. from https://stackoverflow.com/questions/2593689/how-to-prevent-duplicate-records-being-inserted-with-sqlbulkcopy-when-there-is-n by cc-by-sa and MIT license