Оператор INSERT
Как уже говорилось ранее, INSERT
предназначен для вставки данных в таблицу. Существует несколько вариантов его использования.
Вставка с указанием колонок
В таком варианте после указания таблицы в скобках перечисляются колонки, в которые будут записываться указываемые данные.
insert into employees(id, name, age)
values(1, 'John', 35)
insert into employees(id, name, age)
values(1, 'John', 35)
Данный способ является предпочтительным, т.к. он более информативен - сразу видно, что за данные вставляются в таблицу.
Также, при использовании такого способа, можно изменять порядок перечисления данных для строки:
insert into employees(age, name, id)
values(30, 'Dave', 2)
insert into employees(age, name, id)
values(30, 'Dave', 2)
Вставка без указания колонок
При таком варианте список столбцов таблицы не перечисляется, а сразу указываются значения, которые вставляются в таблицу:
insert into employees
values(1, 'John', 35)
insert into employees
values(1, 'John', 35)
Такой способ подразумевает, что мы будем перечислять значения для всех колонок в таблице, причем в том порядке, в котором они следуют в таблице.
Такой способ лучше не использовать, т.к. он:
- Неинформативен. Невозможно сказать, что значит 1, а что 35 без просмотра структуры таблицы
- Нестабилен к изменениям. Добавление/удаление колонки из таблицы потребует добавления/удаления значения из запроса.
Разберем последний минус данного подхода. Предположим, что в таблице employees
колонка age
необязательна, т.е. может содержать NULL
.
В случае, когда мы указываем колонки, мы можем сделать так:
insert into employees(id, name)
values(1, 'John')
insert into employees(id, name)
values(1, 'John')
Если использовать вариант без указания колонок, то мы будем вынуждены прописывать значения для всех колонок:
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
:
-- выдаст ошибку 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
в качестве значений для вставки.
В общем виде подобный запрос выглядит так:
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 лет. Из этой таблицы потом экспортируют данные в отчет для руководства.
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
нет сотрудников с отрицательным возрастом):
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
. Тогда запрос вставки данных мог выглядеть следующим образом:
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