Есть много неожиданных вещей, которые могут произойти при использовании переменных.Некоторые из них перечислены в руководстве :
В операторе SELECT каждое выражение выбора оценивается только при отправке клиенту.Это означает, что в предложении HAVING, GROUP BY или ORDER BY ссылка на переменную, которой назначено значение в списке выражений выбора, работает не так, как ожидалось
Точные детали могут отличаться, но вв вашем случае ваш приращение оценивается дважды (один раз в select
, один раз для having
), поэтому он в основном ведет себя как
SELECT (@cnt := @cnt + 1) AS Rank, Test.col1
FROM Test
CROSS JOIN (SELECT @cnt := 0) AS tmp
having (@cnt := @cnt + 1) > 1;
Одним из способов решения этой проблемы является принудительное выполнение MySQL для предварительного вычисления выражения..
Правильное решение (насколько это возможно при использовании переменных), вероятно, таково:
select (
SELECT (@cnt := @cnt + 1) AS Rank, Test.col1
FROM Test
CROSS JOIN (SELECT @cnt := 0) AS tmp
) x
where Rank > 1;
where Rank > 1
(без подзапроса) скорее всего то, что вы изначально намеревались сделать в любом случае.
Но вы можете сделать это и другими способами.В вашем примере вы должны иметь возможность использовать
SELECT (@cnt := @cnt + 1) AS Rank, Test.col1
FROM Test
CROSS JOIN (SELECT @cnt := 0) AS tmp
group by col1
having Rank > 1;
Если col1
не является кандидатом в первичный ключ (например, уникальное значение, а не нуль), MySQL должен фактически оценить выражение, чтобы выполнить group by
.С другой стороны, если col1
равен , например, первичный ключ, MySQL может оптимизировать group by
и вы вернетесь к исходной ситуации - если он делает , то можетзависит от вашей версии MySQL, но Afaik MySQL 5.6 должен делать это.
Примечание: поскольку rank
стало ключевым словом в MySQL 8, вы не должны использовать его в качестве псевдонима в случае, если вы когда-либо намереваетесь выполнить обновление.