Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 插入时跳过/忽略重复行_Sql Server_Sql Server 2008_Tsql_Stored Procedures - Fatal编程技术网

Sql server 插入时跳过/忽略重复行

Sql server 插入时跳过/忽略重复行,sql-server,sql-server-2008,tsql,stored-procedures,Sql Server,Sql Server 2008,Tsql,Stored Procedures,我有以下表格: DataValue DateStamp ItemId Value ---------- ------ ----- 2012-05-22 1 6541 2012-05-22 2 12321 2012-05-21 3 32 DateStamp ItemId Value ---------- ------ ----- 2012-05-22 1 6541 2012-05-22

我有以下表格:

DataValue

DateStamp    ItemId   Value
----------   ------   -----
2012-05-22   1        6541
2012-05-22   2        12321
2012-05-21   3        32
DateStamp    ItemId   Value
----------   ------   -----
2012-05-22   1        6541
2012-05-22   4        87
2012-05-21   5        234
tmp\u holding\u数据值

DateStamp    ItemId   Value
----------   ------   -----
2012-05-22   1        6541
2012-05-22   2        12321
2012-05-21   3        32
DateStamp    ItemId   Value
----------   ------   -----
2012-05-22   1        6541
2012-05-22   4        87
2012-05-21   5        234
DateStamp
ItemId
是主键列

我正在执行一个插入操作,该操作在一天中定期运行(在存储过程中):

这会将数据从保留表(
tmp\u holding\u DataValue
)移到主数据表(
DataValue
)中。然后截断保留表

问题在于,如示例中所示,保留表可能包含主表中已经存在的项。由于该键不允许重复值,因此该过程将失败

一种选择是在insert proc上放置where子句,但是主数据表有1000多万行,这可能需要很长时间


有没有其他方法让过程在尝试插入时跳过/忽略重复项?

SQL Server 2008+
中:

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);
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 SET
        value = t.value
*/
-- Uncomment above to rewrite duplicates rather than ignore them

您可以将PK分配为Ignore replicate Key=Yes。然后它只会给出一个警告,重复键被忽略并继续。我不是在猜测。我测试了这个

我发现我做不到这是SMSS。必须通过脚本删除并重新创建索引。但您可以右键单击索引,选择drop and recreate,然后只需更改Ignore Duplicate Key=Yes。对我来说,SMS并没有立即显示出变化

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

我遇到了一个类似的要求,最终抛出了相同的重复键错误,然后我们的想法是选择多个不同的列(主列),同时返回其他列:



事实上,由于聚合函数MAX将选择单个值,因此该目标也可以在不使用Distinct的情况下实现。

如果保留表中的
value
列不同,例如,第一行是
3253
,而不是
6541
?那还是复制品吗?如果不是,则是要更新的内容(例如,在源表中添加
6541+3253
)还是简单地替换?值列不重要,如果它不同,则忽略它,该日期戳的数据值中已经包含的内容应该保留为isIt,用您需要支持的最低版本的SQL Server标记您的问题也是非常有用的。我没有提供
MERGE
解决方案,因为最初我完全不知道您使用的是哪个版本。@AaronBertrand-是的,我应该提到我使用的是2008(很快就要到2012年了)。在这种情况下,你会使用merge而不是where吗?我不确定,我仍然觉得
merge
语法让人望而生畏,一般来说,我不太愿意推荐它。我不确定是否所有的合并错误都已修复(请参阅a)。如果您的关键目标是性能,那么您需要测试它们,并确保(a)它们做了正确的事情,(b)您选择了在您的环境中性能最好的on。我们无法预测这些答案…我确实想过使用合并,但由于DataValue为1000多万行,tmp_持有的DataValue约为200万行,我认为这将需要很长时间,因为它将检查该表中的所有数据,直到时间的开始…@finoutlook:换句话说,您过早优化了吗?试试看。我总是做最坏的打算,希望是最好的。。!我会试一试这会管用的,但我想知道如果DataValue表最终有1亿行,是否还有更快的方法如果主键是集群的,并且保留表有一个等价的索引,那么它应该不会是一个问题(或者至少不会比任何其他检查重复项的解决方案更麻烦)。保留表是否有“旧”数据,或者您是否总是附加一些新的数据?您可以添加where子句,将日期限制在合理的范围内,比如两天前,如果主键中的前导列是
DateStamp
,这应该会有所帮助。但前提是你总是在等待表中有新的数据。谢谢,我同意了solution@finoutlook如果I/O成为一个问题,或者您想限制表上的争用,您可以使用类似于
selecttop1000
的方法批量运行它。由于每次迭代都会在以后的执行中插入不合格的记录,这将允许您限制对服务器的影响程度。如果您的目标是最终移动所有内容,那么您不必麻烦使用
ORDER BY
,因为您不再关心SELECT是否是确定性的。我在别处看到了这一建议,但希望保留原样的主键。在最终的
DataValue
表中没有重复项是非常关键的。为什么这很棘手<代码>带有(忽略重复键=打开)还有@finoutlook您在一个简单的表上尝试过这个选项吗?它仍然是主键,不允许重复。
IGNORE\u DUP\u KEY
设置仅控制SQL Server处理密钥冲突的方式(异常情况或简单的状态消息表明
Duplicate KEY已被忽略。
)。仍然存在PK,并强制执行。不同之处在于PK冲突只是一个警告,当Ignore Duplicate Key=Yes时,它会继续插入行。@AaronBertrand ALTER INDEX[PK_PKallowDup]ON[dbo]。[PKallowDup]REBUILD WITH(Ignore_DUP_Key=ON);对我来说失败了。这个语法正确吗?我说我考过了。我可以使用该条件创建表,也可以在空表上删除并创建。不认为OP想要删除他的表行。为了便于将来参考,如果PK是聚集键,则可以使用ALTER table dbo.PKallowDup REBUILD with(IGNORE_DUP_key=ON)执行此操作。奇怪的是,它不允许您指定PK名称,但哦,好吧:-)