Перейти к содержанию

INSERT

DML-команда INSERT используется для записи кортежей в таблицу. На данный момент атомарность записи гарантируется только для одного кортежа в рамках одного запроса.

Синтаксис

INSERT INTO table ( column , ) values select ON CONFLICT DO NOTHING REPLACE FAIL

Выражение

Диаграмма

table . column expression IS NOT NULL OR AND * / + - = > < >= <= <> != expression NOT BETWEEN expression AND expression IN ( select values ) NOT EXISTS ( select values ( select values expression , ) literal cast NOT expression

Литерал

Диаграмма

TRUE FALSE NULL ? $ unsigned integer double decimal string

Параметры

  • TABLE — имя таблицы. Соответствует правилам имен для всех объектов в кластере.

Обработка конфликтов

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

INSERT INTO "characters" ("id", "name", "year") VALUES (10, 'Duke Caboom', 2019);
---
- null
- 'sbroad: Lua error (IR dispatch): LuaError(ExecutionError("sbroad: failed to create
  transaction: RolledBack(FailedTo(Insert, Some(Space), \"TupleFound: Duplicate key
  exists in unique index \\\"primary_key\\\" in space \\\"characters\\\" with old
  tuple - [10, 2695, \\\"The Dummies\\\", 2019] and new tuple - [10, 2695, \\\"Duke
  Caboom\\\", 2019]\"))"))'
...

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

  • FAIL, вернуть ошибку в случае конфликта
  • REPLACE, затереть старый кортеж новым по первичному ключу
  • NOTHING, ничего не делать (оставить старую версию кортежа)

Вариант с DO FAIL предполагает, что запрос будет возвращать ошибку в случае конфликта вставки. Может возникнуть ситуация, когда запрос успешно вставит данные на части узлов хранения, но вернет ошибку на остальных (данные на них откатятся), что приведет к неконсистентному состоянию кластера.

Чтобы решить эту проблему, можно повторить вставку с другими параметрами разрешения конфликта — например, DO REPLACE (замена кортежа на новый).

Вариант с DO REPLACE решает проблему конфликтов только в первичном ключе. Если таблица содержит несколько уникальных индексов (помимо первичного ключа) и конфликт произошел в одном из них, DO REPLACE вернет ошибку. На узле хранения, где произошел конфликт, данные не будут зафиксированы в таблице.

Вариант с DO NOTHING никогда не возвращает ошибку из-за конфликтов в уникальных индексах, т.к. просто оставляет старую версию кортежа в таблице. При такой вставке в результате вернется только количество успешно вставленных новых кортежей (кортежи, где был конфликт и остались прежние данные, в подсчет не попадают).

Если параметр ON CONFLICT не указан, то по умолчанию используется поведение DO FAIL.

INSERT INTO "characters" ("id", "name", "year")
VALUES (10, 'Duke Caboom', 2019)
ON CONFLICT DO NOTHING;
---
- row_count: 0
...

Для успешной вставки (замены кортежа) следует использовать вариант DO REPLACE:

INSERT INTO "characters" ("id", "name", "year")
VALUES (10, 'Duke Caboom', 2019)
ON CONFLICT DO REPLACE ;
---
- row_count: 1
...

Ошибка вставки может также быть вызвана ограничениями неблокирующего SQL. Если речь идет о запросе на вставку более одного кортежа, то для исправления неконсистентного состояния кластера следует повторить запрос с другим способом разрешения конфликтов DO NOTHING.

Параметризация

Параметризация значений при INSERT влияет на тип данных при выполнении запроса. Так, в обычном виде дробные числа конвертируются в числа с фиксированной запятой (например, values(2.5) в decimal 2.5). В параметризированном виде дробнному числу будет назначен типа с плавающей запятой (например, values(?), {2.5} в double 2.5). См. подробнее о типах данных.

Примеры

INSERT INTO assets VALUES (1, 'Woody', 2561);