【问题标题】:Skip insert (and continue) on duplicate key [T-SQL]在重复键上跳过插入(并继续)[T-SQL]
【发布时间】:2018-01-16 00:48:39
【问题描述】:

我正在尝试为一个可以说非常简单的任务找到一个可行的解决方案:

我有一个这样的简单查询:

INSERT INTO [INTRANET].[dbo].[SOME_STATUS]
   ([AUS_STATUS_VID]
  ,[AUS_STATUS_STATUS]
  ,[AUS_STATUS_JAHR]
  ,[AUS_STAUTS_END]
 )

SELECT DISTINCT CD_CLVID, '1', '2017', '0'
FROM [SNTRANET].[dbo].[SOME_DETAILS]
WHERE CD_JAHR = 2017     

长话短说:用另一个表的结果填满一个表。现在看来,我收到的数据不一致。我试图找到类似于replace intoon duplicate key update 的解决方案(我习惯于使用MySQL)。但是,T-SQL 似乎没有这个。

是否有一个简单的解决方案可以跳过重复密钥并继续处理结果集的其余部分?

我使用的是 SQLServer 2008 R2

编辑 1

根据要求,错误消息:

违反主键约束“PK_T_KB_AUSZAHLUNG_STATUS”。无法在对象“dbo.T_KB_AUSZAHLUNG_STATUS”中插入重复键。重复键值为 (7463)。

【问题讨论】:

  • 我能提供的最好的方法是 IF NOT EXIST (SELECT ...) BEGIN /*insert your insert :)*/ END
  • 哪一列是重复键?
  • 重复从哪里来?如果我正确阅读了您的查询,则 select 语句会返回一个不同的 CD_CLVIDs 列表。如果[INTRANET].[dbo].[SOME_STATUS] 中的AUS_STATUS_VID 期望唯一值,它应该得到它们。你能提供create table语句吗?错误消息也会有所帮助。
  • @destination-data 添加了错误消息。您需要哪个创建表?了解状态或详细信息?
  • 两者都很好。如果您可以输入一些重现错误的示例数据,那就更好了!

标签: sql-server tsql


【解决方案1】:

您可以使用SQL Server Merge Join 功能。如果未找到匹配项,它将插入新行,否则更新匹配项的现有记录

例子:

MERGE BookInventory bi
USING BookOrder bo
ON bi.TitleID = bo.TitleID
WHEN MATCHED THEN
  UPDATE
  SET bi.Quantity = bi.Quantity + bo.Quantity
WHEN NOT MATCHED BY TARGET THEN
  INSERT (TitleID, Title, Quantity)
  VALUES (bo.TitleID, bo.Title,bo.Quantity);

如果在 BookOrder .TitleId 表 BookInventory 中找到匹配项,则插入记录,否则将更新匹配的记录。

您也可以使用多个语句来实现相同的目的。像这样

IF EXISTS(SELECT 1 FROM YourTable WHERE <Condition>
BEGIN
    <Update Statements>
END
ELSE
BEGIN
     <Insert Statement>
END

或者在直接插入中,只要勾选存在就可以跳过Target表中已经存在的记录

INSERT INTO TargetTable
SELECT * FROM SourceTable ST
WHERE NOT EXISTS
(
    SELECT 1 FROM TargetTable WHERE TargetId = ST.TargetId 
)

【讨论】:

【解决方案2】:

如果重复键是 [AUS_STATUS_VID] 列,则尝试在表上使用别名并且不存在

INSERT INTO [INTRANET].[dbo].[SOME_STATUS]
   ([AUS_STATUS_VID]
  ,[AUS_STATUS_STATUS]
  ,[AUS_STATUS_JAHR]
  ,[AUS_STAUTS_END]
 )
SELECT DISTINCT S.CD_CLVID, '1', '2017', '0'
FROM [SNTRANET].[dbo].[SOME_DETAILS] S
WHERE S.CD_JAHR = 2017
AND NOT EXISTS
(
  SELECT SS.AUS_STATUS_VID FROM [INTRANET].[dbo].[SOME_STATUS] SS
  WHERE SS.AUS_STATUS_VID = S.CD_CLVID
) ;

【讨论】:

    【解决方案3】:

    使用 ROW_NUMBER() 确保传入的结果没有重复,然后使用 WHERE 子句确保它不存在于目标表中

    SELECT col1, col2, col3, ...
    FROM
    (
        SELECT *, RN = ROW_NUMBER() OVER (PARTITION BY PK_COL ORDER BY some_col)
        FROM   SOME_TABLE
    ) d
    WHERE d.RN = 1
    AND   NOT EXISTS
          (
               SELECT *
               FROM   DEST_TABLE x
               WHERE  x.PK_COL = d.PK_COL 
          )
    

    【讨论】:

    • 这对 OP 没有帮助。如果重复项包含在他尝试从中插入的数据集中,则此方法有效,但问题似乎是数据集与目标表中已有的数据重叠。 – SchmitzIT 刚刚
    • 我觉得 distinct 更直接更高效
    • distinct 不需要确保要插入的行没有重复的主键值
    【解决方案4】:
    INSERT INTO [INTRANET].[dbo].[SOME_STATUS]
       ( [AUS_STATUS_VID]
        ,[AUS_STATUS_STATUS]
        ,[AUS_STATUS_JAHR]
        ,[AUS_STAUTS_END]
       )
    
    SELECT DISTINCT D.CD_CLVID, '1', '2017', '0'
    FROM [SNTRANET].[dbo].[SOME_DETAILS] D
    LEFT JOIN [INTRANET].[dbo].[SOME_STATUS] S 
    ON S.CD_CLVID = D.CD_CLVID 
    WHERE D.CD_JAHR = 2017   
    AND S.CD_CLVID is null
    

    如果 CD_CLVID 是 [SNTRANET].[dbo].[SOME_DETAILS] 中的 PK,那么您将不需要不同的

    【讨论】:

      猜你喜欢
      • 2020-07-13
      • 1970-01-01
      • 2022-01-22
      • 2018-06-18
      • 1970-01-01
      • 1970-01-01
      • 2019-03-11
      • 2016-07-05
      相关资源
      最近更新 更多