logo

Paleta - Deixe colorido🎨

Palette — Construtor visual de páginas. Não precisa ser designer.

Demonstração ao vivo Baixar Palette

Scroll
09/05/2020, by maria

Запросы слияния представляют собой особый тип гибридного запроса. Хотя синтаксис для них определен в спецификации 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();

O exemplo acima comporta-se como o primeiro, exceto que se o registro já existe e estamos atualizando, field1 receberá $alternate1 em vez de $value1, e field2 não será afetado. O método updateFields() aceita um array associativo de valores ou dois arrays numéricos paralelos — um de campos, outro de valores — na mesma ordem.

$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(), не будут затронуты.

Обратите внимание, что все еще возможно определить запросы, которые не имеют смысла. Разработчик должен убедиться, что бессмысленный запрос не указан, поскольку поведение в этом случае не определено.