将SQL数据从一个表移动到另一个表


76

我想知道是否有可能将所有数据行从一个表移动到另一个表,以匹配某个查询?

例如,我需要将所有表行从表1移动到表2,其中用户名=“ X”,密码=“ X”,以便它们不再出现在表1中。

我正在使用SQL Server 2008 Management Studio。

Answers:


129

应该可以在一个事务中使用两个语句,即插入和删除:

BEGIN TRANSACTION;
INSERT INTO Table2 (<columns>)
SELECT <columns>
FROM Table1
WHERE <condition>;

DELETE FROM Table1
WHERE <condition>;

COMMIT;

这是最简单的形式。如果您需要担心在两个语句之间的table1中插入了新的匹配记录,则可以添加and exists <in table2>


1
您想确保两个语句都作为一个事务完成。可以说,仅当没有错误发生时,才关闭自动提交,并在删除后执行一次提交。如果插入失败,您可能不想删除,反之亦然。
杰伊,

确实如此,但是即使将它们作为单个事务完成,如果在两个语句的执行过程中发生插入,也可能会出现问题。不会以使事务内的“读取可重复”的方式运行太多数据库。
托尔斯滕,

我相信您可以为交易使用“ SET TRANSACTION ISOLATION LEVEL SERIALIZABLE”,以确保您看不到新记录
Mike L

1
@Dani:不确定您的意思..如果将其发布为新问题并提供更详细的描述/示例,可能会最简单?如果需要,您可以在此答案中添加评论,以便除其他所有Stackoverflow用户之外,还可以查看一下。
Thorsten

1
我不小心删除了我想移动的所有数据,因为BEGIN TRANSACTION;在此示例的开头没有。将其添加到答案的示例中不是一个好主意吗?
Deantwo

47

抱歉,这是一篇古老的文章,但我现在才偶然遇到,我想将我的解决方案提供给可能在这一天迷路的任何人。

正如一些人提到的那样,先执行“ an”INSERT然后执行“ an”DELETE可能会导致完整性问题,因此,一种解决方法以及在单个语句中巧妙地执行所有操作的一种方法就是利用[deleted]临时表。

DELETE FROM [source]
OUTPUT [deleted].<column_list>
INTO [destination] (<column_list>)

3
使用一条DELETE语句,所有记录首先[deleted]在该DELETE子句解析之前写入临时表中,然后从该表中进行处理(在这种情况下,将其插入到另一个表中),然后解析该语句。如果语句的处理部分失败,则终止整个语句;否则,终止整个语句。不仅INTO条款。此外,BEGIN TRY...BEGIN CATCHROLLBACK TRANSACTION都是很好的预防性陈述。
that0th3rGuy 2014年

6
如果目标与外键关系有关,则会遇到问题。您将得到错误:OUTPUT INTO子句的目标表'<destination>'不能位于(主键,外键)关系的任一侧。找到参考约束'<约束名称>'。
Niels Harremoes 2014年

您能在这里解释OUTPUT关键字如何工作吗?似乎正在尝试将已删除的记录放入[deleted]表中,但是[deleted]表不存在(并且永远不会存在)。
GreySage

1
@GreySageOUTPUT关键字仅用于将表数据集返回到后续语句,但是仅在某些情况下有效,例如UPDATE[inserted])且DELETE我记得正确。该[deleted]表是一个隐式的临时表-不能完全确定它的位置或管理该进程的范围-限于当前语句的执行范围。因此,就像您可以执行类似的操作SELECT [source].[column] INTO [destination](在其中SELECT返回数据集并INTO接收数据)一样,您可以使用OUTPUT将已删除的数据集返回到INTO接收数据集的。
that0th3rGuy18年

OUTPUT语句是非标准SQL FWIW(例如,在中不起作用sqlite3)。
ijoseph '18

21

所有这些答案都会对INSERT和DELETE运行相同的查询。如前所述,这冒着删除语句之间插入记录的风险,如果查询很复杂(尽管聪明的引擎“应该”使第二个调用快速执行),这可能会很慢。

正确的方法(假设INSERT已插入到新表中)是使用table2的键字段对table1进行DELETE。

删除应为:

DELETE FROM tbl_OldTableName WHERE id in (SELECT id FROM tbl_NewTableName)

请原谅我的语法,我在引擎之间切换,但是您明白了。


我真的很喜欢..并且可以将UniqueIDs用作您的密钥!
da_jokker,

9

是的。首先执行INSERT + SELECT,然后删除DELETE原点。

INSERT INTO Table2 (UserName,Password)
SELECT UserName,Password FROM Table1 WHERE UserName='X' AND Password='X'

然后删除原件

DELETE FROM Table1 WHERE UserName='X' AND Password='X'

您可能想要保留UserID或其他主键,则可以使用IDENTITY INSERT保留键。

在MSDN上查看有关SET IDENTITY_INSERT的更多信息


8

其他答案暗示的更清晰的表述:

DELETE sourceTable
OUTPUT DELETED.*
INTO destTable (Comma, separated, list, of, columns)
WHERE <conditions (if any)>

5

使用此单个sql语句是安全的,无需使用多个语句进行提交/回滚。

INSERT Table2 (
      username,password
) SELECT username,password
      FROM    (
           DELETE Table1
           OUTPUT
                   DELETED.username,
                   DELETED.password
           WHERE username = 'X' and password = 'X'
      ) AS RowsToMove ;

在SQL Server上可以对MySql进行适当的更改


3

尝试这个

INSERT INTO TABLE2 (Cols...) SELECT Cols... FROM TABLE1 WHERE Criteria

然后

DELETE FROM TABLE1 WHERE Criteria

3

您应该可以在INSERT语句中使用子查询。

INSERT INTO table1(column1, column2) SELECT column1, column2 FROM table2 WHERE ...;

然后从table1中删除。

请记住,将其作为单个事务运行,这样如果出现任何问题,您可以回滚整个操作。


2

您可以尝试以下方法:

SELECT * INTO tbl_NewTableName 
FROM tbl_OldTableName
WHERE Condition1=@Condition1Value

然后运行一个简单的删除:

DELETE FROM tbl_OldTableName
WHERE Condition1=@Condition1Value

2

您可以使用“逻辑分区”在表之间切换数据:

通过更新分区列,数据将被自动移动到另一个表:

这是示例:

CREATE TABLE TBL_Part1
(id  INT NOT NULL,
 val VARCHAR(10) NULL,
 PartitionColumn  VARCHAR(10) CONSTRAINT CK_Part1 CHECK(PartitionColumn = 'TBL_Part1'),
 CONSTRAINT TBL_Part1_PK PRIMARY KEY(PartitionColumn, id)
);

CREATE TABLE TBL_Part2
(id  INT NOT NULL,
 val VARCHAR(10) NULL,
 PartitionColumn  VARCHAR(10) CONSTRAINT CK_Part2 CHECK(PartitionColumn = 'TBL_Part2'),
 CONSTRAINT TBL_Part2_PK  PRIMARY KEY(PartitionColumn, id)
);

GO

CREATE VIEW TBL(id, val, PartitionColumn)
WITH SCHEMABINDING
AS
     SELECT id, val, PartitionColumn FROM dbo.TBL_Part1
     UNION ALL  
     SELECT id, val, PartitionColumn FROM dbo.TBL_Part2;

GO

--Insert sample to TBL ( will be inserted to Part1 )
INSERT INTO TBL
VALUES(1, 'rec1', 'TBL_Part1');

INSERT INTO TBL
VALUES(2, 'rec2', 'TBL_Part1');

GO

--Query sub table to verify
SELECT * FROM TBL_Part1

GO
--move the data to table TBL_Part2 by Logical Partition switching technique
UPDATE TBL
  SET
      PartitionColumn = 'TBL_Part2';

GO

--Query sub table to verify
SELECT * FROM TBL_Part2

1

这是单个语句的处理方式

WITH deleted_rows AS (
DELETE FROM source_table WHERE id = 1
RETURNING *
) 
INSERT INTO destination_table 
SELECT * FROM deleted_rows;

例:

    postgres=# select * from test1 ;
 id |  name
----+--------
  1 | yogesh
  2 | Raunak
  3 | Varun
(3 rows)


postgres=# select * from test2;
 id | name
----+------
(0 rows)


postgres=# WITH deleted_rows AS (
postgres(# DELETE FROM test1 WHERE id = 1
postgres(# RETURNING *
postgres(# )
postgres-# INSERT INTO test2
postgres-# SELECT * FROM deleted_rows;
INSERT 0 1


postgres=# select * from test2;
 id |  name
----+--------
  1 | yogesh
(1 row)

postgres=# select * from test1;
 id |  name
----+--------
  2 | Raunak
  3 | Varun

1
这使用了不正确的语法(在as和返回附近),并且无法按预期方式工作。
GreySage

0

如果两个表使用相同的ID或具有公共的UNIQUE键:

1)将选择的记录插入表2

INSERT INTO table2 SELECT * FROM table1 WHERE (conditions)

2)如果存在于表2中,则从表1中删除所选记录

DELETE FROM table1 as A, table2 as B WHERE (A.conditions) AND  (A.ID = B.ID)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.