Выбор нескольких строк, в которых разница значений больше, чем x% - PullRequest
1 голос
/ 20 июня 2020

Я столкнулся со следующей проблемой ... Учитывая эти данные: таблица: голосов

=========
  value
=========
   10
   25
   38
   90
   92
   93
   98
   100
   120

Я хотел бы вернуть только значение, если разница между следующим и ранее принятым значением больше, чем 10% от первого:

if abs(int(a)-int(b))*100/int(a) < 10:
  return True

Итак, конечный список должен быть (я добавил процентную разницу в квадратных скобках):

==========
  result
==========
   10 ()
   25 (150%)
   38 (52%)
   90 (136%)
   100 (11%)
   120 (20%)

Запрос также должен сначала отсортировать эти значения .

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

MySQL v.8.0 0,19

Ответы [ 2 ]

0 голосов
/ 20 июня 2020

Вы не упоминаете, какую версию MySQL вы используете, поэтому я предполагаю, что это современная версия (8.x). Вы можете использовать LAG(). Например:

select
  concat('', value,
    case when prev_value is null then '' 
       else concat('', 100 * (value - prev_value) / prev_value, '%')
    end
  ) as result
from (
  select
    value,
    lag(value) over (order by value) as prev_value
  from t
) x
where prev_value is null or value > prev_value * 1.1
order by value
0 голосов
/ 20 июня 2020

В MySQL 8.0 это можно сделать с помощью lag(). Предполагая, что вы хотите отсортировать строки по value, это будет:

select value
from (
    select
        value,
        lag(value, 1, 0) over(order by value) lag_value
    from mytable t
) t
where value > lag_value * 1.10

Если вы хотите использовать другой столбец упорядочения, вы можете изменить предложение order by, чтобы использовать соответствующий столбец.

В более ранних версиях один вариант является коррелированным подзапросом:

select value
from mytable t
where value > 1.10 * coalesce(
    (
        select t1.value 
        from mytable t1 
        where t1.value < t.value
        order by t1.value desc
        limit 1
    ),
    0
)

Чтобы использовать здесь другой столбец упорядочения, вам нужно изменить предложение where и предложение order by в подзапрос.

С другой стороны, если вы хотите выбрать следующую строку в соответствии с соотношением к предыдущей выбранной строке, то это другой вопрос. Вам нужен какой-то итеративный процесс: в SQL одним подходом является рекурсивный запрос:

with 
    data as (
        select value, row_number() over(order by value) rn
        from mytable t
    ) d,
    cte as (
        select 1 is_valid, value, rn from data where rn = 1
        union all 
        select 
            (d.value > 1.1 * c.value),
            case when d.value > 1.1 * c.value then d.value else c.value end,
            d.rn
        from cte c
        inner join data d on d.rn = c.rn + 1
    )
    select value from cte where is_valid order by value

Запрос перечисляет значения, затем последовательно просматривает набор данных, отслеживая последнее выбранное значение, и установка флагов для записей, которые должны появиться в окончательном наборе результатов.

...