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

Для добавления новых записей в таблицу предназначен оператор INSERT. Рассмотрим его общую структуру.

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

MySQL 8.1
INSERT INTO имя_таблицы [(поле_таблицы, ...)]
VALUES (значение_поля_таблицы, ...)
| SELECT поле_таблицы, ... FROM имя_таблицы ...

Значения можно вставлять перечислением с помощью слова VALUES, перечислив их в круглых скобках через запятую или c помощью оператора SELECT.

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

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

MySQL 8.1
INSERT INTO имя_таблицы (поле1, поле2, поле3)
VALUES (значение1, значение2, значение3);

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

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

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

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

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

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

MySQL 8.1
INSERT INTO Goods
VALUES (20, 'Table', 2);

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

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

Оператор INSERT поддерживает два основных синтаксиса для указания данных:

INSERT INTO ... VALUES

Используется для вставки заранее известных значений. Может вставлять одну или несколько строк за раз:

MySQL 8.1
-- Одна строка
INSERT INTO Goods (good_id, good_name, type)
VALUES (20, 'Table', 2);

-- Несколько строк
INSERT INTO Goods (good_id, good_name, type)
VALUES
    (20, 'Table', 2),
    (21, 'Chair', 2),
    (22, 'Lamp', 8);

Когда использовать: для вставки конкретных, статических данных, которые известны заранее.

INSERT INTO ... SELECT

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

MySQL 8.1
INSERT INTO Goods (good_id, good_name, type)
SELECT 20, 'Table', 2;

-- Или копирование из другой таблицы
INSERT INTO Goods (good_id, good_name, type)
SELECT good_id + 100, good_name, type
FROM Goods
WHERE type = 2;

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

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

  • Используя синтаксис INSERT INTO ... SELECT

    MySQL 8.1
    INSERT INTO Goods (good_id, good_name, type)
    SELECT 20, 'Table', 2;
    
  • Используя синтаксис INSERT INTO ... VALUES (...)

    MySQL 8.1
    INSERT INTO Goods (good_id, good_name, type)
    VALUES (20, 'Table', 2);
    

Каждый из этих запросов даст одинаковый результат:

good_idgood_nametype
1apartment fee1
2phone fee1
3bread2
4milk2
5red caviar3
6cinema4
7black caviar3
8cough tablets5
9potato2
10pineapples3
11television8
12vacuum cleaner8
13jacket7
14fur coat7
15music school fee6
16english school fee6
20Table2

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

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

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

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

Здесь мы используем функцию MAX для получения максимального значения первичного ключа. Однако, это не самый надёжный и универсальный способ вычисления значения первичного ключа, потому что он лучше всего работает только с числовым типом данных, для всех остальных реализация будет нетривиальной. А ещё таким способом можно получить значение, которое уже ранее существовало в таблице, но было удалено. Это может привести к неконсистентности данных в системе 💥, поэтому в реальных проектах рекомендуется использовать альтернативный метод.

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

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

MySQL 8.1
CREATE TABLE Goods (
	good_id INT NOT NULL AUTO_INCREMENT,
	good_name VARCHAR(255),
	type INT
);
MySQL 8.1
INSERT INTO Goods VALUES (NULL, 'Table', 2);

В PostgreSQL есть механизм для автоматической генерации уникального идентификатора. Для этого он имеет типы SMALLSERIAL, SERIAL, BIGSERIAL, которые не являются настоящими типами, а скорее просто удобством записи столбцов с уникальным идентификатором. Столбец с одним из вышеперечисленных типов будет являться целочисленным и автоматически увеличиваться при добавлении новой записи.

MySQL 8.1
CREATE TABLE Goods (
	good_id SERIAL,
	good_name VARCHAR(255),
	type INT
);
MySQL 8.1
INSERT INTO Goods (good_name, type) VALUES ('Table', 2);