Добавление данных, оператор INSERT
До сих пор мы только читали данные. Но данные в таблицах не стоят на месте: появляются новые товары, клиенты, заказы, и для каждого в таблицу нужно добавить строку. Для этого есть оператор INSERT.
Общая структура запроса с оператором INSERT
INSERT INTO имя_таблицы [(поле_таблицы [, ...])]
{ VALUES (значение [, ...]) [, ...] | select_выражение };- [ ]необязательная часть
- { a | b }один из вариантов
- ...можно повторить
- имя_таблицы
- Таблица, в которую добавляются записи.
- поле_таблицы
Столбцы, которые получат значения. Без списка значения передаются для всех столбцов таблицы.
Необязательный- значение
Значение для столбца: число, строка, выражение или NULL. Значения идут в том же порядке, что и столбцы. Каждые скобки — одна строка, несколько строк перечисляются через запятую.
- select_выражение
Запрос SELECT, строки результата которого добавляются в таблицу. Он должен возвращать столько же столбцов, сколько их перечислено.
Подзапрос
Значения передают списком после VALUES или получают запросом SELECT.
Перечисление полей и соответствие значениям
Можно явно указать, в какие поля таблицы попадут данные. Для этого имена полей перечисляют в круглых скобках после названия таблицы:
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.4INSERT INTO Goods VALUES (20, 'Table', 8);
Различия между синтаксисами INSERT
Допустим, в справочник товаров Goods нужно добавить новую позицию — стол. Сделать это можно двумя способами.
Привычный способ — перечислить значения после VALUES:
MySQL 8.4INSERT INTO Goods (good_id, good_name, type) VALUES (20, 'Table', 8);
Но INSERT принимает не только готовый список. Вместо VALUES можно подставить запрос SELECT, и в таблицу попадёт всё, что он вернёт. Причём SELECT может обойтись без FROM. Если просто перечислить в нём значения, он вернёт их одной строкой:
MySQL 8.4INSERT INTO Goods (good_id, good_name, type) SELECT 20, 'Table', 8;
Результат у обоих запросов одинаковый — в Goods появился стол:
| good_id | good_name | type |
|---|---|---|
| 17 Ещё 17 строк | airsoft game session | 4 |
| 18 | netflix subscription | 4 |
| 20 | Table | 8 |
Когда какой способ использовать
Если значения известны заранее — например, их ввёл пользователь, — проще всего INSERT ... VALUES. Им же можно добавить сразу несколько строк, каждую в своих скобках:
MySQL 8.4INSERT INTO Goods (good_id, good_name, type) VALUES (20, 'Table', 8), (21, 'Chair', 8), (22, 'Lamp', 8);
А INSERT ... SELECT выручает, когда новые строки нужно собрать из того, что уже лежит в базе: скопировать записи — в ту же или в другую таблицу — или сохранить результат вычислений. Например, продублируем все продукты питания, а копиям дадим номера на 100 больше:
MySQL 8.4INSERT INTO Goods (good_id, good_name, type) SELECT good_id + 100, good_name, type FROM Goods WHERE type = 2;
Запустите запрос и посмотрите в конец таблицы: один запрос добавил сразу три строки — копии bread, milk и potato.
Первичный ключ при добавлении новой записи
Значение первичного ключа в таблице не может повторяться: попытка вставить существующее закончится ошибкой.
Какой номер свободен? Первое, что приходит в голову, — взять наибольший и прибавить единицу:
MySQL 8.4INSERT INTO Goods SELECT MAX(good_id) + 1, 'Table', 8 FROM Goods;
Способ работает, но ненадёжен. Если два таких запроса выполнятся одновременно, они могут получить один и тот же номер, и один из них завершится ошибкой. Кроме того, способ подходит только для числовых ключей и может выдать номер, который раньше принадлежал удалённой записи. Если на этот номер где-то ссылаются старые данные, они окажутся связаны с новой строкой 💥. Поэтому в реальных проектах номер выдаёт сама база данных.
Автоматическая генерация первичного ключа
Первичный ключ можно генерировать автоматически: для этого столбцу good_id задают атрибут AUTO_INCREMENT. Тогда при добавлении записи в good_id достаточно передать NULL или 0 — поле само получит следующее значение счётчика: на единицу больше самого большого из уже использованных.
MySQL 8.4CREATE TABLE Goods ( good_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, good_name VARCHAR(255), type INT );
MySQL 8.4INSERT INTO Goods VALUES (NULL, 'Table', 8);
Уникальный идентификатор можно генерировать автоматически с помощью типов SMALLSERIAL, SERIAL и BIGSERIAL. Это не настоящие типы, а сокращённая запись: столбец с таким типом получается целочисленным и сам увеличивается при добавлении новой записи.
MySQL 8.4CREATE TABLE Goods ( good_id SERIAL PRIMARY KEY, good_name VARCHAR(255), type INT );
MySQL 8.4INSERT INTO Goods (good_name, type) VALUES ('Table', 8);
Проверьте себя
В таблице Goods уже есть товар с good_id = 3, а поле good_id — первичный ключ. Что произойдёт при выполнении запроса?
MySQL 8.4INSERT INTO Goods (good_id, good_name, type) VALUES (3, 'chair', 8);