SQL:将所有记录从一个表插入另一个表而不指定列

问题描述 投票:11回答:7

我想将备份表foo_bk中的所有记录插入到foot table中而不指定列。

如果我尝试这个查询

INSERT INTO foo 
SELECT *
FROM foo_bk

我将收到错误“插入错误:列名称或提供的值的数量与表定义不匹配”。

是否可以在不提供列名的情况下从一个表批量插入到另一个表?我谷歌它但似乎无法找到答案。所有答案都需要特定的列。

sql sql-server syntax
7个回答
17
投票

你不应该想要这样做。选择*不应该用作插入的基础,因为列可能会移动并破坏插入(或者更糟糕的是不会破坏插入但是会弄乱你的数据。假设有人在select中添加了一列而不是在其他表中,您的代码将会中断。或者假设有人因为超出理解但经常发生的原因,决定执行删除并在表上重新创建并将列移动到不同的顺序。现在您的last_name是第一个名称是在原来和select *中会将它放在另一个表中的错误列中。如果无法指定列,并且无法在您感兴趣的表中指定一列到您想要的列的特定映射,那么这是一种非常糟糕的做法。

现在你可能有几个问题,首先两个结构不直接匹配,或者第二个被插入的表有一个标识列,所以即使可插入的列是直接匹配,插入的表还有一列比另一个并且未指定数据库假定您将尝试插入该列。或者您可能具有相同数量的列,但一个是标识,因此无法插入(尽管我认为这将是一个不同的错误消息)。


11
投票

根据这篇文章:Insert all values of a...,您可以执行以下操作:

INSERT INTO new_table (Foo, Bar, Fizz, Buzz)
SELECT Foo, Bar, Fizz, Buzz
FROM initial_table

指定列名称非常重要,如其他答案所示。


10
投票

用这个

SELECT *
INTO new_table_name
FROM current_table_name

2
投票

您需要至少具有相同数量的列,并且必须以完全相同的方式定义每个列,即无法将varchar列插入到int列中。

对于批量传输,请查看您正在使用的SQL实现的文档。通常有工具可用于将数据从一个表批量传输到另一个表。例如,对于SqlServer 2005,您可以使用SQL Server导入和导出向导。右键单击要尝试移动数据的数据库,然后单击“导出”以访问它。


1
投票

如果使用SELECT INTO而不是INSERT INTO / SELECT,SQL 2008允许您放弃在SELECT中指定列名:

SELECT *
INTO Foo
FROM Bar
WHERE x=y

INTO子句确实存在于SQL Server 2000-2005中,但仍需要指定列名。 2008似乎增加了使用SELECT *的能力。

有关详细信息,请参阅INTO(SQL2005),(SQL2008)上的MSDN文章。

但是,INTO子句仅在目标表尚不存在时才有效。如果您要将记录添加到现有表中,这将无济于事。


0
投票

正如你可能从之前的答案中所理解的那样,你无法真正做到你所追求的。我想你可以理解SQL Server遇到的问题,不知道如何映射其他/缺少的列。

也就是说,既然你提到你在这里尝试的目的是备份,也许我们可以使用SQL Server并解决问题。不知道你的具体情况使得无法在这里找到正确的答案,但我假设如下:

  • 您希望管理表的备份/审核过程。
  • 您可能有一些这些并希望避免在每个列添加/删除时更改依赖对象。
  • 备份表可能包含其他列以供审核。

我想为您推荐两种选择:

对此有效的实践(IMO)可以是使用DDL触发器检测模式更改,并使用它们相应地更改备份表。这将使您能够使用'select * from ...'方法,因为列表将在两个表之间保持一致。

我已成功使用此方法,您可以利用它来让DDL触发器自动管理您的审计表。在我的例子中,我对需要审计的表使用了命名约定,而DDL触发器只是在运行时管理它。

对您的特定方案可能有用的另一个选项是为对齐列列表的表创建支持视图。这是一个简单的例子:

create table foo (id int, name varchar(50))
create table foo_bk (id int, name varchar(50), tagid int)
go

create view vw_foo as select id,name from foo 
go

create view vw_foo_bk as select id,name from foo_bk
go

insert into vw_foo
    select * from vw_foo_bk 
go

drop view vw_foo
drop view vw_foo_bk
drop table foo
drop table foo_bk
go

我希望这有帮助 :)


0
投票

上面的所有答案,由于某种原因,在SQL Server 2012上对我不起作用。我的情况是我意外删除了所有行而不是一行。在我们的DBA将表恢复到dbo.foo_bak后,我使用以下内容进行恢复。注意:这仅适用于备份表(由dbo.foo_bak表示)和您要写入的表(dbo.foo)具有完全相同的列名称。

这对我来说使用了一堆不同答案的混合:

USE [database_name];
GO
SET IDENTITY_INSERT dbo.foo ON;
GO
INSERT INTO [dbo].[foo]
           ([rown0]
           ,[row1]
           ,[row2]
           ,[row3]
           ,...
           ,[rown])
     SELECT * FROM [dbo].[foo_bak];
GO
SET IDENTITY_INSERT dbo.foo OFF;
GO

如果您有主键和外键,这个版本的答案会很有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.