2012-05-22 10 views
19

ich die folgenden Tabellen:Überspringen-over/ignorieren doppelte Zeilen auf Insert

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 

DateStamp und ItemId die Primärschlüsselspalten sind.

Ich mache einen Einsatz, der in regelmäßigen Abständen den ganzen Tag läuft (in einer Stored Procedure):

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

Dies verschiebt Daten vom Haltetisch (tmp_holding_DataValue) über in die Hauptdatentabelle (DataValue). Der Haltetisch wird dann abgeschnitten.

Das Problem besteht darin, dass die Warteschlangentabelle, wie im Beispiel, Elemente enthalten kann, die bereits in der Haupttabelle vorhanden sind. Da der Schlüssel keine doppelten Werte zulässt, schlägt die Prozedur fehl.

Eine Option wäre, eine where-Klausel in den insert proc einzufügen, aber die Hauptdatentabelle hat 10 Millionen + Zeilen, und das könnte lange dauern.

Gibt es eine andere Möglichkeit, die Prozedur dazu zu bringen, die Duplikate einfach zu überspringen/zu ignorieren, während sie versucht einzufügen?

+0

Was ist, wenn die Spalte "Wert" in der Warteschlangentabelle anders ist, z. für die erste Reihe ist es "3253" anstatt "6541"? Ist das noch ein Duplikat? Wenn nicht, möchten Sie etwas aktualisieren (z. B. "6541 + 3253" in der Quelltabelle hinzufügen) oder einfach ersetzen? –

+0

Die value-Spalte spielt keine Rolle, wenn sie anders ist, wird sie ignoriert, was im DataValue bereits für diesen Datumsstempel ist, sollte unverändert sein. – finoutlook

+0

Es ist auch sehr nützlich, Ihre Frage mit der minimalen * Version * von SQL Server zu versehen muss unterstützen.Ich habe keine "MERGE" -Lösung angeboten, weil ich anfangs überhaupt keine Ahnung hatte, welche Version Sie verwenden. –

Antwort

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

Das würde funktionieren, aber ich frage mich, ob es etwas schneller gibt, wenn die DataValue-Tabelle schließlich 100 Millionen Zeilen enthält. – finoutlook

+0

Wenn der Primärschlüssel geclustert ist und die Tabelle einen äquivalenten Index hat Es sollte kein Problem sein (oder zumindest kein Problem mehr als jede andere Lösung, die nach Duplikaten sucht). Hat der Haltetisch jemals "alte" Daten oder hängen Sie immer neue Daten an? Sie könnten where-Klauseln hinzufügen, die das Datum auf etwas Vernünftiges begrenzen, wie vor zwei Tagen, und wenn 'DateStamp' die führende Spalte im Primärschlüssel ist, sollte das ein wenig helfen. Aber nur wenn Sie immer neue Daten in der Warteschleife haben. –

+1

Danke Ich ging mit dieser Lösung – finoutlook

15

In SQL Server 2008+:

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

Ich dachte, eine Zusammenführung zu verwenden, aber mit DataValue 10m + Zeilen und tmp_holding_DataValue etwa 2m Zeilen, dachte ich, es würde eine lange Zeit dauern, da es alle Daten zurück zum Anfang der Zeit in dieser Tabelle überprüft würde. – finoutlook

+0

@finoutlook: Mit anderen Worten, Sie haben vorzeitig optimiert? Probier es einfach. – Quassnoi

+1

Ich plane immer das Schlimmste und hoffe auf das Beste ..! Ich gebe es eine Chance – finoutlook

15

Sie konnten die PK zuweisen als Duplikate Key ignorieren = Ja. Dann gibt es nur einen Warnhinweis, der ignoriert wird, und ignoriert den Vorgang. Ich rate nicht. Ich habe das getestet.

Was ich gefunden habe ist, dass ich dies nicht tun kann, ist SMSS. Sie müssen den Index über das Skript löschen und neu erstellen. Aber Sie können mit der rechten Maustaste auf den Index klicken, Drop wählen und neu erstellen, und dann einfach Ignore Duplicate Key = Yes ändern. Für mich hat SMSS die Änderung nicht sofort angezeigt.

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 

Oder ich denke, Sie eine äußere

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

Ich sah dies anderswo vorgeschlagen, aber wollte den Primärschlüssel wie es war. Es ist ziemlich kritisch, dass es keine Duplikate in der endgültigen Tabelle "DataValue" gibt. – finoutlook

+4

Warum ist das schwierig? 'WITH (IGNORE_DUP_KEY = ON);' Auch @finoutlook haben Sie diese Option in einer einfachen Tabelle versucht? Es ist immer noch ein Primärschlüssel und Duplikate sind immer noch nicht erlaubt. Die Einstellung 'IGNORE_DUP_KEY' steuert lediglich, wie SQL Server Schlüsselverletzungen behandelt (mit einer Ausnahme oder mit einer einfachen Statusmeldung, die besagt, dass 'Duplicate key ignored' ist.). –

+2

Es ist immer noch ein PK und es wird erzwungen. Der Unterschied besteht darin, dass eine PK-Verletzung nur eine Warnung ist und weiterhin Zeilen einfügt, wenn Duplicate Key ignorieren = Yes. – Paparazzi

0

Ich lief in eine ähnliche Anforderung beitreten verwenden könnte, die den gleichen doppelten Schlüssel Fehler werfen beendet, und dann war die Idee, mehrere Spalten auszuwählen, die distinct (Primary), während der Rückkehr auch andere Spalten, check:

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

In der Tat könnte das Ziel ohne Distinct als auch seit dem Aggregat Spaß erreicht werden ction MAX wählt einen einzelnen Wert aus.