CASE предложение в ГДЕ - PullRequest
       6

CASE предложение в ГДЕ

0 голосов
/ 02 декабря 2018

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

https://leetcode.com/problems/consecutive-numbers/

Таблица выглядит как

| Id | Num |
|----|-----|
| 1  |  1  |
| 2  |  1  |
| 3  |  1  |
| 4  |  2  |
| 5  |  1  |
| 6  |  2  |
| 7  |  2  |

Правильная версия:

select distinct Num as ConsecutiveNums
from Logs, (select @prev := -1, @count := 0) as Init
where (@count := case when @prev = (@prev := Num) then @count + 1 else 1 end) >= 3

Выход:

| ConsecutiveNums |
|-----------------|
|       1         |

Неправильная версия:

select distinct Num as ConsecutiveNums
from Logs, (select @prev := -1, @count := 0) as Init
where (case when @prev = (@prev := Num) then @count := @count + 1 else @count :=  1 end) >= 3

Выход:

| ConsecutiveNums |
|-----------------|
|       1         |
|       2         |

Единственная разница @число: = перемещено в конец дела .

Кажется, что else part вызывает некоторую ошибку, которая не может быть объяснена моими знаниями.

Ответы [ 3 ]

0 голосов
/ 03 декабря 2018

Если последовательно означает, что идентификаторы увеличиваются на «1» (как в примере данных), то переменные не нужны - или даже не желательны:

select t1.num
from t t1 join
     t t2
     on t2.id = t1.id + 1 and t2.num = t1.num join
     t t3
     on t3.id  = t1.id + 2 and t3.num = t1.num;

Если у вас есть более трех последовательных значенийили num, который соответствует нескольким строкам, тогда вы можете захотеть select distinct num.

0 голосов
/ 03 декабря 2018

Вторая версия кода не работает по довольно непонятной причине.Эта часть:

else @count :=  1

... имеет выражение, которое не имеет динамического компонента.MySql оптимизирует свой план выполнения таким образом, что он не выполняет это назначение во второй раз, а просто возвращает текущее значение @count.Это связано с тем, что переменные MySql действительно не предназначены для изменения во время выполнения запроса.Когда вы все еще решаете использовать этот побочный эффект, вы должны знать о таком поведении «оптимизации».

Вы можете попытаться заставить MySql выполнять присваивание каждый раз.Это можно сделать, включив ссылку на переменную или поле в назначенное выражение.Например, вы можете использовать := if(@count, 1, 1) вместо := 1.Результат тот же (всегда 1), но теперь он будет переоцениваться и присваиваться каждый раз, когда он встречается:

where (case when @prev = (@prev := Num)  
            then @count := @count + 1
            else @count := if(@count, 1, 1)
       end) >= 3

Вы можете думать о других альтернативных выражениях, таких как := 1+Num*0, до тех пор, покапоскольку есть ссылка на некоторую переменную / поле, это решит проблему.

Глядя на первую предоставленную вами версию запроса, вы увидите, что там выражение, присвоенное @count, уже имеет такоединамическое содержимое.

В общем, установка переменных в запросе не рекомендуется, и будущие версии MySql могут больше не поддерживать его, как указано в Справочном руководстве :

Предыдущие выпуски MySQL позволяли присваивать значение пользовательской переменной в операторах, отличных от SET.Эта функциональность поддерживается в MySQL 8.0 для обратной совместимости, но подлежит удалению в будущем выпуске MySQL.

0 голосов
/ 02 декабря 2018

Потому что вы не сравниваете "> = 3" с количеством.Это то, против чего мы пытаемся протестировать 3 последовательных числа.В неправильной версии не уверен, почему было "= - 10", хотя.Исправленная версия «неправильной» версии:

SELECT num AS ConsecutiveNums
FROM   logs,
       (SELECT @prev := -1,
               @count := 0) AS Init
WHERE ( @count := CASE
           WHEN @prev = ( @prev := num ) THEN @count := @count + 1
           ELSE @count
         end ) >= 3

Я также добавил другой тестовый пример, чтобы убедиться:

{"headers": {"Logs": ["Id", "Num"]}, "rows": {"Logs": [[1, 2], [2, 1], [3, 1], [4, 6], [5, 2], [6, 2], [7, 2]]}}

Стандартный вариант без изменения тестового примера дает«1» этот тест должен возвращать «2»

...