Вставить в … значения (ВЫБРАТЬ… ИЗ…)
-
09-06-2019 - |
Вопрос
я пытаюсь INSERT INTO
таблицу, используя входные данные из другой таблицы.Хотя это вполне осуществимо для многих механизмов баз данных, мне всегда трудно запомнить правильный синтаксис для SQL
двигатель дня(MySQL, Оракул, SQL-сервер, Информикс, и DB2).
Существует ли в стандарте SQL «серебряная пуля» синтаксиса (например, SQL-92), что позволило бы мне вставлять значения, не беспокоясь о базовой базе данных?
Решение
Пытаться:
INSERT INTO table1 ( column1 )
SELECT col1
FROM table2
Это стандартный ANSI SQL, который должен работать в любой СУБД.
Это определенно работает для:
- Оракул
- MS SQL-сервер
- MySQL
- Постгрес
- SQLite v3
- Терадата
- DB2
- Сибаза
- Вертика
- HSQLDB
- Н2
- AWS RedShift
- SAP Хана
Другие советы
@Тень_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 и, как я ожидал, со всеми СУБД.(Давным-давно, пять или более лет назад 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.
Большинство баз данных следуют базовому синтаксису:
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.
Вместо VALUES
часть INSERT
запрос, просто используйте SELECT
запрос, как показано ниже.
INSERT INTO table1 ( column1 , 2, 3... )
SELECT col1, 2, 3... FROM table2
Это еще один пример использования значений с помощью 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 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 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 yourtable
SELECT fielda, fieldb, fieldc
FROM donortable;
Это работает на всех СУБД
Вы можете попробовать это, если хотите вставить весь столбец, используя SELECT * INTO
стол.
SELECT *
INTO Table2
FROM Table1;
Это сработало для меня:
insert into table1 select * from table2
Предложение немного отличается от предложения Oracle.
Для Microsoft SQL Server я рекомендую научиться интерпретировать СИНТАКСИС, представленный в 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 нет смысла запоминать весь синтаксис для всех продуктов.
На самом деле я предпочитаю в 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.Например вот так:
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 *
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 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 FIRST_TABLE_NAME (COLUMN_NAME)
SELECT COLUMN_NAME
FROM ANOTHER_TABLE_NAME
WHERE CONDITION;
Два подхода для вставки с подзапросом выбора.
- С подзапросом SELECT, возвращающим результаты с Один ряд.
- С подзапросом SELECT, возвращающим результаты с Несколько строк.
1.Подход к подзапросу SELECT, возвращающему результаты с один ряд.
INSERT INTO <table_name> (<field1>, <field2>, <field3>)
VALUES ('DUMMY1', (SELECT <field> FROM <table_name> ),'DUMMY2');
В этом случае предполагается, что подзапрос SELECT возвращает только одну строку результата на основе условия WHERE или агрегатных функций SQL, таких как SUM, MAX, AVG и т. д.В противном случае выдаст ошибку
2.Подход к подзапросу SELECT, возвращающему результаты с несколько строк.
INSERT INTO <table_name> (<field1>, <field2>, <field3>)
SELECT 'DUMMY1', <field>, 'DUMMY2' FROM <table_name>;
Второй подход подойдет для обоих случаев.
Если вы используете маршрут 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», и вы в конечном итоге напишете тривиальное сообщение, когда наконец поймете, что с этим делать.