Запросы слияния merge
Запросы слияния представляют собой особый тип гибридного запроса. Хотя синтаксис для них определен в спецификации SQL 2003, практически ни одна база данных не поддерживает стандартный синтаксис. Однако большинство из них предоставляют альтернативную реализацию с использованием синтаксиса, специфичного для базы данных. Построитель запросов слияния в Drupal абстрагирует концепцию запроса слияния в структурированный объект, который может быть скомпилирован с соответствующим синтаксисом для каждой базы данных. Их иногда называют запросами "UPSERT", комбинацией UPDATE и INSERT.
В общем смысле запрос на слияние - это сочетание запроса на вставку и запроса на обновление. Если данное условие выполнено, например, строка с заданным первичным ключом уже существует, выполняется запрос на обновление. Если нет, выполняется запрос на вставку. В наиболее распространенном случае это эквивалентно:
if ($connection->query("SELECT COUNT(*) FROM {example} WHERE id = :id", [':id' => $id])->fetchField()) { // Run an update using WHERE id = $id } else { // Run an insert, inserting $id for id }
Фактическая реализация сильно варьируется от базы данных к базе данных. Обратите внимание, что хотя запросы слияния концептуально являются атомарной операцией, они могут быть или не быть действительно атомарными в зависимости от реализации конкретной базы данных. Например, реализация MySQL - это отдельный атомарный запрос, но вырожденный случай (выше) - нет.
Наиболее распространенные идиомы для запросов Merge перечислены ниже.
Просто установите его
$connection->merge('example') ->key('name', $name) ->fields([ 'field1' => $value1, 'field2' => $value2, ]) ->execute();
В приведенном выше примере мы указываем запросу работать с таблицей «example». Затем мы указываем одно ключевое поле 'name' со значением $name. Затем мы указываем массив значений для установки.
Если уже существует строка, в которой поле «name» имеет значение $name, тогда поля field1 и field2 будут установлены на соответствующие значения в этой существующей строке. Если такой строки не существует, будет создана такая, в которой name имеет значение $ name, field1 имеет значение $value1, а field2 имеет значение $value2. Таким образом, в конце запроса конечный результат остается одинаковым независимо от того, существовала или нет строка.
Условный набор
В некоторых случаях может потребоваться установить значения по-разному в зависимости от того, существует ли уже запись, как определено полями key(). Есть два способа сделать это.
$connection->merge('example') ->insertFields([ 'field1' => $value1, 'field2' => $value2, ]) ->updateFields([ 'field1' => $alternate1, ]) ->key('name', $name) ->execute();
Приведенный выше пример будет вести себя так же, как и первый, за исключением того, что если запись уже существует и мы ее обновляем, для field1 будет установлено значение $alternate1 вместо $value1, и на field2 это не повлияет. Метод updateFields() принимает либо один ассоциативный массив значений, либо два параллельных числовых массива, одно из полей, одно из значений, которые должны быть в том же порядке.
$connection->merge('example') ->key('name', $name) ->fields([ 'field1' => $value1, 'field2' => $value2, ]) ->expression('field1', 'field1 + :inc', [':inc' => 1]) ->execute();
В этом примере, если запись уже существует, для field1 будет установлено ее текущее значение плюс 1. Это делает ее очень полезной для «встречных запросов», когда вы хотите увеличивать некоторый счетчик в базе данных каждый раз, когда происходит определенное событие. field2 по-прежнему будет иметь одинаковое значение независимо от того, существует запись или нет.
Обратите внимание, что expression() может вызываться несколько раз, по одному разу для каждого поля, которое должно быть установлено в выражение, если запись уже существует. Первый параметр - это поле, второй - фрагмент SQL, указывающий на выражение, которому должно быть задано поле, а необязательный третий параметр - это массив значений заполнителей для вставки в выражение.
Также не требуется, чтобы поле, используемое в expression(), уже присутствовало в fields().
Учитывая приведенный выше API, вполне возможно определить запросы, которые не имеют логического смысла, скажем, если для поля установлено, что оба игнорируются и устанавливаются в выражение, если запись уже существует. Чтобы свести к минимуму возможные ошибки, применяются следующие правила:
- Если для поля установлено expression(), оно имеет приоритет над updateFields().
- Если значения указаны в updateFields(), только эти поля будут изменены, если запись уже существует. Поля, не указанные в updateFields(), не будут затронуты.
Обратите внимание, что все еще возможно определить запросы, которые не имеют смысла. Разработчик должен убедиться, что бессмысленный запрос не указан, поскольку поведение в этом случае не определено.
Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.