【问题标题】:Delete from source table then insert to target table if not exists从源表中删除,如果不存在则插入到目标表
【发布时间】:2013-08-06 05:33:26
【问题描述】:

需要从源表中删除所有行,然后将删除的行插入到目标表中
仅当目标表中尚不存在已删除的行时。
是否可以使用单个 sql 发出问题?

代码是我迄今为止尝试过的代码(尽管有错误)。 谢谢你!

create table #Target (column01 varchar(100)  
        ,employee_number varchar(10)  
                    )
 Insert into #Target (column01, employee_number)  
values ('2','222')  

create table #Srs (column01 varchar(100)  
        ,employee_number varchar(10)  
                )  

 Insert into #Srs (column01, employee_number)  
 values ('1','111')  
    ,('2','222')  
    ,('3','333')  
        ,('4','444')  


;with cteTable as (Select column01, employee_number from #Srs)  
insert into #Target (column01, employee_number)  
select * from (Delete from cteTable output deleted.column01, deleted.employee_number)  t  
where   not exists (select 1  
        from #Target t1  
        where t1.employee_number = t.employee_number)  

在调用“;with cteTable..”时,不应将 2,'222' 插入到 #Target 中

SQL FIDDLE DEMO

【问题讨论】:

  • 您可能想了解 MERGE 的功能
  • 嗨 Raj,我还没有尝试过那种方法来插入 Merge 语句。我可以使用 Merge 对源表进行删除吗?
  • 根据定义,DML 不允许您在一个语句中影响 2 个表。 MERGE 只影响一个目标表。 SQL Server 中最接近的内容是 OUTPUT 子句,但它适用于所有受影响的行。
  • @LuisLL - 使用composable DML,您可以对行应用过滤器,但它不允许WHERE 中的子查询

标签: sql-server sql-server-2008


【解决方案1】:

可组合的 DML 非常有限。

如果你改变#Target的定义,你可以这样做

CREATE TABLE #Target
  (
     column01        VARCHAR(100),
     employee_number VARCHAR(10) PRIMARY KEY WITH (IGNORE_DUP_KEY=ON)
  )

INSERT INTO #Target
            (column01,
             employee_number)
VALUES      ('2',
             '222')

CREATE TABLE #Srs
  (
     column01        VARCHAR(100),
     employee_number VARCHAR(10)
  )

INSERT INTO #Srs
            (column01,
             employee_number)
VALUES      ('1', '111'),
            ('2', '222'),
            ('3', '333'),
            ('4', '444');

WITH cteTable
     AS (SELECT column01,
                employee_number
         FROM   #Srs)
INSERT INTO #Target
            (column01,
             employee_number)
SELECT * from (Delete from cteTable output deleted.column01, deleted.employee_number)  t  

【讨论】:

  • 谢谢马丁。但是,目标表包含主键,ID 定义为 int 作为 Identity,而不是employee_number(w/c 我没有包含在 DDL 中)。
  • @Elmer - 你可以使用employee_number VARCHAR(10) UNIQUE WITH (IGNORE_DUP_KEY=ON) 然后(如果意图是不应该有任何重复)。除此之外,不可能在单个语句中执行此操作(除非使用 INSTEAD OF 触发器作弊)
  • 嗨,马丁。实际上,我需要检查两列中的重复条目(对不起,我的 DDL 中没有指定)。它是员工编号和 transaction_date 列。
  • @Elmer - 那么UNIQUE(employee_number, transaction_date) WITH (IGNORE_DUP_KEY=ON)。如果这是唯一的,则无论如何都应该使用唯一索引来保护它。但可能我只会OUTPUT INTO 一个表变量然后使用MERGE 只插入所需的行。
  • 嗨,马丁。我按照您的建议输出到表变量中,然后使用 MERGE。由于某些公司政策,我无法更新现有表的 DDL。这建议有所作为。感谢您的帮助... :)
【解决方案2】:

必须只有一个语句吗?如果没有,您可以使用它。

begin transaction;

insert into Target(column01, employee_number)
select column01, employee_number
from Srs with (updlock, holdlock)
except
select column01, employee_number
from Target;

delete from Srs;

commit transaction;

【讨论】:

  • 嗨,米凯尔。删除是否安全?如果有一段时间,有人在 Srs 上发出插入,我担心它也会被删除。请指教
  • @Elmer 然后你需要使用一个事务。我已经更新了答案。
  • 谢谢米凯尔。这对可能的选择有很大帮助。
猜你喜欢
  • 1970-01-01
  • 2021-11-17
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
  • 2020-05-20
  • 2013-02-23
相关资源
最近更新 更多