Вставить в ... значения (выбрать ... из …)

Я пытаюсь INSERT INTO таблица, использующая вход из другой таблицы. Хотя это вполне возможно для многих ядер баз данных, мне всегда трудно вспомнить правильный синтаксис для SQL двигатель в день (в MySQL, Oracle, SQL Server, Informix и в DB2).

есть ли синтаксис silver-bullet, исходящий из стандарта SQL (например,SQL-92), что позволит мне вставить значения, не беспокоясь о базовой базе данных?

22 ответов


попробуй:

INSERT INTO table1 ( column1 )
SELECT  col1
FROM    table2  

Это стандартный ANSI SQL и должен работать на любой СУБД

Это, безусловно, работает:

  • Oracle
  • MS SQL Server
  • в MySQL
  • Postgres
  • SQLite в В3
  • Teradata
  • в DB2
  • Sybase
  • Vertica и
  • HSQLDB
  • H2
  • AWS RedShift
  • SAP HANA

@Shadow_x99: Это должно работать нормально, и вы также можете иметь несколько столбцов и другие данные:

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

Edit: я должен упомянуть, что я использовал этот синтаксис только с Access, SQL 2000/2005/Express, MySQL и PostgreSQL, поэтому они должны быть покрыты. Комментатор отметил, что он будет работать с sqlite3.


чтобы получить только одно значение в multi value 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))

оба ответа, которые я вижу, отлично работают в Informix, и в основном являются стандартными SQL. То есть обозначение:

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

отлично работает с Informix и, я бы ожидал, со всеми СУБД. (Когда-то 5 или более лет назад это то, что MySQL не всегда поддерживал; теперь он имеет приличную поддержку для такого стандартного синтаксиса SQL, и, AFAIK, он будет работать нормально на этой нотации.) Список столбцов является необязательным, но указывает целевые столбцы в последовательности, поэтому первый столбец результата SELECT перейдет в первый указанный столбец и т. д. При отсутствии списка столбцов первый столбец результата выбора переходит в первый столбец целевой таблицы.

что может отличаться между системами, так это нотация, используемая для идентификации таблиц в разных базах данных - стандарт ничего не говорит об операциях между базами данных (не говоря уже о МЕЖБДМ). С помощью Informix можно использовать следующие обозначения для идентификации таблица:

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

то есть вы можете указать базу данных, необязательно идентифицируя сервер, на котором размещена эта база данных, если она не находится на текущем сервере, а затем необязательный владелец, точка и, наконец, фактическое имя таблицы. Стандарт SQL использует схему терминов для того, что Informix называет владельцем. Таким образом, в Informix любая из следующих обозначений может идентифицировать таблицу:

table
"owner".table
dbase:table
dbase:owner.table
[email protected]:table
[email protected]:owner.table

владельцу вообще не нужно быть закавыченным; однако, если вы используете цитаты, то вы нужно правильно написать имя владельца-оно становится чувствительным к регистру. То есть:

someone.table
"someone".table
SOMEONE.table

все идентифицируют одну и ту же таблицу. С Informix есть небольшое осложнение с базами данных MODE ANSI, где имена владельцев обычно преобразуются в верхний регистр (informix является исключением). То есть в режиме базы данных ANSI (обычно не используется) Вы можете написать:

CREATE TABLE someone.table ( ... )

и имя владельца в системном каталоге будет "кто-то", а не "кто-то". Если вы заключаете имя владельца в двойных кавычках, он действует как идентификатор с разделителями. В стандартном SQL идентификаторы с разделителями могут использоваться во многих местах. С Informix их можно использовать только вокруг имен владельцев - в других контекстах Informix рассматривает как одинарные, так и двукратные строки как строки, а не разделяет одинарные строки как строки и двукратные строки как идентификаторы с разделителями. (Конечно, только для полноты, есть переменная среды, DELIMIDENT, которая может быть установлена на любое значение, но Y безопаснее всего-указать, что двойные кавычки всегда окружают разделенные идентификаторы, а одинарные кавычки всегда окружают строки.)

обратите внимание, что MS SQL Server удается использовать [идентификаторы с разделителями], заключенные в квадратные скобки. Это выглядит странно для меня и, конечно, не является частью стандарта SQL.


большинство баз данных следуют базовому синтаксису,

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

каждая база данных, которую я использовал, следует этому синтаксису, а именно:DB2, SQL Server, MY SQL, PostgresQL


чтобы добавить что-то в первый ответ, когда нам нужно всего несколько записей из другой таблицы (в этом примере только одна):

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

Это можно сделать без указания столбцов в INSERT INTO часть если вы вводите значения для всех столбцов в SELECT часть.

предположим, что table1 имеет два столбца. Этот запрос должен работать:

INSERT INTO table1
SELECT  col1, col2
FROM    table2

Это не сработает (значение для col2 не указан):

INSERT INTO table1
SELECT  col1
FROM    table2

я использую MS SQL Server. Я не знаю, как работают другие RDMS.


это еще один пример использования значений с select:

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

простая вставка, когда последовательность столбцов таблицы известна:

    Insert into Table1
    values(1,2,...)

простая вставка упоминая столбец:

    Insert into Table1(col2,col4)
    values(1,2)

массовая вставка, когда количество выбранных столбцов таблицы (#table2) равно таблице вставки(Table1)

    Insert into Table1 {Column sequence}
    Select * -- column sequence should be same.
       from #table2

массовая вставка, когда вы хотите вставить только в нужный столбец таблицы (table1):

    Insert into Table1 (Column1,Column2 ....Desired Column from Table1)  
    Select Column1,Column2..desired column from #table2
       from #table2

вместо VALUES часть INSERT запрос, просто использовать SELECT запрос, как показано ниже.

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

вот как вставить данные из нескольких таблиц. В этом конкретном примере у вас есть таблица сопоставления во многих сценариях:

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'

(Я понимаю, что соответствие имени студента может возвращать более одного значения, но вы понимаете идею. Соответствие чему-либо, кроме идентификатора, необходимо, когда идентификатор является столбцом идентификатора и неизвестен.)


вот еще один пример, где источник берется с использованием более чем одной таблицы:

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;

INSERT INTO yourtable
SELECT fielda, fieldb, fieldc
FROM donortable;

это работает на всех СУБД


это сработало для меня:

insert into table1 select * from table2

предложение немного отличается от Oracle.


для Microsoft SQL Server я рекомендую научиться интерпретировать синтаксис, предоставленный в MSDN. С Google это проще, чем когда-либо, искать синтаксис.

для этого конкретного случая попробуйте

Google: вставить site:microsoft.com

первый результат будет http://msdn.microsoft.com/en-us/library/ms174335.aspx

прокрутите вниз до примера ("используя параметры SELECT и EXECUTE для вставки данных из другие таблицы"), если вам трудно интерпретировать синтаксис, приведенный в верхней части страницы.

[ 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 
        }
    }
}
[;]

Это должно быть применимо для любых других РСУБД, доступных там. Нет смысла запоминать весь синтаксис для всех продуктов IMO.


вы можете попробовать это, если хотите вставить весь столбец с помощью SELECT * INTO таблица.

SELECT  *
INTO    Table2
FROM    Table1;

Я на самом деле предпочитаю следующее В SQL Server 2008:

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 *
into tmp
from orders

выглядит красиво, но работает только если tmp не существует (его создает и заполняет). (SQL sever)

для вставки в существующую таблицу tmp:

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

лучший способ вставить несколько записей из любых других таблиц.

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)

просто используйте скобки для выберите пункт в "вставить". Например, вот так:

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'
);

Если вы идете по маршруту вставки значений для вставки нескольких строк, обязательно разделите значения на наборы, используя круглые скобки, так:

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", и вы в конечном итоге пишете тривиальный пост, когда Вы наконец поймете, что с этим делать.


INSERT INTO FIRST_TABLE_NAME (COLUMN_NAME)
SELECT  COLUMN_NAME
FROM    ANOTHER_TABLE_NAME 
WHERE CONDITION;