Skip to content

Оператор INSERT

Как уже говорилось ранее, INSERT предназначен для вставки данных в таблицу. Существует несколько вариантов его использования.

Вставка с указанием колонок

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

sql
insert into employees(id, name, age)
values(1, 'John', 35)
insert into employees(id, name, age)
values(1, 'John', 35)

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

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

sql
insert into employees(age, name, id)
values(30, 'Dave', 2)
insert into employees(age, name, id)
values(30, 'Dave', 2)

Вставка без указания колонок

При таком варианте список столбцов таблицы не перечисляется, а сразу указываются значения, которые вставляются в таблицу:

sql
insert into employees
values(1, 'John', 35)
insert into employees
values(1, 'John', 35)

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

Такой способ лучше не использовать, т.к. он:

  • Неинформативен. Невозможно сказать, что значит 1, а что 35 без просмотра структуры таблицы
  • Нестабилен к изменениям. Добавление/удаление колонки из таблицы потребует добавления/удаления значения из запроса.

Разберем последний минус данного подхода. Предположим, что в таблице employees колонка age необязательна, т.е. может содержать NULL.

В случае, когда мы указываем колонки, мы можем сделать так:

sql
insert into employees(id, name)
values(1, 'John')
insert into employees(id, name)
values(1, 'John')

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

sql
insert into employees(id, name, age)
values(1, 'John', null)
insert into employees(id, name, age)
values(1, 'John', null)

Попытка указать всего 2 значения при вставке приведет к ошибке ORA-00947: not enough values:

sql
-- выдаст ошибку ORA-00947: not enough values
insert into employees
values(1, 'John')
-- выдаст ошибку ORA-00947: not enough values
insert into employees
values(1, 'John')

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

INSERT INTO ... SELECT

Данный способ очень мощная и гибкая возможность. Она позволяет использовать значения, возвращаемые оператором select в качестве значений для вставки.

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

sql
insert into table_1(column_1, column_2, column_3...)
select col_1,
       col_2,
       col_3,
       ....
from table_2
insert into table_1(column_1, column_2, column_3...)
select col_1,
       col_2,
       col_3,
       ....
from table_2

Более конкретный пример может выглядеть так: предположим, что нас попросили записать в таблицу emp_report список сотрудников, которые старше 40 лет. Из этой таблицы потом экспортируют данные в отчет для руководства.

sql
insert into emp_report(emp_id, name)
select emp.id,
       emp.name
from employees emp
where emp.age > 40
insert into emp_report(emp_id, name)
select emp.id,
       emp.name
from employees emp
where emp.age > 40

В случае, если запрос select не вернул никаких данных, то в таблицу также не будет вставлено ни одной строки.

В следующем примере данные не будут добавлены в таблицу(предполагается, что в таблице employees нет сотрудников с отрицательным возрастом):

sql
insert into emp_report(emp_id, name)
select emp.id,
       emp.name
from employees emp
where emp.age < 0
insert into emp_report(emp_id, name)
select emp.id,
       emp.name
from employees emp
where emp.age < 0

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

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

sql
insert into emp_report(emp_id, name, childs_count)
select emp.id,
       emp.name,
       count(chlds.id) childs_count
from employees emp
join emp_childs chlds on chlds.emp_id = emp.id
where emp.age > 40
group by emp.id, emp.name
insert into emp_report(emp_id, name, childs_count)
select emp.id,
       emp.name,
       count(chlds.id) childs_count
from employees emp
join emp_childs chlds on chlds.emp_id = emp.id
where emp.age > 40
group by emp.id, emp.name