SQL-запрос для подсчета строк на основе предыдущих значений другого столбца - PullRequest
0 голосов
/ 22 ноября 2018

Я работаю в SAS, и у меня есть таблица, которая выглядит следующим образом

ID | Time | Main | lag_1 | lag_2
----------------------------------------------------------------------------
A  |  01  |   0  |   0   |  1  
A  |  03  |   0  |   0   |  1  
A  |  04  |   0  |   0   |  0  
A  |  10  |   1  |   0   |  0  
A  |  11  |   1  |   0   |  0  
A  |  12  |   1  |   0   |  0  
B  |  02  |   1  |   1   |  1  
B  |  04  |   0  |   1   |  1  
B  |  07  |   0  |   0   |  1  
B  |  10  |   1  |   0   |  0  
B  |  11  |   1  |   0   |  0  
B  |  12  |   1  |   0   |  0  

, за исключением нескольких идентификаторов.Таблица отсортирована по ID и времени.После вычисления общего количества единиц в столбце Main (назовите его tot ), я пытаюсь вычислить 2 вещи:

  1. Общее количество единиц только в столбце Mainесли lag_1 был равен 1 в какое-то время до Main стал 1, скажем tot_1
  2. То же, что и 1., но в этом случае для lag_2 вызовите переменную tot_2

Таблица ожидаемых расчетов даст мне

tot | tot_1 | tot_2
--------------------
 7  |   3   |   6

, поскольку tot_1 должно быть 3 (0 от ID = A + 3 от ID = B), а tot_2 должно быть 6 (3 от ID = A + 3от ID = B).

Я - полный новичок в этих типах сегментации, поэтому любая помощь очень ценится.

Редактировать: я ожидаю, что tot_2> = tot_1, потому что lag_2 построен насобытия из Main, которые уходят в прошлое дольше, чем lag_1.

Ответы [ 3 ]

0 голосов
/ 22 ноября 2018

Рассмотрим вычисления для tot_1 и tot_2

Мой первый шаг - поиск шаблона, в котором lag_1> main (Это соответствует случаю, который вы упомянули, т. Е. Найти записи, где lag_1 = 1 за некоторое время до main = 1) и я называю все такие значения как 'grp_lag_1' и 'grp_lag_2'

После того, как я сгруппировал записи, я "копирую" значения, используя значение max () over (order by id, time1).

select *
      ,max(case when lag_1 > main then 'grp_lag_1' end) over(partition by id order by id,time1) as grp_1 
      ,max(case when lag_2 > main then 'grp_lag_2' end) over(partition by id order by id,time1) as grp_2 
  from t

Таким образом, я получаю результат следующим образом

+----+-------+------+-------+-------+-----------+-----------+
| id | time1 | main | lag_1 | lag_2 |   grp_1   |   grp_2   |
+----+-------+------+-------+-------+-----------+-----------+
| A  |    01 |    0 |     0 |     1 |           | grp_lag_2 |
| A  |    03 |    0 |     0 |     1 |           | grp_lag_2 |
| A  |    04 |    0 |     0 |     0 |           | grp_lag_2 |
| A  |    10 |    1 |     0 |     0 |           | grp_lag_2 |
| A  |    11 |    1 |     0 |     0 |           | grp_lag_2 |
| A  |    12 |    1 |     0 |     0 |           | grp_lag_2 |
| B  |    02 |    1 |     1 |     1 |           |           |
| B  |    04 |    0 |     1 |     1 | grp_lag_1 | grp_lag_2 |
| B  |    07 |    0 |     0 |     1 | grp_lag_1 | grp_lag_2 |
| B  |    10 |    1 |     0 |     0 | grp_lag_1 | grp_lag_2 |
| B  |    11 |    1 |     0 |     0 | grp_lag_1 | grp_lag_2 |
| B  |    12 |    1 |     0 |     0 | grp_lag_1 | grp_lag_2 |
+----+-------+------+-------+-------+-----------+-----------+

После этого, если бы я суммировал основные значения для grp_lag_1, я бы получил tot_1, а также суммируя grp + lag_2, я получил бы tot_2

 select sum(main) as tot_cnt
       ,sum(case when grp_1='grp_lag_1' then main end) as tot_1
       ,sum(case when grp_2='grp_lag_2' then main end) as tot_2
 from(      
select *
      ,max(case when lag_1 > main then 'grp_lag_1' end) over(partition by id order by id,time1) as grp_1 
      ,max(case when lag_2 > main then 'grp_lag_2' end) over(partition by id order by id,time1) as grp_2 
  from t
  )x


+---------+-------+-------+
| tot_cnt | tot_1 | tot_2 |
+---------+-------+-------+
|       7 |     3 |     6 |
+---------+-------+-------+

Демо https://dbfiddle.uk/?rdbms=sqlserver_2012&fiddle=c17be111dbc3c516afa2bc3dcd3c9e1c

0 голосов
/ 22 ноября 2018

Гораздо проще сделать это в шаге данных.Таким образом, вы можете проверить запуск нового идентификатора и сбросить флаг, чтобы переменные lag_x когда-либо были истинными.

data want ;
  set have end=eof;
  by id time ;
  tot + main ;
  if first.id then call missing(any_lag_1,any_lag_2);
  if any_lag_1 then tot_1 + main ;
  if any_lag_2 then tot_2 + main ;
  if eof then output;
  any_lag_1+lag_1;
  any_lag_2+lag_2;
  keep tot: ;
run;
0 голосов
/ 22 ноября 2018

Если я правильно понимаю, вы хотите эти суммы на один идентификатор.Ключ сравнивает минимальное значение идентификатора при различных обстоятельствах, а затем делает суммы.Это все условное агрегирование:

select sum(tot) as tot,
       sum(case when id_lag_1 < id_main then tot else 0 end) as tot_1,
       sum(case when id_lag_2 < id_main then tot else 0 end) as tot_2
from (select id, sum(main) as tot,
             min(case when main = 1 then id end) as id_main,
             min(case when lag_1 = 1 then id end) as id_lag_1,
             min(case when lag_2 = 1 then id end) as id_lag_2
      from t 
      group by id
     ) t;
...