关于sql:插入…值(SELECT … FROM …)

关于sql:插入…值(SELECT … FROM …)

Insert into … values ( SELECT … FROM … )

我试图使用另一个表的输入来创建一个表。尽管对于许多数据库引擎来说这是完全可行的,但我似乎总是很难记住当时的SQL引擎(mysql、oracle、sql server、informix和db2)的正确语法。

是否有一个来自SQL标准(例如,SQL-92)的银弹语法可以让我插入值而不必担心底层数据库?


尝试:

1
2
3
INSERT INTO table1 ( column1 )
SELECT  col1
FROM    table2

这是标准的ANSI SQL,应该在任何DBMS上工作。

它绝对适用于:

  • 甲骨文公司
  • MS SQL服务器
  • MySQL
  • Postgres公司
  • sqlite v3
  • Teradata公司
  • DB2
  • 赛贝斯
  • 垂直
  • HQLDB
  • H2
  • AWS红移
  • SAP HANA

@shadow_x99:应该可以,您也可以有多个列和其他数据:

1
2
3
4
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一起工作。


为了从另一个表中仅获取多值INSERT中的一个值,我在sqlite3中执行了以下操作:

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

我看到的这两个答案在Informix中都特别有效,基本上都是标准的SQL。也就是说,符号:

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

使用Informix和所有DBMS都很好。(大约5年前,MySQL并不总是支持这种类型的东西;现在它已经很好地支持这种标准的SQL语法,而且,在这个符号上,它可以正常工作。)列列表是可选的,但按顺序指示目标列,因此选择结果的第一列将进入第一列列出的列等。如果没有列列表,则选择结果的第一列将进入目标表的第一列。

不同系统之间的区别在于用于标识不同数据库中表的符号——标准中没有关于数据库间(更不用说数据库间)操作的内容。使用Informix,可以使用以下符号来标识表:

1
[dbase[@server]:][owner.]TABLE

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

1
2
3
4
5
6
TABLE
"owner".table
dbase:TABLE
dbase:owner.table
dbase@server:TABLE
dbase@server:owner.table

通常不需要引用所有者;但是,如果确实使用了引号,则需要正确拼写所有者名称-它会区分大小写。即:

1
2
3
someone.table
"someone".table
SOMEONE.table

所有这些都标识同一个表。对于Informix,模式ansi数据库有一个轻微的复杂性,其中所有者名称通常转换为大写(Informix是例外)。也就是说,在模式ansi数据库(不常用)中,您可以编写:

1
CREATE TABLE someone.table ( ... )

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

注意,MS SQL Server设法使用括在方括号中的[分隔标识符]。我觉得这很奇怪,而且肯定不是SQL标准的一部分。


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

1
2
3
4
INSERT INTO TABLE_NAME
SELECT COL1, COL2 ...
FROM TABLE_YOU_NEED_TO_TAKE_FROM
;

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


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

1
2
3
4
5
6
7
INSERT INTO TABLE1
(COLUMN1, COLUMN2, COLUMN3, COLUMN4)
VALUES (value1, value2,
(SELECT COLUMN_TABLE2
FROM TABLE2
WHERE COLUMN_TABLE2 LIKE"blabla"),
value4);


如果要为SELECT部分中的所有列提供值,则可以在不指定INSERT INTO部分中的列的情况下执行此操作。

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

1
2
3
INSERT INTO table1
SELECT  col1, col2
FROM    table2

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

1
2
3
INSERT INTO table1
SELECT  col1
FROM    table2

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


不使用INSERT查询的VALUES部分,只使用下面的SELECT查询。

1
2
INSERT INTO table1 ( column1 , 2, 3... )
SELECT col1, 2, 3... FROM table2


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

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


表列序列已知时的简单插入:

1
2
    INSERT INTO Table1
    VALUES(1,2,...)

简单插入说明列:

1
2
    INSERT INTO Table1(col2,col4)
    VALUES(1,2)

当表(表2)的选定列数等于插入表(表1)时进行大容量插入

1
2
3
    INSERT INTO Table1 {COLUMN SEQUENCE}
    SELECT * -- column sequence should be same.
       FROM #table2

大容量插入当您只想插入到表(表1)的所需列时:

1
2
3
    INSERT INTO Table1 (Column1,Column2 ....Desired COLUMN FROM Table1)  
    SELECT Column1,Column2..desired COLUMN FROM #table2
       FROM #table2


下面介绍如何从多个表中插入。这个特殊的例子是在多对多场景中有一个映射表:

1
2
3
INSERT INTO StudentCourseMap (StudentId, CourseId)
SELECT  Student.Id, Course.Id FROM Student, Course
WHERE Student.Name = 'Paddy Murphy' AND Course.Name = 'Basket weaving for beginners'

(我知道匹配学生的名字可能会返回一个以上的值,但你明白了。当ID是标识列且未知时,必须在ID之外的其他对象上进行匹配。)


下面是另一个使用多个表获取源的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
INSERT INTO cesc_pf_stmt_ext_wrk(
  PF_EMP_CODE    ,
  PF_DEPT_CODE   ,
  PF_SEC_CODE    ,
  PF_PROL_NO     ,
  PF_FM_SEQ      ,
  PF_SEQ_NO      ,
  PF_SEP_TAG     ,
  PF_SOURCE)
SELECT
  PFl_EMP_CODE    ,
  PFl_DEPT_CODE   ,
  PFl_SEC         ,
  PFl_PROL_NO     ,
  PF_FM_SEQ       ,
  PF_SEQ_NO       ,
  PFl_SEP_TAG     ,
  PF_SOURCE
 FROM cesc_pf_stmt_ext,
      cesc_pfl_emp_master
 WHERE pfl_sep_tag LIKE '0'
   AND pfl_emp_code=pf_emp_code(+);

COMMIT;

1
2
3
INSERT INTO yourtable
SELECT fielda, fieldb, fieldc
FROM donortable;

这适用于所有DBMS


如果要使用SELECT * INTO表插入所有列,可以尝试此操作。

1
2
3
SELECT  *
INTO    Table2
FROM    Table1;


这对我很有用:

1
INSERT INTO table1 SELECT * FROM table2

这句话和甲骨文的有点不同。


对于Microsoft SQL Server,我建议您学习解释msdn上提供的语法。使用谷歌,查找语法比以往任何时候都容易。

对于这种特殊情况,请尝试

Google: insert site:microsoft.com

第一个结果是http://msdn.microsoft.com/en-us/library/ms174335.aspx

如果您发现很难解释页面顶部给出的语法,请向下滚动到示例("使用select和execute选项插入其他表中的数据")。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[ WITH <common_table_expression> [ ,...n ] ]
INSERT
{
        [ TOP ( expression ) [ PERCENT ] ]
        [ INTO ]
        { <object> | rowset_function_limited
          [ WITH ( <Table_Hint_Limited> [ ...n ] ) ]
        }
    {
        [ ( column_list ) ]
        [ <OUTPUT Clause> ]
        { VALUES ( { DEFAULT | NULL | expression } [ ,...n ] ) [ ,...n     ]
        | derived_table       <<<<------- Look here ------------------------
        | execute_statement   <<<<------- Look here ------------------------
        | <dml_table_source>  <<<<------- Look here ------------------------
        | DEFAULT VALUES
        }
    }
}
[;]

这应该适用于任何其他可用的RDBMS。记住所有产品的语法是没有意义的。


我实际上更喜欢SQL Server 2008中的以下内容:

1
2
3
SELECT Table1.Column1, Table1.Column2, Table2.Column1, Table2.Column2, 'Some String' AS SomeString, 8 AS SomeInt
INTO Table3
FROM Table1 INNER JOIN Table2 ON Table1.Column1 = Table2.Column3

它消除了添加insert()集的步骤,只需选择表中的值。


只需使用括号将select子句插入insert。例如:

1
2
3
4
5
6
7
INSERT INTO Table1 (col1, col2, your_desired_value_from_select_clause, col3)
VALUES (
   'col1_value',
   'col2_value',
   (SELECT col_Table2 FROM Table2 WHERE IdTable2 = 'your_satisfied_value_for_col_Table2_selected'),
   'col3_value'
);

1
2
3
SELECT *
INTO tmp
FROM orders

看起来不错,但只有在tmp不存在(创建并填充)时才有效。(SQL服务器)

要插入现有的tmp表,请执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SET identity_insert tmp ON

INSERT tmp
([OrderID]
      ,[CustomerID]
      ,[EmployeeID]
      ,[OrderDate]
      ,[RequiredDate]
      ,[ShippedDate]
      ,[ShipVia]
      ,[Freight]
      ,[ShipName]
      ,[ShipAddress]
      ,[ShipCity]
      ,[ShipRegion]
      ,[ShipPostalCode]
      ,[ShipCountry] )
      SELECT * FROM orders

SET identity_insert tmp off


从任何其他表插入多个记录的最佳方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
INSERT  INTO dbo.Users
            ( UserID ,
              Full_Name ,
              Login_Name ,
              Password
            )
            SELECT  UserID ,
                    Full_Name ,
                    Login_Name ,
                    Password
            FROM    Users_Table
            (INNER JOIN / LEFT JOIN ...)
            (WHERE CONDITION...)
            (OTHER CLAUSE)


1
2
3
4
INSERT INTO FIRST_TABLE_NAME (COLUMN_NAME)
SELECT  COLUMN_NAME
FROM    ANOTHER_TABLE_NAME
WHERE CONDITION;


使用select子查询插入到的两种方法。

  • 使用select子查询返回一行结果。
  • 使用Select子查询返回多行结果。
  • 1。使用Select子查询返回一行结果的方法。

    1
    2
    INSERT INTO <table_name> (<field1>, <field2>, <field3>)
    VALUES ('DUMMY1', (SELECT <field> FROM <table_name> ),'DUMMY2');

    在这种情况下,它假定select子查询仅根据where条件或SQL聚合函数(如sum、max、avg等)返回一行结果,否则将引发错误。

    2。使用Select子查询返回多行结果的方法。

    1
    2
    INSERT INTO <table_name> (<field1>, <field2>, <field3>)
    SELECT 'DUMMY1', <field>, 'DUMMY2' FROM <table_name>;

    第二种方法适用于这两种情况。


    如果执行"插入值"路径以插入多行,请确保使用括号将值分隔到集合中,因此:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    INSERT INTO `receiving_table`
      (id,
      first_name,
      last_name)
    VALUES
      (1002,'Charles','Babbage'),
      (1003,'George', 'Boole'),
      (1001,'Donald','Chamberlin'),
      (1004,'Alan','Turing'),
      (1005,'My','Widenius');

    否则,mysql对象"列计数与第1行的值计数不匹配",当您最终确定如何处理它时,您将编写一篇普通的文章。


    推荐阅读