SQL INSERT INTO: примеры вставки строк в таблицу БД MySQL

SQL оператор INSERT используется для вставки записей в существующую таблицу.

Синтаксис этого оператора следующий:

INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
      [INTO] tbl_name [(col_name,...)]
        VALUES (expression,...),(...),...

или 

INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
        [INTO] tbl_name [(col_name,...)]
        SELECT ...

или 

INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
        [INTO] tbl_name
        SET col_name=expression, col_name=expression, ...

Создадим тестовую таблицу

Давайте создадим таблицу table1 со столбцами a, b, c в нашей MySQL базе данных:

CREATE TABLE `table1` (
      `a` INT(11),
      `b` INT(11),
      `c` INT(11)
);

Запрос на вставку строки

Простой запрос, который вставляет строку со столбцами 111, 222 и 333 выглядит так:

INSERT INTO table1 (a, b, c) VALUES (111, 222, 333);

Еще один способ сделать то же самое:

INSERT INTO table1 SET a=111, b=222, c=333;

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

У таблиц обычно есть поле id с первичным ключом (PRIMARY KEY) таблицы. Если этому полю установлено значение AUTOINCREMENT т.е. оно заполняется автоматически, то в таком случае вы не должны его перечислять в списке столбцов оператора INSERT.

Вставка без перечисления столбцов

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

INSERT INTO table1 VALUES (111, 222, 333);

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

Вставка сразу нескольких строк с помощью INSERT INTO

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

INSERT INTO table1 (a, b, c) VALUES 
    (1, 222, 333), 
    (2, 555, 666),
    (3, 555, 333);

Таким образом мы вставили 3 строки в нашу таблицу table1. Их может быть и больше. В MySQL четкого предела нет, однако он все таки существует и зависит от параметра max_allowed_packet который ограничивает размер запроса. Если вы установите SET GLOBAL max_allowed_packet=524288000; то размер запроса будет ограничен 500MB но делайте это в очень крайнем случае. Обычно всегда можно найти решение и разделить 1 большой запрос, на несколько более мелких и вставлять например не больше 1000 строк за один цикл.

Как вставить значение из другой таблицы INSERT INTO ... SELECT ...

Допустим у нас есть еще одна таблица table2 которая по структуре точно такая же как и первая. Нам в таблицу table2 нужно вставить все строки из table1.

Вставляем значения из table1 в таблицу table2:

INSERT INTO table2 (a, b, c) SELECT a, b, c FROM table1;

Вам следует позаботиться об уникальности ключей, если они есть в таблице, в которую мы вставляем. Например при дублировании PRIMARY KEY мы получим следующее сообщение об ошибке:

/* ERROR 1062 (23000): Duplicate entry '100' for key 'PRIMARY' */

Если вы делаете не какую-то единичную вставку при переносе данных, а где-то сохраните этот запрос, например в вашем PHP скрипте, то всегда перечисляйте столбцы.

Как не рекомендуется делать (без перечисления столбцов):

INSERT INTO table2 SELECT * FROM table1;

Если у вас со временем изменится количество столбцов в таблице, то запрос перестанет работать. При выполнении запроса MySQL в лучшем случае просто будет возвращать ошибку:

/* Ошибка SQL (1136): Column count doesn't match value count at row 1 */

Либо еще хуже: значения вставятся не в те столбцы.

Вставка из другой таблицы с условием INSERT INTO ... SELECT ... WHERE ...

А теперь представим, что нам нужно вставить только те строки из table1, у которых столбец "c" равен 333. Тогда наш запрос будет выглядеть так

INSERT INTO table2 (a, b, c)
    SELECT a, b, c FROM table1 
    WHERE c = 333;

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

Теперь представим, что у нас в таблице table2 - 4 столбца, а в table1 - 3. При этом четвертый столбец в table2 обязательный. Чтобы выйти из этой ситуации, нужно передать какое-нибудь подходящее значение в этот лишний столбец. У нас чисто абстрактная задача, поэтому давайте передадим туда просто единицу.

INSERT INTO table2 (a, b, c, d)
    SELECT a, b, c, 1 FROM table1 
    WHERE c = 333;

Теперь в столбец d у нас записалась единица и проблема решена.

Вставка в определенный раздел INSERT INTO ... PARTITION ...

Подробнее о разделах: https://dev.mysql.com/doc/refman/5.7/en/partitioning-overview.html

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

INSERT INTO table1 PARTITION (p1) VALUES(1, 2, 3);

Вставка в несколько разделов. Первая строка вставляется в раздел p1, а вторая в p2

INSERT INTO table1 PARTITION (p1, p2) VALUES(1, 2, 3), (4, 5, 6);

Больше примеров для работы с разделами: https://dev.mysql.com/doc/refman/5.6/en/partitioning-selection.html

Вставка строк, некоторые из которых уже существуют в целевой таблице

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

Игнорирование INSERT IGNORE INTO

Например если мы вставляем строку с PK = 1, и при этом в таблице уже есть PK = 1 то MySQL выдаст ошибку:

/* ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY' */

Выполнение запроса на этом прервется, однако нам в некоторых случаях хотелось бы просто вставить данные, игнорируя ошибки. В этом нам поможет INSERT IGNORE INTO:

INSERT IGNORE INTO table1 (a, b, c) VALUES 
    (1, 222, 333), 
    (2, 555, 666),
    (3, 555, 333);

Просто добавляем IGNORE в наш запрос и ошибки будут игнорироваться

Вставка с заменой существующих значений REPLACE INTO

REPLACE работает также INSERT, но если совпадают уникальные ключи, то старая строка (или строки!) удаляется до вставки новой.

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

REPLACE INTO table1 (a, b, c) VALUES 
    (1, 222, 333), 
    (2, 555, 666),
    (3, 555, 333);

Обновление некоторых полей, при существовании строк ON DUPLICATE KEY UPDATE

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

Наш запрос будет выглядеть так:

INSERT INTO table1 (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=VALUES(c);

В данном примере если у нас какой-то уникальный ключ совпадает, то мы не производим вставку, а обновляем существующую строку или строки путем присваивания столбцу "c" значения, которое у нас перечислено в VALUES.

Иными словами, если ключ совпадает, то мы просто обновим данные столбца "с" а остальные столбцы трогать не будем.

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

INSERT INTO table1 (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE a=VALUES(a), b=VALUES(b), c=VALUES(c);

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

INSERT INTO table1 (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

Подробнее про ON DUPLICATE KEY UPDATE

Выражения для вставляемых значений в VALUES

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

Пример использования выражений:

INSERT INTO table1 (a, b, c) VALUES 
    (1, 222, 333 + a), 
    (2, 555, 666 + b);

Таким образом мы для формирования столбца "c" использовали столбцы "a" и "b".

Приоритет вставки INSERT LOW_PRIORITY / HIGH_PRIORITY

Установление приоритета нужно для решение проблем с конкурентными вставками. При вставках происходит блокировка строк и если 2 INSERT запроса требуют блокировки одних и тех же строк, для своего выполнения, то иногда может потребоваться повысить или понизить приоритет некоторых запросов, по отношению к другим. Это можно сделать указав приоритет LOW_PRIORITY или HIGH_PRIORITY

Наш запрос будет выглядеть так для LOW_PRIORITY:

INSERT LOW_PRIORITY INTO table1 (a, b, c) VALUES(1, 2, 3);

HIGH_PRIORITY:

INSERT HIGH_PRIORITY INTO table1 (a, b, c) VALUES(1, 2, 3);