Урок доступен в видеоформате 

Добавление данных, оператор INSERT

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

Общая структура запроса с оператором INSERT

MySQL 8.4
INSERT INTO имя_таблицы [(поле_таблицы [, ...])]
{ VALUES (значение [, ...]) [, ...] | select_выражение };
  • [ ]необязательная часть
  • { a | b }один из вариантов
  • ...можно повторить
имя_таблицы
Таблица, в которую добавляются записи.
поле_таблицы

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

Необязательный
значение

Значение для столбца: число, строка, выражение или NULL. Значения идут в том же порядке, что и столбцы. Каждые скобки — одна строка, несколько строк перечисляются через запятую.

select_выражение

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

Подзапрос

Значения передают списком после VALUES или получают запросом SELECT.

Перечисление полей и соответствие значениям

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

MySQL 8.4
INSERT INTO имя_таблицы (поле_таблицы [, ...])
VALUES (значение [, ...]);
  • [ ]необязательная часть
  • ...можно повторить
имя_таблицы
Таблица, в которую добавляются записи.
поле_таблицы

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

значение

Значение для столбца, который стоит на той же позиции в списке полей.

Важные правила:

  • Порядок значений в VALUES должен строго соответствовать порядку полей в перечислении
  • Количество значений должно совпадать с количеством указанных полей
  • Если поле не указано в перечислении, оно получит значение по умолчанию (если оно задано) или NULL (если поле допускает NULL)

Например, если таблица Goods имеет поля good_id, good_name и type, то следующие запросы эквивалентны:

MySQL 8.4
-- Явное указание полей
INSERT INTO Goods (good_id, good_name, type)
VALUES (20, 'Table', 8);

-- Изменённый порядок полей - значения меняются соответственно
INSERT INTO Goods (good_name, type, good_id)
VALUES ('Table', 8, 20);

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

MySQL 8.4
INSERT INTO Goods
VALUES (20, 'Table', 8);

Различия между синтаксисами INSERT

Допустим, в справочник товаров Goods нужно добавить новую позицию — стол. Сделать это можно двумя способами.

Привычный способ — перечислить значения после VALUES:

MySQL 8.4
INSERT INTO Goods (good_id, good_name, type)
VALUES (20, 'Table', 8);

Но INSERT принимает не только готовый список. Вместо VALUES можно подставить запрос SELECT, и в таблицу попадёт всё, что он вернёт. Причём SELECT может обойтись без FROM. Если просто перечислить в нём значения, он вернёт их одной строкой:

MySQL 8.4
INSERT INTO Goods (good_id, good_name, type)
SELECT 20, 'Table', 8;

Результат у обоих запросов одинаковый — в Goods появился стол:

good_idgood_nametype
17
Ещё 17 строк
airsoft game session4
18netflix subscription4
20Table8

Когда какой способ использовать

Если значения известны заранее — например, их ввёл пользователь, — проще всего INSERT ... VALUES. Им же можно добавить сразу несколько строк, каждую в своих скобках:

MySQL 8.4
INSERT INTO Goods (good_id, good_name, type)
VALUES
    (20, 'Table', 8),
    (21, 'Chair', 8),
    (22, 'Lamp', 8);

А INSERT ... SELECT выручает, когда новые строки нужно собрать из того, что уже лежит в базе: скопировать записи — в ту же или в другую таблицу — или сохранить результат вычислений. Например, продублируем все продукты питания, а копиям дадим номера на 100 больше:

MySQL 8.4
INSERT INTO Goods (good_id, good_name, type)
SELECT good_id + 100, good_name, type
FROM Goods
WHERE type = 2;

Запустите запрос и посмотрите в конец таблицы: один запрос добавил сразу три строки — копии bread, milk и potato.

Первичный ключ при добавлении новой записи

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

Какой номер свободен? Первое, что приходит в голову, — взять наибольший и прибавить единицу:

MySQL 8.4
INSERT INTO Goods SELECT MAX(good_id) + 1, 'Table', 8 FROM Goods;

Способ работает, но ненадёжен. Если два таких запроса выполнятся одновременно, они могут получить один и тот же номер, и один из них завершится ошибкой. Кроме того, способ подходит только для числовых ключей и может выдать номер, который раньше принадлежал удалённой записи. Если на этот номер где-то ссылаются старые данные, они окажутся связаны с новой строкой 💥. Поэтому в реальных проектах номер выдаёт сама база данных.

Автоматическая генерация первичного ключа

Первичный ключ можно генерировать автоматически: для этого столбцу good_id задают атрибут AUTO_INCREMENT. Тогда при добавлении записи в good_id достаточно передать NULL или 0 — поле само получит следующее значение счётчика: на единицу больше самого большого из уже использованных.

MySQL 8.4
CREATE TABLE Goods (
	good_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
	good_name VARCHAR(255),
	type INT
);
MySQL 8.4
INSERT INTO Goods VALUES (NULL, 'Table', 8);

Уникальный идентификатор можно генерировать автоматически с помощью типов SMALLSERIAL, SERIAL и BIGSERIAL. Это не настоящие типы, а сокращённая запись: столбец с таким типом получается целочисленным и сам увеличивается при добавлении новой записи.

MySQL 8.4
CREATE TABLE Goods (
	good_id SERIAL PRIMARY KEY,
	good_name VARCHAR(255),
	type INT
);
MySQL 8.4
INSERT INTO Goods (good_name, type) VALUES ('Table', 8);

Проверьте себя

В таблице Goods уже есть товар с good_id = 3, а поле good_id — первичный ключ. Что произойдёт при выполнении запроса?

MySQL 8.4
INSERT INTO Goods (good_id, good_name, type)
VALUES (3, 'chair', 8);