webentwicklung-frage-antwort-db.com.de

Überspringen/ignorieren Sie doppelte Zeilen beim Einfügen

Ich habe folgende Tabellen:

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 sind die Primärschlüsselspalten.

Ich mache eine Einfügung, die den ganzen Tag (in einer gespeicherten Prozedur) regelmäßig ausgeführt wird:

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

Dadurch werden Daten aus der Haltetabelle (tmp_holding_DataValue) in die Hauptdatentabelle (DataValue) verschoben. Die Ablagetabelle wird dann abgeschnitten.

Das Problem ist, dass die Haltetabelle 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, die INS-Prozedur mit einer where-Klausel zu versehen. Die Hauptdatentabelle enthält jedoch mehr als 10 Millionen Zeilen. Dies kann sehr lange dauern.

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

21
finoutlook
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);
26
Aaron Bertrand

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
18
Quassnoi

Sie können den PK als Ignore Duplicate Key = Yes zuweisen. Dann wird nur eine Warnung angezeigt, dass der doppelte Schlüssel ignoriert wird und der Vorgang fortgesetzt wird. Ich vermute nicht. Ich habe das getestet. 

Was ich gefunden habe ist, dass ich dies nicht tun kann, ist SMSS. Muss den Index per Skript löschen und neu erstellen. Sie können jedoch mit der rechten Maustaste auf den Index klicken, die Option zum Ablegen und erneuten Erstellen auswählen und dann einfach Ignore Duplicate Key = Yes ändern. Für mich zeigte SMSS die Änderung nicht sofort.

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 könnten einen äußeren Join verwenden 

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
16
paparazzo

Ich stieß auf eine ähnliche Anforderung, die letztendlich denselben doppelten Schlüsselfehler auslöste. Dann sollten mehrere Spalten (Primär) ausgewählt werden, während auch andere Spalten zurückgegeben werden: check

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

Tatsächlich könnte das Ziel auch ohne Distinct erreicht werden, da die Aggregatfunktion MAX einen einzelnen Wert auswählen wird.

0
usefulBee