Использование оператора SELECT в команде INSERT

Использование оператора SELECT в команде INSERT

Оператор SELECT в команде INSERT позволяет взять данные из одной или нескольких таблиц и вставить их в другую таблицу. Если вы вставляете значения только для части столбцов, определить значения для других столбцов можно будет позднее с помощью оператора UPDATE.

Если вы вставляете строки из одной таблицы в другую, эти таблицы должны иметь совместимую структуру, т.е. соответствующие столбцы должны иметь одинаковый тип, или же система должна уметь автоматически выполнять нужное преобразование.

Если столбцы в обеих таблицах совместимы по типам и определены в одинаковом порядке в соответствующих операторах CREATE TABLE, перечислять их в команде INSERT необязательно.

Пример

Предположим, что в таблице sale_arhiiv содержатся строки с информацией о продажах в том же формате, что и в таблице tbl_sale.

Для добавления в таблицу sale_arhiiv строк из таблицы tbl_sale, содержащих данные о проджах за 2004 год в можно воспользоваться следующей командой:

SQL:

INSERT INTO sale_arhiiv
SELECT sale_id, client_id, prod_id, amount, saledate
FROM tbl_sale
WHERE YEAR(saledate)=2004

или

INSERT INTO sale_arhiiv
SELECT *
FROM tbl_sale
WHERE YEAR(saledate)=2004


Если столбцы в двух таблицах (таблица, в которую вы вставляете данные, и таблица, из которой вы берете данные) определены в разном порядке в соответствующих операторах CREATE TABLE, для установления соответствия между ними можно воспользоваться предложениями INSERT или SELECT.

Пример

Например, предположим, что в операторе CREATE TABLE для таблицы tbl_sale столбцы определены в следующем порядке — sale_id, client_id, prod_id, amount, saledate, a для таблицы sale_arviiv — sale_id, prod_id, client_id saledate и amount. Тогда установить соответствие между ними можно с помощью оператора INSERT. Для этого столбцы таблицы sale_arhiiv нужно перечислить в предложении INSERT:

SQL:
INSERT INTO sale_arhiiv (sale_id, client_id, prod_id, amount, saledate)
SELECT *
FROM tbl_sale
WHERE YEAR(saledate)=2004

 

Такой же результат можно получить, перечислив в нужном порядке столбцы таблицы tbl_sale в предложении SELECT:

SQL:
INSERT INTO sale_arhiiv
SELECT sale_id,prod_id, client_id, saledate amount
FROM tbl_sale

WHERE YEAR(saledate)=2004


Одним из преимуществ использования оператора SELECT в команде INSERT является возможность включения в него различных выражений (expression) — строк символов, математических формул и функций, позволяющих манипулировать вставляемыми данными.

Кроме того, с помощью оператора SELECT можно добавлять данные как во все сразу, так и в отдельные столбцы, по аналогии с предложением VALUE. Для этого нужно просто задать имена столбцов, в которые вы хотите добавить данные в предложении INSERT

Пример

Ниже приводится пример предложения SELECT, в котором над столбцом выполняются математические действия.

Предположим, что описываемая нами компания купила продукцию у другой фармацевттической компании. Причем, по счастливой случайности, для описания продукции эта компания использовала таблицу tbl_prod с той же структурой, что и таблица tbl_product. Однако при покупке стоимость продукции была увеличена на 10%. Кроме того, данные будут добавлены во все поля таблицы tbl_product, кроме поля tbl_group. Оператор, увеличивающий значения стоимости товаров вставляющий строки из таблицы tbl_prod в таблицу tbl_product, имеет следующий вид:

SQL:
INSERT INTO tbl_product(prod_id, pr_name,price)
SELECT prod_id, name, price * 1. 1 FROM tbl_prod


« Previous | Next »

SQL INSERT INTO SELECT, заявление

❮ Предыдущая Следующая Глава ❯


С помощью SQL можно скопировать информацию из одной таблицы в другую.

INSERT INTO SELECT, заявление копирует данные из одной таблицы и вставляет его в существующую таблицу.


Заявление SQL INSERT INTO SELECT,

INSERT INTO SELECT, оператор выбирает данные из одной таблицы и вставляет его в существующую таблицу. Любые существующие строки в целевой таблице не изменяются.

SQL INSERT INTO SELECT, Синтаксис

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

INSERT INTO table2
SELECT * FROM table1;

Или же мы можем скопировать только те столбцы, которые мы хотим в другую, существующую таблицу:

INSERT INTO table2
(column_name(s))
SELECT column_name(s)
FROM table1;


Демо-версия базы данных

В этом уроке мы будем использовать хорошо известную базу данных Борей.

Ниже приводится подборка из «Customers» таблицы:

Пользовательский ИД Имя Клиента Контактное лицо Адрес город Почтовый индекс Страна
1 Alfreds Futterkiste Maria Anders Obere Str. 57
Berlin
12209 Germany
2 Ana Trujillo Emparedados y helados Ana Trujillo Avda. de la Constitucion 2222 Mexico D.F. 05021 Mexico
3 Antonio Moreno Taqueria Antonio Moreno Mataderos 2312 Mexico D.F. 05023 Mexico

И выбор из «Suppliers» таблицы:

SupplierID Наименование поставщика Контактное лицо Адрес город Почтовый индекс Страна Телефон
1 Экзотические Liquid Шарлотта Купер 49 Гилберта St. Londona EC1 4SD Великобритания (171) 555-2222
2 Новый Орлеан Cajun наслаждений Shelley Берк PO Box 78934 Жители Нового Орлеана 70117 США (100) 555-4822
3 Homestead Бабушка Келли Regina Мерфи 707 Oxford Rd. Ann Arbor 48104 США (313) 555-5735


SQL INSERT INTO SELECT, Примеры

Копирование только несколько столбцов из «Suppliers» Into «Customers» :

пример

INSERT INTO Customers (CustomerName, Country)
SELECT SupplierName, Country FROM Suppliers;

Попробуй сам «

Копирование только немецких поставщиков в «Customers» :

пример

INSERT INTO Customers (CustomerName, Country)
SELECT SupplierName, Country FROM Suppliers
WHERE Country=’Germany’;

Попробуй сам «

❮ Предыдущая Следующая Глава ❯

sql — Вставить в .

.. значения ( SELECT … FROM … )

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

 INSERT INTO target_table[()] SELECT ... FROM ...;
 

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

Между системами может различаться нотация, используемая для идентификации таблиц в разных базах данных — стандарт ничего не говорит об операциях между базами данных (не говоря уже о межСУБД).

В Informix вы можете использовать следующую нотацию для идентификации таблицы:

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

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

 таблица
"владелец".таблица
база данных: таблица
база данных: владелец. таблица
dbase@сервер: таблица
dbase@сервер:владелец.таблица
 

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

 кто-то.таблица
"кто-то".таблица
SOMEONE.table
 

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

 СОЗДАТЬ ТАБЛИЦУ Someone.table ( ... )
 

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

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

sql — INSERT — SELECT * вместо одного столбца

Хорошо, во-первых, ваш синтаксис не будет работать, несмотря ни на что. Попробуйте

 INSERT INTO tableB (Field1, Field2, Field3, Field4, Field5, FieldX)
ВЫБЕРИТЕ Field4, Field3, Field2, Field1, Field5, 'HARDCODEVALUE' КАК FieldX
ИЗ таблицы А
 

Далее да, вы должны ВСЕГДА использовать все столбцы в том порядке, в котором вы хотите вставить их в таблицу как при выборе, так и при вставке. В противном случае это очень большой антипаттерн SQL, и это вызовет проблемы в будущем, особенно если столбцы меняются. Вы всегда хотите, чтобы правый столбец соответствовал правому столбцу. Это становится еще более проблематичным, если имена полей не всегда совпадают напрямую.

Если структура вашей таблицы меняется ежедневно, то у вас проблемы с дизайном, так как этого никогда не должно произойти.

Я мог бы предложить вам использовать таблицы информационной схемы для поиска столбцов на лету, но на самом деле, если таблица A добавляет столбец, как узнать, с каким столбцом его сопоставить в таблице B? Если столбец удален из таблицы B, как узнать, какой столбец удалить из таблицы A в SELECT? Позвольте мне проиллюстрировать проблему.

Предположим, у вас есть такая структура:

 ТАБЛИЦА
ID ПОЛЬЗОВАТЕЛЯ
ЛОГИН ПОЛЬЗОВАТЕЛЯ
ПОЛЬЗОВАТЕЛЬСКИЙ ПАРОЛЬ
ТАБЛИЦАB
ID ПОЛЬЗОВАТЕЛЯ
СИСТЕМНЫЙ ВХОД
СИСТЕМНЫЙ ПАРОЛЬ
ТИП ПОЛЬЗОВАТЕЛЯ
 

Затем, глядя на SELECT * вставить

 INSERT INTO tableB
ВЫБЕРИТЕ *, 'Пользователь' КАК ПОЛЬЗОВАТЕЛЬСКИЙ ТИП
ИЗ таблицы А
 

Эквивалент

 INSERT INTO tableB (USERID,SYSLOGIN,SYSPASSWORD,USERTYPE)
ВЫБЕРИТЕ ИДЕНТИФИКАТОР ПОЛЬЗОВАТЕЛЯ,ВХОД ПОЛЬЗОВАТЕЛЯ,ПАРОЛЬ ПОЛЬЗОВАТЕЛЯ, 'Пользователь' КАК ТИП ПОЛЬЗОВАТЕЛЯ
ИЗ таблицы А
 

На данный момент все в порядке. Но что происходит, когда структура изменяется?

Затем структура становится

 ТАБЛИЦА
ID ПОЛЬЗОВАТЕЛЯ
ЛОГИН ПОЛЬЗОВАТЕЛЯ
ПОЛЬЗОВАТЕЛЬСКИЙ ПАРОЛЬ
LASTLOGINDATE
ТАБЛИЦАB
ID ПОЛЬЗОВАТЕЛЯ
СИСТЕМНЫЙ ВХОД
СИСТЕМНЫЙ ПАРОЛЬ
ТИП ПОЛЬЗОВАТЕЛЯ
LASTLOGINDATE
 

Если вы используете select *

 INSERT INTO tableB
ВЫБИРАТЬ *
ИЗ таблицы А
 

эквивалентен

 INSERT INTO tableB (USERID,SYSLOGIN,SYSPASSWORD,USERTYPE, LASTLOGINDATE)
ВЫБЕРИТЕ USERID,USERLOGIN,USERPASSWORD, LASTLOGINDATE,'User' AS USERTYPE
ИЗ таблицы А
 

Как видите, используя SELECT *, вы в конечном итоге пытаетесь вставить LASTLOGINDATE в USERTYPE, а значение USERTYPE, которое вы ранее жестко запрограммировали, попадает в LASTLOGINDATE.