web-dev-qa-db-fra.com

Ignorer/ignorer les lignes en double lors de l'insertion

J'ai les tables suivantes:

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 et ItemId sont les colonnes de clé primaire.

Je fais un insert qui fonctionne périodiquement tout au long de la journée (dans une procédure stockée):

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

Cela déplace les données de la table de stockage (tmp_holding_DataValue) dans la table de données principale (DataValue). La table de maintien est alors tronquée.

Le problème est que, comme dans l'exemple, la table de stockage peut contenir des éléments qui existent déjà dans la table principale. Étant donné que la clé n'autorisera pas les valeurs en double, la procédure échouera.

Une option serait de placer une clause where sur le processus d'insertion, mais la table de données principale contient plus de 10 millions de lignes, ce qui peut prendre beaucoup de temps.

Existe-t-il un autre moyen de faire en sorte que la procédure ignore ou ignore les doublons lors de la tentative d'insertion?

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

Vous pouvez attribuer à la clé la clé Ignore Duplicate Key = Yes. Ensuite, il va simplement donner une clé de duplication d'avertissement ignoré et continuer. Je ne devine pas. J'ai testé cela. 

Ce que j'ai trouvé, c'est que je ne peux pas faire cela, c'est SMSS. Doit supprimer et recréer l'index via un script. Mais vous pouvez faire un clic droit sur l’index, sélectionner déposer et recréer, puis simplement changer Ignore Duplicate Key = Yes. Pour moi, SMSS n'a pas immédiatement montré le changement.

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

Ou je pense que vous pourriez utiliser une jointure externe 

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

J'ai rencontré une exigence similaire qui a fini par générer la même erreur de clé en double, puis l'idée était de sélectionner plusieurs colonnes distinctes (Primaire) tout en renvoyant d'autres colonnes, check

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

En fait, l'objectif pourrait être atteint sans Distinct également puisque la fonction d'agrégat MAX sélectionnera une valeur unique.

0
usefulBee