SQL запрос для подсчета, если несколько строк, ограниченных 2 строками с флагом bool true, удовлетворяют определенным условиям - PullRequest
0 голосов
/ 12 марта 2020

Скажем, у меня большой набор данных, подобный этому

row | id | flag | sequence | count |   text
...
...
1     abc  true     22         1       textA
2     abc  false    23         8       textB
3     abc  false    24         2       textZ
4     abc  true     25         1       textA

5     bdf  false    10         1       textA
6     bdf  true     11         1       textB
7     bdf  false    12         2       textA
8     bdf  false    13         4       textF
9     bdf  false    14         6       textZ
10    bdf  true     15         1       textA
...
20    dhg  true     5         4       textF
21    dhg  false    6         20       textZ
22    dhg  true     7         1       textA

...
...

Все строки с одинаковым идентификатором гарантированно будут в последовательной последовательности.

Помогите, пожалуйста, написать запрос для подсчета как 1, если

  1. несколько строк между 2 строками с флагом true имеют как минимум 2 строки
  2. и сумму (число)> 4.
  3. и хотя бы один из этой строки есть текст Z.

Таким образом, в приведенном выше наборе данных строки 1-4 удовлетворяют условию и должны учитываться как 1. строки 5-10 также удовлетворяют всем условиям, так что count теперь равен 2 , Строка 20-22 не удовлетворяет 2-му условию, поэтому счетчик остается равным 2. Для этого запроса в примере выше должно быть 2.

Спасибо.

Ответы [ 2 ]

1 голос
/ 12 марта 2020

Если я правильно понимаю, вы можете назначить группировку на основе количества true значений до заданного значения:

select id, min(row), max(row)
from (select t.*,
             sum(flag = 'true') over (partition by id order by row) as grp
      from t
     ) t
where not flag
group by id, grp
having count(*) >= 2 and   -- the first "true" is included
       sum(count) > 4 and
       sum(text = 'textZ') > 0;

Это фактически не проверяет, что группа заканчивается на true. Я не уверен, насколько это важно.

РЕДАКТИРОВАТЬ:

Если вам нужны фактические строки, то это немного сложнее, но вы можете сделать это с помощью оконных функций:

select id, min(row), max(row)
from (select t.*,
             sum(case when flag <> 'true' then 1 else 0 end) over (partition by id, grp_desc) as cnt_false,
             sum(case when flag <> 'true' then count else 0 end) over (partition by id, grp_desc) as sum_count,
             sum(case when flag <> 'true' and text = 'textZ' then 1 else 0 end) over (partition by id, grp_desc) as cnt_textZ
      from (select t.*,
                   sum(flag = 'true') over (partition by id order by row) as grp_inc,
                   sum(flag = 'true') over (partition by id order by row desc) as grp_desc
            from t
           ) t
     ) t
where cnt_false >= 2 and
      sum_count > 4 and
      cnt_textZ > 0;

Обратите внимание, что и group_inc, и group_desc определяют группы. Если вы можете жить только с одной «истинной» строкой, то group_inc включает первую, а group_desc включает последнюю.

0 голосов
/ 12 марта 2020

Я не могу придумать какой-либо «правильный» 1019 *, способ сделать это, проблема кажется слишком сложной, чтобы ее можно было решить в СУБД. Возможно, вам следует пересмотреть дизайн ваших таблиц, чтобы оптимизировать эту вещь.

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

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

Таким образом, вы можете сделать что-то вроде этого, чтобы выбрать список диапазонов, которые соответствуют вашим критериям:

-- note: variables are hard-typed
SET @i = '', @c = 0, @m = 0, @s = 0;

SELECT 
  `id`,
  `start`,
  `end`
FROM
(
  SELECT
    *,
    @s `start`,
    IF(`id` = @i AND `flag` AND @c >= 2 AND (`text` = 'TextZ' OR @m), `sequence`, 0) `end`,
    @s := IF(`flag`, `sequence`, IF(`id` <> @i, 0, @s)) `unused1`,
    @m := IF(`text` = 'TextZ', 1, IF(`flag`, 0, @m)) `unused2`,
    @c := IF(`id` = @i, IF(`flag`, 0, @c + 1), 0) `unused3`,
    @i := `id` `unused4`
  FROM `t`
) `a` WHERE `end` <> 0;

Вот функциональный пример для тестирования и просмотра: http://sqlfiddle.com/#! 9 / 95f2b / 3

И запрос, который выбирает допустимые диапазоны: http://sqlfiddle.com/#! 9 / 95f2b / 6

...