# INSERT

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

## Синтаксис {: #syntax }

![Insert](../../images/ebnf/insert.svg)

### Выражение {: #expression }

??? note "Диаграмма"
    ![Expression](../../images/ebnf/expression.svg)

### Литерал {: #literal }

??? note "Диаграмма"
    ![Literal](../../images/ebnf/literal.svg)

## Параметры {: #params }

* **TABLE** — имя таблицы. Соответствует правилам имен для всех
  [объектов](object.md) в кластере.

## Требуемые привилегии {: #required_privileges }

Данная команда требует привилегии `WRITE TABLE`.

См. также:

- [Управление доступом — Таблица привилегий](../../admin/access_control.md#privileges_table)

## Примеры вставки данных {: #examples }

??? example "Тестовые таблицы"
    Примеры использования команд включают в себя запросы к [тестовым
    таблицам](../legend.md).

С явным указанием колонок:

```sql
INSERT INTO warehouse (id, item, type) VALUES (1, 'bricks', 'heavy');
```

Без указания колонок (при условии, что передаются значения для всех колонок):

```sql
INSERT INTO warehouse VALUES (1, 'bricks', 'heavy');
```

## Обработка конфликтов {: #conflicts }

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

```sql
INSERT INTO warehouse (id, item, type)
VALUES (1, 'bricks', 'heavy');
```

Результат:

```
---
sbroad: Lua error (IR dispatch): LuaError(ExecutionError("sbroad: failed to create transaction: RolledBack(FailedTo(Insert, Some(Space), \"TupleFound: Duplicate key exists in unique index \\\"WAREHOUSE_pkey\\\" in space \\\"WAREHOUSE\\\" with old tuple - [1, 1934, \\\"bricks\\\", \\\"heavy\\\"] and new tuple - [1, 1934, \\\"bricks\\\", \\\"heavy\\\"]\"))"))
```

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

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

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

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

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

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

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

```sql
INSERT INTO warehouse (id, item, type)
VALUES (1, 'bricks', 'heavy')
ON CONFLICT DO NOTHING;
```

Результат:

```
0
```

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

```sql
INSERT INTO warehouse (id, item, type)
VALUES (1, 'bricks', 'heavy')
ON CONFLICT DO REPLACE;
```

Результат:

```
1
```

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

!!! note "Примечание"
    При вставке в таблицу большого числа строк может сработать
    ограничение на число
    [инструкций](https://www.sqlite.org/opcode.html) и/или размер
    результирующей виртуальной таблицы. Для обхода ограничений
    используйте дополнительные параметры, описанные в разделе
    [Неблокирующие запросы](non_block.md).

## Параметризация {: #parametrization }

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