На каких базах данных может работать следующий SQL? - PullRequest
3 голосов
/ 22 октября 2011

Я создал запрос, и мне интересно, будет ли он работать на любой базе данных, кроме MySQL.На самом деле я никогда не использовал другую базу данных, поэтому меня не устраивают различия.

UPDATE `locks` AS `l1`
  CROSS JOIN (SELECT SUM(`value`) AS `sum` FROM `locks`
              WHERE `key` IN ("key3","key2")) AS `l2`
SET `l1`.`value` = `l1`.`value` + 1
WHERE `l1`.`key` = "key1" AND (`l2`.`sum` < 1);

Вот некоторые особенности, на которые я полагаюсь (насколько я могу думать о них):

  1. Запросы на обновление.
  2. Включение в запросы на обновление.
  3. Агрегирование функций в запросах, не сгруппированных явно.
  4. ГДЕ ...В состоянии.

Я уверен, что людям будет любопытно, что именно это делает, и это может также включать функции базы данных, которые могут быть не повсеместными.Это реализация взаимного исключения с использованием базы данных, предназначенной для веб-приложения.В моем случае это было необходимо, потому что определенные действия пользователя приводят к удалению и воссозданию таблиц с разными столбцами, и я хочу избежать ошибок, если другие части приложения пытаются вставить данные.Поэтому реализация специализирована для решения проблемы читателей-писателей .

. В этом запросе предполагается, что существует таблица locks с двумя полями: key (varchar) и value (int).Далее предполагается, что таблица содержит строку, такую, что key = "key1".Затем он пытается увеличить value для «key1».Это происходит только в том случае, если для каждого key в списке ("key2","key3") связанный value равен 0 (условие WHERE для l2 является приближением, в котором value никогда не бывает отрицательным).Поэтому этот запрос «получает блокировку» только при соблюдении определенных условий, предположительно атомарным способом.Затем приложение проверяет, получило ли оно блокировку по возвращаемому значению запроса, которое предположительно указывает, сколько строк было затронуто.Если и только если ни одна строка не была затронута, приложение не получило блокировку.

Итак, вот дополнительные условия, не различимые в самом запросе:

  1. Предполагается, что вВ многопоточной среде, копия этого запроса никогда не будет чередоваться с другой копией.
  2. При обработке запроса должно быть возвращено, были ли затронуты какие-либо значения.

В качестве вторичного запроса ябыл бы признателен за любые ресурсы по "стандартному SQL".Я слышал об этом, но так и не смог найти какое-либо определение, и мне кажется, что мне не хватает многих вещей, когда в документации MySQL говорится, что «эта функция является расширением стандартного SQL».

Основываясь на ответах, этот запрос должен работать лучше во всех системах:

UPDATE locks AS l1
  CROSS JOIN (SELECT SUM(val) AS others FROM locks
              WHERE keyname IN ('key3','key2')) AS l2
SET l1.val = l1.val + 1
WHERE l1.keyname = 'key1' AND (l2.others < 1);

Upvotes для всех из-за хороших ответов.Отмеченный ответ направлен на прямой ответ на мой вопрос, даже если он предназначен только для одной другой СУБД, и хотя могут быть лучшие решения для моей конкретной проблемы (или даже проблемы кросс-платформенного SQL в целом).

Ответы [ 3 ]

6 голосов
/ 22 октября 2011

Этот точный синтаксис будет работать только в MySQL.

Это уродливый обходной путь для этой конструкции:

UPDATE  locks
SET     value = 1
WHERE   key = 'key1'
        AND NOT EXISTS
        (
        SELECT  NULL
        FROM    locks li
        WHERE   li.key IN ('key2', 'key3')
                AND li.value > 0
        )

, который работает во всех системах, кроме MySQL, поскольку последняя не допускает подзапросов к целевой таблице в операторах UPDATE или DELETE.

3 голосов
/ 22 октября 2011

для PostgreSQL

1) Обновление запросов.

Не могу представить СУРБД, в которой нет UPDATE. (?)

2) Присоединяется к запросам на обновление.

В PostgreSQL вы бы добавили дополнительные таблицы с FROM from_list.

3) Агрегатные функции в несгруппированных запросах.

Не возможно в PostgreSQL. Для этого используйте подзапросы, функции CTE или Window.
Но ваш запрос сгруппирован . Предложение GROUP BY просто не прописано. Это работает и в PostgreSQL.

Наличие HAVING превращает запрос в сгруппированный запрос, даже если нет предложения GROUP BY. Это то же самое, что происходит, когда запрос содержит агрегатные функции, но не содержит предложения GROUP BY.

(Цитата из руководства ).

4) ГДЕ ... В состоянии

Работает в любой известной СУБД.

«Дополнительные условия»: предполагается, что в многопоточной среде копия этого запроса никогда не будет чередоваться с другой копией.

Многоверсионная модель PostgreSQL MVCC (Multiversion Concurrency Control) превосходит MySQL для обработки параллелизма. С другой стороны, большинство СУБД превосходит MySQL в этом отношении.

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

Postgres делает это, почти все СУБД.

Кроме того, этот запрос не будет работать в PostgreSQL, потому что:

  • нет идентификаторов с обратными галочками (это сленг MySQL).
  • значения должны быть в одинарных кавычках, а не в двойных.

См. Список зарезервированных слов в стандартах Postgres и SQL .
A объединенный список для различных РСУБД .

2 голосов
/ 22 октября 2011

Это будет работать только в mysql только потому, что вы используете разделитель "` ", который зависит только от mysql.

Что если вы замените разделитель на более" стандартный ": тогда, вероятно, он будет работать ввсе современные СУБД (postgres, sql server, oracle), но я бы никогда не написал общий запрос для всех - я бы лучше написал конкретный запрос для каждой используемой (или потенциально используемой) СУБД, чтобы использовать ее специфические языковые диалекты, чтобы получить лучшеепроизводительность и удобочитаемость запросов.

А как насчет "Как дополнительный запрос, я был бы признателен за любые ресурсы по" стандартному SQL "." --- посмотрите на http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...