Гарантии при использовании пользовательских переменных для нумерации строк

использование пользовательских переменных для нумерации строк

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

SELECT *
FROM (SELECT *, (@row := @row + 1) AS rownum
      FROM (SELECT @row := 0) AS init, tablename
      ORDER BY tablename.ordercol
     ) sub
WHERE rownum % 2 = 1

этот подход, похоже, обычно работа.

причины быть осторожным

С другой стороны,MySQ docs состояние:

как правило, вы никогда не должны присваивать значения переменной пользователя, и посмотреть значение в том же заявлении. Вы можете получить ожидаемые результаты, но это не гарантируется. Порядок оценки выражений с пользовательскими переменными не определен и может изменяться на основе элементов, содержащихся в данном операторе; кроме того, этот порядок не гарантируется одинаковым между выпусками сервера MySQL.

основной вопрос

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

By "гарантии" я имею в виду авторитетные источники, такие как MySQL документация или некоторые стандартные утверждения MySQL соответствуют. Не имея таких авторитетных ответов, другие источники, такие как часто используемые учебники или части исходного кода MySQL, могут быть процитированы вместо этого. By "комбината" я имею в виду тот факт, что задания будут выполняться последовательно, один раз в строке результата и в порядке, индуцированном ORDER BY линии.

пример прерывания запроса

чтобы дать вам пример, как легко вещи fail:

SELECT *
FROM (SELECT *, (@row := @row + 1) AS rownum
      FROM (SELECT @row := 0) AS init, tablename
      HAVING rownum > 0
      ORDER BY tablename.ordercol
     ) sub
WHERE rownum % 2 = 1

произведет пустой результат на MySQL 5.5.27, установленном в настоящее время на SQL Fiddle. Причина заключается в том, что HAVING результате rownum выражение, чтобы получить оценку дважды, поэтому конечный результат будет иметь только четные числа. У меня есть идея о том, что происходит за кулисами, и я не утверждаю, что запрос HAVING имеет смысл. Я просто хочу продемонстрировать, что существует тонкая грань между кодом, который работает и код, который выглядит очень похожим, но ломается.

1 ответов


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

но гарантия будущего? Кто знает.


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

в инструкции SELECT каждое выражение select оценивается только тогда, когда отправлено клиенту. Это означает, что в наличии, группе или порядке предложение, ссылающееся на переменную, которой присвоено значение в select список выражений работает не так, как ожидалось

порядок обработки запросов примерно

FROM / JOIN
WHERE / ON
GROUP BY / ROLLUP
HAVING
UNION
SELECT
ORDER BY
@variable resolution

ваш "сломанный" запрос пытается использовать переменная того же уровня, что и использование предложения WHERE/HAVING против псевдонима столбца. Вот почему вы никогда не увидите решения для нумерации строк на основе переменных MySQL, использующие переменную на том же уровне запроса, она всегда находится в подзапросе. Внешний запрос можно считать client внутреннего запроса, на котором была отображена переменная / выражение-заполнитель. По вашему аргументу вы можете так же легко сломать его, используя предложение WHERE с участием @row прямо (да это будет бежать!).