Вставить в... значения ( SELECT ... FROM ...)

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

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

28 ответов

Решение

Пытаться:

INSERT INTO table1 ( column1 )
SELECT  col1
FROM    table2  

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

Это определенно работает для:

  • оракул
  • MS SQL Server
  • MySQL
  • Postgres
  • SQLite v3
  • 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;

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

Чтобы получить только одно значение в множественном значении 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 перейдет в первый перечисленный столбец и т. д. В отсутствие списка столбцов первый столбец результата SELECT перейдет в первый столбец целевой таблицы.

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

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

То есть вы можете указать базу данных, опционально идентифицируя сервер, на котором размещена эта база данных, если он не находится на текущем сервере, за которым следует необязательный владелец, точка и, наконец, фактическое имя таблицы. Стандарт SQL использует термин схема для того, что 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 ( ... )

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

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

Два подхода для вставки с подзапросом select.

  1. Подзапрос SELECT возвращает результаты с одной строкой.
  2. Подзапрос SELECT возвращает результаты с несколькими строками.

1. Подход с подзапросом With SELECT, возвращающий результаты с одной строкой.

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

В этом случае предполагается, что подзапрос SELECT возвращает только одну строку результата на основе условия WHERE или агрегатных функций SQL, таких как SUM, MAX, AVG и т. Д. В противном случае будет выдана ошибка.

2. Подход с подзапросом With SELECT, возвращающим результаты с несколькими строками.

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

Второй подход будет работать в обоих случаях.

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

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

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

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

Большинство баз данных придерживаются основного синтаксиса,

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

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

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

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

INSERT INTO table1
SELECT  col1, col2
FROM    table2

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

INSERT INTO table1
SELECT  col1
FROM    table2

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

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

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

Это еще один пример использования значений с помощью 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

Массовая вставка, если вы хотите вставить только в нужный столбец таблицы (таблица1):

    Insert into Table1 (Column1,Column2 ....Desired Column from Table1)  
    Select Column1,Column2..desired column from #table2
       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;

Вы можете попробовать это, если вы хотите вставить все столбцы, используя 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 (), и вы просто выбираете, какие значения идут в таблице.

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

insert into table1 select * from table2

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

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

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

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

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

Google: вставить сайт: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.

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

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

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

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

Чтобы вставить в существующую таблицу 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 CUSTOMER_INFO
   (SELECT CUSTOMER_NAME,
           MOBILE_NO,
           ADDRESS
      FROM OWNER_INFO cm)

Где находятся таблицы:

            CUSTOMER_INFO               ||            OWNER_INFO
----------------------------------------||-------------------------------------
CUSTOMER_NAME | MOBILE_NO | ADDRESS     || CUSTOMER_NAME | MOBILE_NO | ADDRESS 
--------------|-----------|---------    || --------------|-----------|--------- 
      A       |     +1    |   DC        ||       B       |     +55   |   RR  

Результат:

            CUSTOMER_INFO               ||            OWNER_INFO
----------------------------------------||-------------------------------------
CUSTOMER_NAME | MOBILE_NO | ADDRESS     || CUSTOMER_NAME | MOBILE_NO | ADDRESS 
--------------|-----------|---------    || --------------|-----------|--------- 
      A       |     +1    |   DC        ||       B       |     +55   |   RR
      B       |     +55   |   RR        ||

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

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

Если вы сначала создаете таблицу, вы можете использовать ее так:

        select * INTO TableYedek From Table

Этот метод вставляет значения, но по-другому при создании новой таблицы копирования.

В informix это работает, как сказал Клод:

INSERT INTO table (column1, column2) 
VALUES (value1, value2);    

Postgres поддерживает следующее: создать таблицу company.monitor2 как select * from company.monitor;

      INSERT INTO Table_Name (COL1, COL2, COL3, ...)
VALUES (Value1, Value2, Value3, ...);

С именем схемы (как в PostgreSQL):

      INSERT INTO "Schema-name"."Table_Name" (COL1, COL2, COL3, ...)
VALUES (Value1, Value2, Value3, ...);
Другие вопросы по тегам