2012-05-22 7 views
19
나는 다음과 같은 테이블이

에 중복 행을 무시 :건너 뛰기 오버/인서트

DataValue

DateStamp ItemId Value 
---------- ------ ----- 
2012-05-22 1  6541 
2012-05-22 2  12321 
2012-05-21 3  32 

tmp_holding_DataValue

DateStamp ItemId Value 
---------- ------ ----- 
2012-05-22 1  6541 
2012-05-22 4  87 
2012-05-21 5  234 

DateStampItemId 기본 키 열입니다.

insert into DataValue(DateStamp, ItemId, Value) 
select DateStamp, ItemId, Value from tmp_holding_DataValue; 

이 유지 테이블 (tmp_holding_DataValue)에서 데이터를 이동하는 주요 데이터 테이블 (DataValue)에 걸쳐 :

나는 (저장 프로 시저에) 하루 동안 주기적으로 실행되는 삽입을하고 있어요. 그러면 홀딩 테이블이 잘립니다.

예에서와 같이 보유 테이블에 이미 주 테이블에있는 항목이 포함될 수 있습니다. 키가 중복 값을 허용하지 않으므로 프로 시저가 실패합니다.

하나의 옵션은 삽입 프로 시저에 where 절을 넣는 것이지만 기본 데이터 테이블에는 1000 만 개의 행이 있으며 이는 오랜 시간이 걸릴 수 있습니다.

삽입을 시도 할 때 중복을 건너 뛰거나 무시하는 다른 방법이 있습니까? SQL Server 2008+에서

+0

보유 테이블의 '값'열이 다른 경우 (예 : 첫 번째 행의 경우 '6541'대신 '3253'입니까? 아직도 중복 된 것입니까? 그렇지 않다면 소스 테이블에서 '6541 + 3253'을 추가하거나 업데이트 하시겠습니까? –

+0

값 열은 중요하지 않습니다. 다른 값이 무시되면 해당 날짜 스탬프에 대해 이미 DataValue에있는 값을 그대로 두어야합니다. – finoutlook

+0

SQL Server의 최소 * 버전 *에 질문을 태그하는 것이 매우 유용합니다. 지원해야합니다.처음에는 당신이 어떤 버전을 사용하고 있는지 전혀 몰랐기 때문에 나는'MERGE' 솔루션을 제공하지 않았습니다. –

답변

22
INSERT dbo.DataValue(DateStamp, ItemId, Value) 
SELECT DateStamp, ItemId, Value 
FROM dbo.tmp_holding_DataValue AS t 
WHERE NOT EXISTS (SELECT 1 FROM dbo.DataValue AS d 
WHERE DateStamp = t.DateStamp 
AND ItemId = t.ItemId); 
+3

이것은 효과가있을 것이지만, DataValue 테이블이 결국 1 억 개의 행으로 끝나는 것이 더 빠르면 궁금하다. – finoutlook

+0

기본 키가 클러스터되어 있고 보유 테이블에 동등한 인덱스가 있다면 문제가되어서는 안됩니다 (또는 적어도 중복을 검사하는 다른 솔루션보다 문제가 없어야합니다). 홀딩 테이블에 "오래된"데이터가 있습니까? 아니면 항상 새로운 데이터를 추가하고 있습니까? 이틀 전과 같이 합리적으로 날짜를 제한하는 where 절을 추가 할 수 있습니다. 그리고 'DateStamp'가 기본 키의 선행 열이면 약간 도움이됩니다. 하지만 항상 새로운 데이터가 홀딩 테이블에있는 경우에만 해당됩니다. –

+1

감사합니다.이 솔루션을 사용해 주셔서 감사합니다. – finoutlook

15

:

MERGE 
INTO dataValue dv 
USING tmp_holding_DataValue t 
ON  t.dateStamp = dv.dateStamp 
     AND t.itemId = dv.itemId 
WHEN NOT MATCHED THEN 
INSERT (dateStamp, itemId, value) 
VALUES (dateStamp, itemId, value) 
/* 
WHEN MATCHED THEN 
UPDATE 
     value = t.value 
*/ 
-- Uncomment above to rewrite duplicates rather than ignore them 
+0

병합 사용을 생각했지만 DataValue가 10m + 행이고 tmp_holding_DataValue가 약 2m 행인데 시간이 오래 걸린다는 생각이 들었습니다. 모든 데이터를 해당 테이블의 시간으로 다시 검사 할 것이기 때문입니다. – finoutlook

+0

@finoutlook : 즉, 성급하게 최적화 했습니까? 그냥 시도 해 봐. – Quassnoi

+1

나는 항상 최악의 희망과 최선의 희망을 ..! – finoutlook

15

당신은 예 = 중복 키를 무시로 PK를 지정할 수 있습니다. 그런 다음 경고 복제 키를 무시하고 계속합니다. 나는 짐작하지 않는다. 나는 이것을 시험했다.

내가 찾은 것은 SMSS라고 할 수 없다는 것입니다. 스크립트를 통해 색인을 삭제하고 다시 만들어야합니다. 그러나 인덱스를 마우스 오른쪽 버튼으로 클릭하고 드롭을 선택하여 다시 만들고 중복 키 무시 = 예를 변경할 수 있습니다. 나를 위해 SMSS 즉시 변경 내용을 표시하지 않았습니다.

IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[PKallowDup]') AND name = N'PK_PKallowDup') 
ALTER TABLE [dbo].[PKallowDup] DROP CONSTRAINT [PK_PKallowDup] 
GO 

USE [test] 
GO 

/****** Object: Index [PK_PKallowDup] Script Date: 05/22/2012 10:23:13 ******/ 
ALTER TABLE [dbo].[PKallowDup] ADD CONSTRAINT [PK_PKallowDup] PRIMARY KEY CLUSTERED 
(
    [PK] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON, IGNORE_DUP_KEY = ON, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO 

아니면 당신이 외부 조인을 사용할 수 있다고 생각

INSERT dbo.DataValue(DateStamp, ItemId, Value) 
SELECT t.DateStamp, t.ItemId, t.Value 
    FROM dbo.tmp_holding_DataValue AS t 
    left join dbo.DataValue AS d 
    on d.DateStamp = t.DateStamp 
    AND d.ItemId = t.ItemId 
WHERE d.DateStamp is null 
    and d.ItemId in null 
+0

나는 이것이 다른 곳에서 제안 된 것을 보았지만 기본 키를 그대로 유지하기를 원했습니다. 최종적으로 'DataValue' 테이블에는 중복이 없습니다. – finoutlook

+4

왜 까다 롭습니까? 'WITH (IGNORE_DUP_KEY = ON); 또한 @finoutlook 간단한 테이블에서이 옵션을 사용해 보셨습니까? 여전히 기본 키이며 복제본은 허용되지 않습니다. 'IGNORE_DUP_KEY' 설정은 SQL Server가 키 위반을 처리하는 방법을 제어합니다 (예외 또는 "중복 키가 무시되었습니다"라는 간단한 상태 메시지로 만). –

+2

PK가 있고 강제 적용됩니다. 차이점은 PK 위반은 경고 일 뿐이며 중복 키 무시 = 예 일 때 행 삽입을 계속한다는 것입니다. – Paparazzi

0

나도 같은 중복 키 오류를 던지고 결국 비슷한 요구 사항으로 실행하고 아이디어가 여러 열을 선택했다 별개의 (차)도 복귀하면서 다른 열, check는 :

INSERT INTO DataValue(DateStamp, ItemId, Value) 
SELECT DISTINCT DateStamp, ItemId, MAX(Value) AS Value 
FROM tmp_holding_DataValue 
GROUP BY DateStamp, ItemId 

사실, 목표는 고유뿐만 아니라 이후 집계 재미없이 수행 할 수 MAX는 하나의 값을 선택합니다.