Spec-Zone.ru › SQLite

UPSERT

1. Синтаксис

upsert-оператор:

В КОНФЛИКТЕ ( индексированный-столбец ) ГДЕ выражение ВЫПОЛНИТЬ , конфликтная цель ОБНОВИТЬ УСТАНОВИТЬ список-имен-столбцов = выражение ГДЕ выражение НИЧЕГО , имя-столбца

список-имен-столбцов:

( имя-столбца ) ,

выражение:

значение-буквально связанный-параметр имя-схемы . имя-таблицы . имя-колонки унарный-оператор выражение выражение бинарный-оператор выражение имя-функции ( аргументы-функции ) часть-фильтра часть-over ( выражение ) , CAST ( выражение как имя-типа
) expr COLLATE имя_сортировки expr НЕ ПОДОБНО GLOB REGEXP СООТВЕТСТВУЕТ expr expr ESCAPE expr expr ISNULL NOTNULL НЕ NULL expr ЯВЛЯЕТСЯ НЕ РАЗЛИЧНЫМ ИЗ expr
expr НЕ МЕЖДУ expr И expr expr НЕ В ( выражение-select ) expr , имя-схемы . функция-таблицы ( expr ) имя-таблицы , НЕ СУЩЕСТВУЕТ ( выражение-select )
СЛУЧАЙ expr КОГДА expr ТОГДА expr ИНАЧЕ expr КОНЕЦ функция-вызов

оператор-фильтрации:

ФИЛЬТР ( ГДЕ expr )

аргументы-функции:

DISTINCT expr , * ORDER BY ordering-term ,

ordering-term:

expr COLLATE collation-name DESC ASC NULLS FIRST NULLS LAST

literal-value:

CURRENT_TIMESTAMP числовое_литерал строковая_литерал байтовый_литерал NULL ИСТИНА ЛОЖЬ ТЕКУЩЕЕ_ВРЕМЯ ТЕКУЩАЯ_ДАТА

оператор_over:

ПЕРЕД имя-окна ( базовое-имя-окна РАЗДЕЛЕННЫЙ ПО выражение , ПОРЯДОК ПО условия-упорядочивания , спецификация-кадра )

спецификация-кадра:

ГРУППЫ МЕЖДУ НЕОГРАНИЧЕННЫЕ ПРЕДШЕСТВУЮЩИЕ И НЕОГРАНИЧЕННЫЕ СЛЕДУЮЩИЕ ДИАПАЗОН СТРОКИ НЕОГРАНИЧЕННЫЕ ПРЕДШЕСТВУЮЩИЕ expr ПРЕДШЕСТВУЮЩИЕ ТЕКУЩИЙ СТРОКА expr ПРЕДШЕСТВУЮЩИЕ ТЕКУЩИЙ СТРОКА expr СЛЕДУЮЩИЕ expr ПРЕДШЕСТВУЮЩИЕ ТЕКУЩИЙ СТРОКА expr СЛЕДУЮЩИЕ
Исключить Текущий Строка Исключить Группа Исключить Связи Исключить Нет Другие

Сортировка элементов:

выражение СОРТИРОВКА название_сортировки по убыванию по возрастанию НУЛЕВЫЕ первый НУЛЕВЫЕ последний

Функция поднятия исключения:

ВОЗВЫШЕНИЕ ( ОТКАТ , сообщение об ошибке ) ИГНОРИРОВАТЬ ПРЕКРАТИТЬ ПРОВАЛ

заявление select:

С РЕКУРСИВНЫЕ выражение-с-общим-табличным-выражением , ВЫБЕРИТЕ УНИКАЛЬНЫЕ столбец-результата , ВСЕ ИЗ таблицы-или-подзапроса условие-соединения , ГДЕ выражение ГРУППИРОВАТЬ ПО выражение С УСЛОВИЕМ выражение ,
ОКОН имя-окна КАК определение-окна , ЗНАЧЕНИЯ ( выражение ) , , составной-оператор select-core ПОРЯДОК ПО ОГРАНИЧЕНИЕ выражение член-упорядочивания , СМЕЩЕНИЕ выражение , выражение

общее-выражение-с-подзапросом:

имя_таблицы ( имя_столбца ) AS НЕ МАТЕРИАЛИЗОВАННЫЙ ( выражение_select ) ,

сложный_оператор:

ОБЪЕДИНЕНИЕ ОБЪЕДИНЕНИЕ ПЕРЕСЕЧЕНИЕ ИСКЛЮЧЕНИЕ ВСЕ

запрос_соединения:

table-or-subquery join-operator table-or-subquery join-constraint

join-constraint:

USING ( column-name ) , ON expr

join-operator:

NATURAL LEFT OUTER JOIN , RIGHT FULL INNER CROSS

join-operator:

NATURAL LEFT OUTER JOIN , <path class="stroke" d="M189,
expr COLLATE collation-name DESC ASC NULLS FIRST NULLS LAST

result-column:

expr AS имя_псевдонима_столбца * имя_таблицы . *

таблица_или_подзапрос:

имя-схемы . имя-таблицы КАК псевдоним-таблицы ИНДЕКСИРОВАН ПО имя-индекса НЕ ИНДЕКСИРОВАН имя-функции-таблицы ( выражение ) , КАК псевдоним-таблицы ( выражение-select ) ( таблица-или-подзапрос ) ,
join-clause

window-defn:

( base-window-name PARTITION BY expr , ORDER BY ordering-term , frame-spec )

frame-spec:

ГРУППЫ МЕЖДУ НЕОГРАНИЧЕННЫЕ ПРЕДШЕСТВУЮЩИЕ И НЕОГРАНИЧЕННЫЕ СЛЕДУЮЩИЕ ОБЛАСТЬ СТРОКИ НЕОГРАНИЧЕННЫЕ ПРЕДШЕСТВУЮЩИЕ expr ПРЕДШЕСТВУЮЩИЕ ТЕКУЩАЯ СТРОКА expr ПРЕДШЕСТВУЮЩИЕ ТЕКУЩАЯ СТРОКА expr СЛЕДУЮЩИЕ expr ПРЕДШЕСТВУЮЩИЕ ТЕКУЩАЯ СТРОКА expr СЛЕДУЮЩИЕ
EXCLUDE CURRENT ROW EXCLUDE GROUP EXCLUDE TIES EXCLUDE NO OTHERS

type-name:

name ( signed-number , signed-number ) ( signed-number )

signed-number:

+ numeric-literal -

indexed-column:

имя_столбца COLLATE имя_сортировки DESC выражение ASC

2.Описание

Оператор UPSERT добавляется к оператору INSERT и заставляет его вести себя как UPDATE или как ничего не делать, если бы вставка нарушила ограничение уникальности. UPSERT не является стандартным SQL. UPSERT в SQLite следует синтаксису, установленному PostgreSQL, с обобщениями.

UPSERT — это обычное предложение INSERT, за которым следует одно или несколько предложений ON CONFLICT, как показано на диаграмме синтаксиса.

Синтаксис между ключевыми словами «ON CONFLICT» и «DO» называется «целью конфликта». Цель конфликта указывает ограничение уникальности, которое будет триггерить upsert. Цель конфликта может быть опущена в последнем предложении ON CONFLICT в операторе INSERT, но она обязательна для всех остальных предложений ON CONFLICT.

Если операция вставки приведет к нарушению ограничения уникальности в целевом конфликте, то вставка пропускается, и вместо этого выполняется соответствующая операция DO NOTHING или DO UPDATE. Предложения ON CONFLICT проверяются в указанном порядке. Если в последнем предложении ON CONFLICT опущена цель конфликта, то оно будет выполнено, если какое-либо ограничение уникальности будет нарушено, которое не отслеживается предыдущими предложениями ON CONFLICT.

Для каждой строки вставки может быть выполнено только одно предложение ON CONFLICT, а именно первое предложение ON CONFLICT с соответствующей целью конфликта. Когда срабатывает предложение ON CONFLICT, все последующие предложения ON CONFLICT пропускаются для этой строки.

В случае многострочной вставки решение upsert принимается раздельно для каждой строки вставки.

Обработка UPSERT выполняется только для ограничений уникальности. «Ограничение уникальности» — это явное ограничение UNIQUE или PRIMARY KEY в операторе CREATE TABLE или уникальный индекс unique index. UPSERT не вмешивается в случае нарушения ограничений NOT NULL, CHECK или внешних ключей, а также ограничений, реализованных с помощью триггеров.

Имена столбцов в выражениях DO UPDATE относятся к исходному неизменённому значению столбца до попытки вставки. Чтобы использовать значение, которое было бы вставлено, если бы ограничение не было нарушено, добавьте специальный квалификатор таблицы «excluded.» к имени столбца.

2.1.Примеры

Некоторые примеры помогут проиллюстрировать работу UPSERT:

CREATE TABLE vocabulary(word TEXT PRIMARY KEY, count INT DEFAULT 1);
INSERT INTO vocabulary(word) VALUES('jovial')
  ON CONFLICT(word) DO UPDATE SET count=count+1;

Вышеупомянутая upsert вставляет новое слово «jovial» в словарь, если это слово ещё не существует в нём, или, если оно уже существует, увеличивает счётчик. Выражение «count+1» также можно записать как «vocabulary.count». PostgreSQL требует второй формы, но SQLite принимает любую из них.

CREATE TABLE phonebook(name TEXT PRIMARY KEY, phonenumber TEXT);
INSERT INTO phonebook(name,phonenumber) VALUES('Alice','704-555-1212')
  ON CONFLICT(name) DO UPDATE SET phonenumber=excluded.phonenumber;

Во втором примере выражение в предложении DO UPDATE имеет вид «excluded.phonenumber». Префикс «excluded.» заставляет «phonenumber» ссылаться на значение для phonenumber, которое было бы вставлено, если бы не было конфликта. Таким образом, эффект upsert заключается в вставке номера телефона Алисы, если он не существует, или в перезаписи любого предыдущего номера телефона для Алисы новым.

Обратите внимание, что предложение DO UPDATE действует только на строку, которая столкнулась с ошибкой ограничения во время вставки. Не нужно включать предложение WHERE, которое ограничивает действие только этой строкой. Единственное использование предложения WHERE в конце DO UPDATE — это необязательно сделать DO UPDATE ничем не делящимся, в зависимости от исходных и/или новых значений. Например:

CREATE TABLE phonebook2(
  name TEXT PRIMARY KEY,
  phonenumber TEXT,
  validDate DATE
);
INSERT INTO phonebook2(name,phonenumber,validDate)
  VALUES('Alice','704-555-1212','2018-05-08')
  ON CONFLICT(name) DO UPDATE SET
    phonenumber=excluded.phonenumber,
    validDate=excluded.validDate
  WHERE excluded.validDate>phonebook2.validDate;

В этом последнем примере запись phonebook2 обновляется только в том случае, если validDate для нового вставленного значения новее, чем запись, уже существующая в таблице. Если таблица уже содержит запись с тем же именем и текущей validDate, то предложение WHERE заставляет DO UPDATE стать пустой операцией.

2.2.Неясность синтаксического анализа

Когда оператор INSERT, к которому прикреплен UPSERT, получает свои значения из оператора SELECT, существует потенциальная неясность синтаксического анализа. Парсер может не определить, вводит ли ключевое слово «ON» UPSERT или является ли оно предложением ON для соединения. Чтобы обойти эту проблему, предложение SELECT всегда должно включать предложение WHERE, даже если это просто «WHERE true».

Неоднозначное использование ON:

INSERT INTO t1 SELECT * FROM t2
ON CONFLICT(x) DO UPDATE SET y=excluded.y;

Неясность, разрешённая с помощью предложения WHERE:

INSERT INTO t1 SELECT * FROM t2 WHERE true
ON CONFLICT(x) DO UPDATE SET y=excluded.y;

3.Ограничения

UPSERT в настоящее время не работает для виртуальных таблиц.

Алгоритм разрешения конфликтов для операции обновления в предложении DO UPDATE всегда ABORT. Другими словами, поведение такое, как если бы предложение DO UPDATE фактически было написано как «DO UPDATE OR ABORT». Если предложение DO UPDATE обнаружит какое-либо нарушение ограничения, весь оператор INSERT откатывается и останавливается. Это верно даже если предложение DO UPDATE содержится внутри оператора INSERT или триггера, который указывает другой алгоритм разрешения конфликтов.

4.История

Синтаксис UPSERT был добавлен в SQLite с версией 3.24.0 (2018-06-04). Исходная реализация тесно следовала синтаксису PostgreSQL, так как она допускала только одно предложение ON CONFLICT и требовала цель конфликта для ON DO UPDATE. Синтаксис был обобщён для разрешения нескольких предложений ON CONFLICT и допускал разрешение DO UPDATE без цели конфликта в версии SQLite 3.35.0 (2021-03-12).

Последнее изменение этой страницы 2024-04-11 23:26:09 UTC

SQLite is in the Public Domain.
https://sqlite.org/lang_upsert.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API