题 插入...值(SELECT ... FROM ...)


我在尝试着 INSERT INTO 使用另一个表的输入的表。虽然这对于许多数据库引擎来说完全可行,但我似乎总是很难记住正确的语法 SQL 当天的引擎(MySQL的神谕SQL ServerInformix的,和 DB2)。

是否有来自SQL标准的银弹语法(例如, SQL-92)这将允许我插入值而不用担心底层数据库?


1099
2017-08-25 12:45


起源


这个例子有效:插入tag_zone select @ tag,zoneid,GETDATE(),@ positiong.STIntersects(polygon)来自zone - Uğur Gümüşhan


答案:


尝试:

INSERT INTO table1 ( column1 )
SELECT  col1
FROM    table2  

这是标准ANSI SQL,应该适用于任何DBMS

它肯定适用于:

  • 神谕
  • MS SQL Server
  • MySQL的
  • Postgres的
  • SQLite v3
  • Teradata数据
  • DB2
  • SYBASE
  • Vertica的
  • HSQLDB
  • H2
  • AWS RedShift
  • SAP HANA

1279
2017-08-25 12:47





@Shadow_x99:这应该工作正常,你也可以有多列和其他数据:

INSERT INTO table1 ( column1, column2, someInt, someVarChar )
SELECT  table2.column1, table2.column2, 8, 'some string etc.'
FROM    table2
WHERE   table2.ID = 7;

编辑:我应该提一下,我只使用Access,SQL 2000/2005 / Express,MySQL和PostgreSQL这种语法,所以应该涵盖这些。一位评论者指出它可以与SQLite3一起使用。


776
2017-08-25 14:11



如果,where条件更改为table2.country并返回大于1的行数?我在这里遇到类似的问题: stackoverflow.com/questions/36030370/... - vijayrana
插入多行时应该没有问题。 - rinukkusu


仅获取多值中的一个值 INSERT 从另一个表我在SQLite3中做了以下:

INSERT INTO column_1 ( val_1, val_from_other_table ) 
VALUES('val_1', (SELECT  val_2 FROM table_2 WHERE val_2 = something))

76
2018-01-10 23:46



只是为了澄清:这对SQLite3来说是不正确的。按照 文件,源的数据 INSERT 是 或  VALUES 或者a SELECT 声明,而不是两者。 - ZaLiTHkA
确实,文档没有列出它,但确实有效。无论如何,我认为使用select语句而不是值确实使它更具可读性。 - Banjocat
它适用于指定行内的值,但更一般的情况需要获取大量行。 - Luchostein
如果val_1不跨行更改,那么以下语法可能在SQLite3中有效吗?选择'foo',some_table中的some_column - 适用于SQLServer 2014 - Chris B
文档列出了这个(现在?):这个语法是 INSERT INTO ... VALUES ([expr], [expr], ...) 和其中一条路径 [expr] 是 {{NOT} EXISTS} ([select-stmt])  - 请注意,select语句周围的paranthesis是必需的({} 含义可选) - zapl


我看到的两个答案都在Informix中运行得很好,基本上都是标准的SQL。也就是说,符号:

INSERT INTO target_table[(<column-list>)] SELECT ... FROM ...;

适用于Informix,我希望,所有的DBMS。 (5年或更久以前,这是MySQL并不总是支持的东西;它现在对这种标准的SQL语法有很好的支持,而AFAIK,它在这种表示法上可以正常工作。)列列表是可选的但是按顺序指示目标列,因此SELECT结果的第一列将进入第一个列出的列,等等。如果没有列列表,SELECT结果的第一列将进入目标表的第一列。

系统之间可能存在的不同之处是用于识别不同数据库中的表的符号 - 该标准对数据库间(更不用说DBMS间)操作没什么好说的。使用Informix,您可以使用以下表示法来标识表:

[dbase[@server]:][owner.]table

也就是说,您可以指定一个数据库,可选择标识托管该数据库的服务器(如果它不在当前服务器中),后跟可选的所有者,点,最后是实际的表名。 SQL标准使用术语schema来表示Informix调用所有者的内容。因此,在Informix中,以下任何符号都可以标识表:

table
"owner".table
dbase:table
dbase:owner.table
dbase@server:table
dbase@server:owner.table

一般所有者不需要引用;但是,如果您使用引号,则需要正确拼写所有者名称 - 它会区分大小写。那是:

someone.table
"someone".table
SOMEONE.table

所有人都识别同一张桌子。使用Informix,MODE ANSI数据库有一个轻微的复杂性,其中所有者名称通常转换为大写(informix是例外)。也就是说,在MODE ANSI数据库(不常用)中,您可以编写:

CREATE TABLE someone.table ( ... )

并且系统目录中的所有者名称将是“SOMEONE”,而不是“某人”。如果将所有者名称括在双引号中,则它就像一个分隔标识符。使用标准SQL,可以在许多地方使用分隔标识符。使用Informix,您只能在所有者名称周围使用它们 - 在其他上下文中,Informix将单引号和双引号字符串视为字符串,而不是将单引号字符串分隔为字符串,将双引号字符串分隔为分隔标识符。 (当然,只是为了完整性,有一个环境变量,DELIMIDENT,可以设置 - 任何值,但Y是最安全的 - 表示双引号始终围绕分隔标识符,单引号始终包围字符串。)

请注意,MS SQL Server设法使用括在方括号中的[分隔标识符]。它看起来很怪异,当然不是SQL标准的一部分。


52
2017-09-28 03:18





大多数数据库遵循基本语法,

INSERT INTO TABLE_NAME
SELECT COL1, COL2 ...
FROM TABLE_YOU_NEED_TO_TAKE_FROM
;

我使用的每个数据库都遵循这种语法,即 DB2SQL ServerMY SQLPostgresQL


26
2018-04-01 10:09





要在第一个答案中添加内容,当我们只需要来自另一个表的少量记录时(在此示例中只有一个):

INSERT INTO TABLE1
(COLUMN1, COLUMN2, COLUMN3, COLUMN4) 
VALUES (value1, value2, 
(SELECT COLUMN_TABLE2 
FROM TABLE2
WHERE COLUMN_TABLE2 like "blabla"),
value4);

26
2018-04-09 17:15



此方法仅适用于仅选择一列的此子查询。在多列子查询的情况下,将引发错误“子查询必须仅返回一列”。然后采用@travis的答案。 - snowfox


这可以在不指定列中的列的情况下完成 INSERT INTO 部分,如果您提供的所有列的值 SELECT 部分。

假设table1有两列。此查询应该有效:

INSERT INTO table1
SELECT  col1, col2
FROM    table2

这不起作用(价值为 col2 未指定):

INSERT INTO table1
SELECT  col1
FROM    table2

我正在使用MS SQL Server。我不知道其他RDMS是如何工作的。


22
2017-10-16 14:19





这是使用select和值的另一个示例:

INSERT INTO table1(desc, id, email) 
SELECT "Hello World", 3, email FROM table2 WHERE ...

16
2018-03-20 09:12



老答案仍然有用。非常简单明了但完全涵盖了我的需求。谢谢! - Sebastian Kaczmarek