Недавно я пытался использовать пользовательскую переменную для сбора некоторой информации из строки last , возвращенной в моем наборе результатов.
Я имею в виду, например, если у меня есть список имен от «Аарон» до «Заркс»,
SELECT @n:=Name FROM people ORDER BY Name;
SELECT @n;
Второй SELECT
должен вернуть 'Zzarx'.
Это простой случай. Это работает как ожидалось; назначение переменных надежно происходит в том же порядке, в котором строки отправляются клиенту, поэтому последнее назначение соответствует последней возвращенной строке.
Но странные вещи, кажется, происходят, когда запрос более сложен:
SELECT DISTINCT IFNULL(@n:=Name,'unknown') FROM people ORDER BY <some non-indexed expression> LIMIT 10;
SELECT @n;
Выполнение чего-то подобного в MariaDB v10.3.16 Я получаю конечное значение @n (из второго SELECT
) , которое не соответствует ни одной из строк, возвращаемых первым SELECT
! . (Обратите внимание, что Name - это столбец NOT NULL
, поэтому IFNULL()
на самом деле является избыточным, но все еще необходим для запуска этого поведения).
Обратите внимание, что это происходит только тогда, когда ВСЕ из следующего:
SELECT DISTINCT
ORDER BY
не может использовать индекс
- Переменная присваивается внутри некоторого выражения
Моя теория такова:
SELECT DISTINCT
вызывает раннюю оценку возвращенных выражений столбцов.
ORDER BY (non-indexed expression)
вызывает явную операцию сортировки после оценки данных столбца.
- Механизм SQL достаточно умен, чтобы распознавать простой шаблон
SELECT @var := (expression)
и оценивать @var только при отправке строки клиенту, но не может выполнить эту оптимизацию, если назначение @var:=...
встроено в большее выражение , как в IFNULL()
в моем примере.
Однако это всего лишь догадки.
Страница руководства по пользовательским переменным на самом деле не говорит ничего полезного (ни MySQL, ни MariaDB).
Мне кажется, что использование @variable для захвата чего-либо из последней возвращаемой строки в многострочном запросе является полезным и, вероятно, довольно распространенным трюком, но сейчас я не уверен, можно ли полагаться на него или когда Это. Точно так же для множества нумерованных строк и других хитроумных схем, которые я видел, которые используют @variables в части набора результатов SELECT
.
Имеет ли кто-то здесь в SO какую-либо определенную информацию о том, как это должно работать, и, в частности, , при каких условиях порядок вычислений выражений присваивания переменных в строке будет гарантированно соответствовать фактическому порядку строк вернулся?
... Потому что это очень важная вещь для понимания!
Другой, немного менее патологический пример:
Скажем, таблица t имеет 1000 строк:
SET @n:=0;
SELECT @n:=@n+1 FROM t ORDER BY 1 DESC LIMIT 5;
SELECT @n;
Возвращенные наборы результатов:
1000
999
998
997
996
и
1000
Обратите внимание, что еще раз, окончательное значение @n
НЕ соответствует последней возвращенной строке, и действительно, учитывая семантику запроса, в этом случае это не может.