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

Posted

技术标签:

【中文标题】自动匹配 INSERT INTO ... SELECT ... FROM 中的列【英文标题】:Automatically match columns in INSERT INTO ... SELECT ... FROM 【发布时间】:2010-12-19 17:55:41 【问题描述】:

SQL Server 问题。 做的时候

INSERT INTO T1 SELECT (C1, C2) FROM T2

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

有可能吗?

目前我遇到了错误

消息 213,第 16 级,状态 1,第 1 行

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

【问题讨论】:

【参考方案1】:

为什么不简单

INSERT INTO t1
SELECT * FROM T2

【讨论】:

我需要跳过一列(身份主键)【参考方案2】:

是的,您可以省略插入到的表的字段名称,并且可以使用 select * 从表中获取所有字段,但我不推荐这种方法。

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

【讨论】:

有没有办法在不指定所有列名的情况下插入除identity key 之外的所有列?我使用的表包含数十列,每次都列出它们真的很无聊。 也许你可以创建一个包含所有你想要的列的视图并从中选择 *。 @Konstantin:不,没有简单的方法可以指定除身份字段之外的所有字段。要么全有,要么全无。 只要列完全相同就可以使用【参考方案3】:

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

即使当您执行select MSSQL 提供列标题时,insert 语句不会使用该信息来匹配列。

【讨论】:

此语句的第二部分不正确 - MSSQL 与列名匹配。 请记住,当您评论一个 12 年前的答案时,中间版本可能已经发生了一些变化。 :)【参考方案4】:

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

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

【讨论】:

这是我想摆脱的代码重复,转而采用约定驱动的方法(具有相同名称的列应该相互映射) SQL 通常是一种冗长的语言。例如,group by 子句在聚合中是多余的,INTO 是多余的。我认为你只需要接受这一点。 这是一个很好的做法,因为数据库系统无法跟踪客户端代码中的依赖关系。可以向 T2 添加一列,也可以重组 T2 以更改列顺序,也可以删除一列,所有操作都会导致代码中断。 这不是代码重复。代码重复将是INSERT INTO T1 (C1, C2) SELECT C1 C1, C2 C2 FROM T2(列别名)。我还认为 SQL 会尝试根据我定义的列别名来匹配列,但它只关心SELECT 中列的顺序。您在 INTO (destCol1, destCol2) 部分中进行绑定。 @cindi 聚合中的 GROUP BY 子句不一定是多余的。 GROUP BY 可以包含根本不在选择列表中的列。如果我有一个包含 FirstName、LastName、State 的表,我可以进行以下查询:SELECT FirstName, COUNT(*) FROM MyTable GROUP BY FirstName, State【参考方案5】:

如果您担心列名,您可以随时给它们取别名:

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

虽然我真的不知道为什么要在这样一个简单的例子中这样做

【讨论】:

是否可以为多个列设置别名?例如,insert into T1 ALL_COLUMNS_ALIAS select (C1, C2, C3) as ALL_COLUMNS_ALIAS from T2?【参考方案6】:

引用如下:

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

【讨论】:

【参考方案7】:

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

xparams 为 ( 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,',') 组内 (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" 来自 t1c1, xparams order by t1c1.table_name ) 从 res1 中选择 *

【讨论】:

【参考方案8】:

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

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(以及任何其他具有隐式转换的松散类型语言)的经验法则是尽可能具体,如果您不希望在运行时出现静默错误,并且在有人添加新功能时不希望出现错误。

【讨论】:

以上是关于自动匹配 INSERT INTO ... SELECT ... FROM 中的列的主要内容,如果未能解决你的问题,请参考以下文章

Postgresql中无则插入的使用方法INSERT INTO WHERE NOT EXISTS

OracleMergeinto详细介绍

Merge into 详细介绍

Oracle基础之Merge into

Oracle 使用MERGE INTO 语句更新数据

Oracle 使用MERGE INTO 语句更新数据