自动匹配INSERT INTO ... SELECT ... FROM中的列

时间:2009-11-24 03:43:11

标签: sql sql-server tsql select insert

SQL Server问题。 做的时候

INSERT INTO T1 SELECT (C1, C2) FROM T2

我不想指定T1的列名,因为它们与T2

中的相同

是否可以这样做?

目前我收到错误

  

Msg 213,Level 16,State 1,Line 1

     

列名或提供的值与表定义不匹配。

8 个答案:

答案 0 :(得分:18)

始终在INSERT和SELECT投影中都使用显式列。即使你不想,你应该:

INSERT INTO T1 (C1, c2)
SELECT C1, C2 FROM T2

答案 1 :(得分:13)

是的,您可以省略插入的表的字段名称,并且可以使用select *来获取表中的所有字段,但我不建议使用此方法。

如果省略字段名称,则字段按位置匹配,而不是按名称匹配。如果字段的顺序不完全相同,则会混淆。通常,您应该避免依赖表的确切布局,以最大程度地降低表中更改破坏查询的风险。

答案 2 :(得分:3)

如果T1T2完全匹配,您有两个选择。您可以select T2 insert into T1的所有列insert,也可以为select语句提供列列表。

即使您执行insert MSSQL提供的列标题,{{1}}语句也不会使用该信息来匹配列。

答案 3 :(得分:1)

为什么不简单

INSERT INTO t1
SELECT * FROM T2

答案 4 :(得分:0)

如果您担心列名称,您可以随时为它们添加别名:

INSERT INTO T1 (C1, c2)
SELECT C1 AS C1_ALIAS, C2 AS C2_ALIAS FROM T2

或者,更简洁:

INSERT INTO T1 (C1, c2)
SELECT C1 C1_ALIAS, C2 C2_ALIAS FROM T2

虽然我不能真正想到为什么人们会想要这样一个简单的例子

答案 5 :(得分:0)

首先选择这个sql,从sql结果中选择你的表行并更改目标或源表名。如果表具有相同的列(不需要相同的顺序),它将起作用。

 with xparams as (      select (select user from dual) "OWNER", '' "ADDSTRTOFROMTABLENAME" from dual  )
  ,t1 as (  SELECT dbat.table_name from dba_tables dbat, xparams where dbat.owner = xparams.OWNER )
  ,t1c1 as (  SELECT utcs.table_name ,  LISTAGG(utcs.column_name,',') within group (order by utcs.column_name) "COLS"  from USER_TAB_COLUMNS utcs, t1 where utcs.table_name = t1.table_name group by utcs.table_name )
  ,res1 as ( SELECT 'insert into '|| t1c1.table_name || ' ( '|| t1c1.COLS ||') select '|| t1c1.COLS || ' from ' || t1c1.table_name||xparams.ADDSTRTOFROMTABLENAME ||';' "RES" from t1c1, xparams order by t1c1.table_name )
select * from res1

答案 6 :(得分:0)

其他答案是好的,但没有解释为什么不好用:

INSERT INTO T1
SELECT * FROM T2

在评论中,OP讨论了使用更安全的方法指定列时的代码重复:

INSERT INTO T1 (C1, c2)
SELECT C1, C2 FROM T2

但是,如果您不确定,您将依赖始终匹配的列数以及期望的列顺序。如果更改其中一个表以添加一个逻辑,则该逻辑将中断 柱。

此外,您还会遇到无声错误的麻烦。如果您使用具有相同列数但位置不同的表:


CREATE TABLE tab1 (col1 int, col2 string);

CREATE TABLE tab2 (col1 string, col2 int);

INSERT INTO tab1 values(1, 'aaa');

INSERT INTO TABLE tab2 select * FROM tab1;

然后,您可能希望您进行了复制,以使tab1和tab2相同。我想要的是:

+-------------------+-------------------+
| tab2.col1         | tab2.col2         |
+-------------------+-------------------+
| 1                 | aaa               |
+-------------------+-------------------+

但是它将根据列位置加载并转换数据,所以我得到的是:

+-------------------+-------------------+
| tab2.col1         | tab2.col2         |
+-------------------+-------------------+
| 1                 | NULL              |
+-------------------+-------------------+

发生的事情是它无法将字符串转换为int,因此将其设置为NULL。它可以将int转换为字符串“ 1”,而不再是数字类型。

即使列确实匹配,任何人都可以做:

ALTER TABLE tab1 ADD COLUMNS (col3 string COMMENT 'a new column');

此后,未指定列的查询将中断,说明两个表中的列数不匹配。它将不再能够将数据移到tab2中。

这意味着安全的做法是使用SQL明确:

INSERT INTO T1 (C1, c2)
SELECT C1, C2 FROM T2

如果有人只是想快速获取表的副本,则某些SQL引擎支持

CREATE TABLE tab3 AS SELECT * FROM tab1;

在这种情况下,请确保键入列是浪费时间,并且如果有人在克隆之前在tab1中添加列,则显式将无法克隆新列。所有反例显示的是,仅编程经验法则没有绝对的规则。如果您不希望在运行时出现静默错误,而又不想在有人添加新功能时发现错误,则SQL(以及任何其他具有隐式转换的松散类型的语言)的经验法则应尽可能具体。

答案 7 :(得分:-1)

参考如下:

INSERT INTO NEWTABLENAME COL1[,COL2,..COLN]
SELECT COL1[,COL2,..COLN] FROM THE EXISTINGTABLENAME