Вставить в… значения (ВЫБРАТЬ… ОТ…)

1427

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

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

Клод Хоул
источник
1
этот пример работает: вставьте в tag_zone select @ tag, zoneid, GETDATE (), @ positiong.STIntersects (многоугольник) из зоны
Uğur Gümüşhan

Ответы:

1612

Пытаться:

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
Клод Хоул
источник
948

Ответ Клода Хоула : должен работать нормально, вы также можете иметь несколько столбцов и другие данные:

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.

Трэвис
источник
1
что если условие where было изменено на table2.country и возвращает число строк больше единицы? У меня похожая проблема здесь: stackoverflow.com/questions/36030370/…
Виджайрана
1
Не должно быть проблем со вставкой более чем одной строки.
rinukkusu
Нужно ли вставлять во все столбцы таблицы
maheshmnj
1
@maheshmnj нет, только столбцы, для которых установлено значение NOT NULL, и значения по умолчанию включать не нужно, для всех остальных столбцов будут установлены значения по умолчанию или NULL
travis
спасибо за информацию
maheshmnj
148

Чтобы получить только одно значение в множественном значении 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))
kylie.a
источник
4
Просто для пояснения: это неверно для SQLite3. Согласно документации , исходные данные для INSERTявляется либо VALUES или SELECTзаявление, но не оба.
2
Это правда, документация не перечисляет это, но это работает. Несмотря на это, я думаю, что использование оператора выбора вместо значений делает его более читабельным.
Банджокат
1
Он работает для указания значения внутри строки, но в более общем случае требуется получить много строк.
Лучостейн
Если val_1 не изменяется между строками, то следующий синтаксис может работать в SQLite3? выберите 'foo', some_column from some_table - работает в SQLServer 2014
Chris B
Документация делает список этот (теперь?): Этот синтаксис INSERT INTO ... VALUES ([expr], [expr], ...)и один из путей в [expr]является {{NOT} EXISTS} ([select-stmt])- к сведению , что paranthesis вокруг оператора выбора необходима ( {}то есть по желанию)
zapl
64

Оба ответа, которые я вижу, отлично работают в 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.

Джонатан Леффлер
источник
40

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

INSERT INTO TABLE1
(COLUMN1, COLUMN2, COLUMN3, COLUMN4) 
VALUES (value1, value2, 
(SELECT COLUMN_TABLE2 
FROM TABLE2
WHERE COLUMN_TABLE2 like "blabla"),
value4);
Weslor
источник
4
Этот подход применяется только к такому подзапросу, что выбран только один столбец. В случае подзапроса с несколькими столбцами возникнет ошибка «подзапрос должен возвращать только один столбец». Примите ответ @ travis тогда.
Snowfox
34

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

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

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

Santhosh
источник
34

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

INSERT INTO table1 ( column1 , 2, 3... )
SELECT col1, 2, 3... FROM table2
логан
источник
32

Два подхода для вставки в с помощью подзапроса 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>;

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

Мохаммед Сейфер
источник
29

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

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

INSERT INTO table1
SELECT  col1, col2
FROM    table2

Это НЕ БУДЕТ работать (значение для col2не указано):

INSERT INTO table1
SELECT  col1
FROM    table2

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

northben
источник
24

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

INSERT INTO table1(desc, id, email) 
SELECT "Hello World", 3, email FROM table2 WHERE ...
Сарвар Нишонбоев
источник
Старый ответ и до сих пор полезен. Довольно простой и очевидный, но точно соответствует моим потребностям. Спасибо!
Себастьян Качмарек
21

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

    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
RameezAli
источник
17

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

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;
SWATI BISWAS
источник
17

Просто используйте скобки для предложения 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'
);
Dasikely
источник
Спасибо @Das Это работает для меня ....
Радж Г
16

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

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 является столбцом Identity и неизвестен.)

Кьяран Бруен
источник
14
INSERT INTO yourtable
SELECT fielda, fieldb, fieldc
FROM donortable;

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

Matt
источник
14

Вы можете попробовать это, если хотите вставить все столбцы, используя SELECT * INTOтаблицу.

SELECT  *
INTO    Table2
FROM    Table1;
Теория Бхараты
источник
13

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

Grungondola
источник
13

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

insert into table1 select * from table2

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

elijah7
источник
12

Для 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.

Файз
источник
Я совершенно не согласен, я годами смотрю на эти синтаксические утверждения и до сих пор не могу их понять. Примеры гораздо полезнее
reggaeguitar
Это не ответ, он говорит «прочитай документы», вот и все
регги-гитара
12
INSERT INTO FIRST_TABLE_NAME (COLUMN_NAME)
SELECT  COLUMN_NAME
FROM    ANOTHER_TABLE_NAME 
WHERE CONDITION;
Gaurav
источник
@ggorlen Это выглядит довольно само собой разумеющимся
регги-гитара
Он был помечен в очереди на просмотр как ответ только для кода. Однако я могу понять вашу точку зрения - теперь в контексте большинства ответов на этой странице особо нечего сказать, поскольку я вижу это в естественной среде.
Ггорлен
9
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
Павел
источник
9

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

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)
Маниш Вадхер
источник
2

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

Себастьян
источник
6
Вопрос «вставить в таблицу, используя данные из другой таблицы ». Как ваш ответ отвечает на этот вопрос?
Качественный катализатор
3
Эх, не будь слишком строг с ним. Он ответил на мой вопрос, когда я гуглил вокруг. @QualityCatalyst
пояс Кэмерона
1

Если вы хотите вставить некоторые данные в таблицу без записи имени столбца.

INSERT INTO CUSTOMER_INFO
   (SELECT CUSTOMER_NAME,
           MOBILE_NO,
           ADDRESS
      FROM OWNER_INFO cm
     WHERE ID>100)

Где таблицы:

            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        ||
SMFazle Rabbi
источник
0

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

INSERT INTO table (column1, column2) 
VALUES (value1, value2);    
Мирослав Савель
источник
0

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

Казаков Всеволод
источник