2012-05-22 3 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 

DateStamp и ItemId являются столбцы первичного ключа.

Я делаю вставку, которая работает периодически в течение дня (в хранимой процедуре):

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

Это перемещает данные из удерживающего таблицы (tmp_holding_DataValue) через в основной таблице данных (DataValue). Стол удерживания затем усекается.

Проблема заключается в том, что, как и в примере, таблица хранения может содержать элементы, которые уже существуют в основной таблице. Поскольку ключ не позволит дублировать значения, процедура завершится неудачно.

Один из вариантов заключается в том, чтобы поместить предложение where в вставку proc, но в таблице основных данных имеется 10 миллионов + строк, и это может занять много времени.

Есть ли другой способ заставить процедуру просто пропускать/игнорировать дубликаты при попытке вставить?

+0

Что делать, если столбец «Значение» в таблице удержания отличается, например. для первой строки это '3253' вместо' 6541'? Это еще дубликат? Если нет, это то, что вы хотите обновить (например, добавить «6541 + 3253» в исходную таблицу) или просто заменить? –

+0

Столбец значения не имеет значения, если его отличие игнорируется, то, что находится в DataValue уже для этой datestamp, должно быть оставлено как-есть – 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 в конечном итоге заканчивается 100 миллионами строк. – finoutlook

+0

Если первичный ключ кластерный и таблица удержания имеет эквивалентный индекс, тогда это не должно быть проблемой (или, по крайней мере, не более проблемой, чем любое другое решение, проверяющее наличие дубликатов). Есть ли у холдинга таблицы «старые» данные, или вы всегда добавляете довольно новые данные? Вы можете добавить, где клаузулы, которые ограничивают дату чем-то разумным, как и два дня назад, и если 'DateStamp' является ведущим столбцом первичного ключа, это должно немного помочь. Но только если у вас всегда есть новые данные в таблице холдинга. –

+1

Спасибо, что я пошел с этим решением – finoutlook

15

В 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

Я думал об использовании слияния, но с DataValue было 10 м + строк, а tmp_holding_DataValue было около 2 м строк, я думал, что это займет много времени, так как он будет проверять все данные до начала времени в этой таблице. – finoutlook

+0

@finoutlook: другими словами, вы оптимизировали преждевременно? Просто попробуйте. – Quassnoi

+1

Я всегда планирую худшее и надеюсь на лучшее ..! Я дам ему выстрел – finoutlook

15

Вы можете назначить ПК в качестве Ignore дубликат ключа = Да. Затем он будет просто игнорировать дубликат ключа и продолжать. Я не догадываюсь. Я проверил это.

То, что я нашел, это то, что я не могу это сделать, это SMSS. Необходимо отбрасывать и воссоздавать индекс через скрипт. Но вы можете щелкнуть правой кнопкой мыши по индексу, выбрать drop and rereate, а затем просто изменить Ignore Duplicate Key = Yes. Для меня 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 обрабатывает ключевые нарушения (с исключением или с простым сообщением о состоянии, в котором говорится, что' Duplicate key был проигнорирован. '). –

+2

Есть еще ПК, и он соблюдается. Разница в том, что нарушение PK является просто предупреждением и продолжает вставлять строки, когда Ignore Duplicate Key = Yes. – Paparazzi

0

я столкнулся с подобным требованием, чтобы в конечном итоге бросать же дубликат ключа ошибки, а затем идея состояла в том, чтобы выбрать несколько столбцов, которые отчетливые (Primary), а возвращающиеся и другие столбцы, check:

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

на самом деле, цель может быть достигнута без отчетливых, а с совокупным удовольствия ction MAX выберет одно значение.

Смежные вопросы