Как показать события с 2 или менее минутами между ними от одного и того же пользователя? - PullRequest
1 голос
/ 29 октября 2019

Представьте, что у меня есть таблица с событиями в ней:

id user date                 amount
1  1    29.10.2019 16:35:01  10
2  1    29.10.2019 16:35:29  15
3  2    29.10.2019 16:48:29  12
4  2    29.10.2019 16:55:44  14

Я хотел бы видеть все события, такие как 1 и 2 (между ними менее 2 минут; они от одного пользователя)заказано пользователем и датой.

Что я уже пробовал:

SELECT *
FROM (
SELECT id, user, amount, 
datediff(MINUTE, lag(date) OVER (ORDER BY to_qw, d_date), date) 
AS since_past_one
FROM events
) e
where since_past_one <> 0
and since_past_one <= 2
order by user, date

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

Что я хотел бы видеть в результате это:

id user date                 amount
1  1    29.10.2019 16:35:01  10
2  1    29.10.2019 16:35:29  15

Ответы [ 2 ]

2 голосов
/ 29 октября 2019

Я думаю, вам не хватает аргумента partition by

datediff(MINUTE, lag(date) OVER (PARTITION BY user ORDER BY to_qw, d_date), date)
1 голос
/ 30 октября 2019

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

WITH input(id,usr,ts,amount) AS ( 
          SELECT 1,1,TIMESTAMP '2019-10-29 16:35:00.0',10.00 
UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:01.5',10.26 
UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:03.0',10.52 
UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:04.5',10.78 
UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:06.0',11.03 
UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:07.5',11.29 

UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:09.0',11.55 
UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:10.5',11.81 
UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:18.0',13.10 
UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:19.5',13.36 
UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:21.0',13.62 

UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:27.0',14.66 
UNION ALL SELECT 1,1,TIMESTAMP '2019-10-29 16:35:28.5',14.91 

UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:00.0',12.00 
UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:01.5',12.10 
UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:03.0',12.21 
UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:04.5',12.31 

UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:12.0',12.83 
UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:13.5',12.93 
UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:15.0',13.03 
UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:16.5',13.14 

UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:24.0',13.66 
UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:25.5',13.76 
UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:27.0',13.86 
UNION ALL SELECT 3,2,TIMESTAMP '2019-10-29 16:35:28.5',13.97 
) 
SELECT * FROM input; 

Дает мне:

 id | usr |          ts           | amount                                  
----+-----+-----------------------+--------
  1 |   1 | 2019-10-29 16:35:00   |  10.00
  1 |   1 | 2019-10-29 16:35:01.5 |  10.26
  1 |   1 | 2019-10-29 16:35:03   |  10.52
  1 |   1 | 2019-10-29 16:35:04.5 |  10.78
  1 |   1 | 2019-10-29 16:35:06   |  11.03
  1 |   1 | 2019-10-29 16:35:07.5 |  11.29
  1 |   1 | 2019-10-29 16:35:09   |  11.55
  1 |   1 | 2019-10-29 16:35:10.5 |  11.81
  1 |   1 | 2019-10-29 16:35:18   |  13.10
  1 |   1 | 2019-10-29 16:35:19.5 |  13.36
  1 |   1 | 2019-10-29 16:35:21   |  13.62
  1 |   1 | 2019-10-29 16:35:27   |  14.66
  1 |   1 | 2019-10-29 16:35:28.5 |  14.91
  3 |   2 | 2019-10-29 16:35:00   |  12.00
  3 |   2 | 2019-10-29 16:35:01.5 |  12.10
  3 |   2 | 2019-10-29 16:35:03   |  12.21
  3 |   2 | 2019-10-29 16:35:04.5 |  12.31
  3 |   2 | 2019-10-29 16:35:12   |  12.83
  3 |   2 | 2019-10-29 16:35:13.5 |  12.93
  3 |   2 | 2019-10-29 16:35:15   |  13.03
  3 |   2 | 2019-10-29 16:35:16.5 |  13.14
  3 |   2 | 2019-10-29 16:35:24   |  13.66
  3 |   2 | 2019-10-29 16:35:25.5 |  13.76
  3 |   2 | 2019-10-29 16:35:27   |  13.86
  3 |   2 | 2019-10-29 16:35:28.5 |  13.97

Таким образом, мы хотим, чтобы начальная строка каждой группы строк была не дальше, чем 2 секунды, для одного и того же пользователя. Vertica может идентифицировать такие группы. Этот процесс обычно называется «сессионизация». У нас есть функция Vertica OLAP CONDITIONAL_TRUE_EVENT (), которая делает это для нас: она начинается с 0 для каждой PARTITION и увеличивается на 1 каждый раз, когда логическое выражение в скобках истинно.

SELECT                                                                      
  CONDITIONAL_TRUE_EVENT(ts - LAG(ts) > INTERVAL '2000 msec') OVER(
    PARTITION BY usr ORDER BY ts
  ) AS session_id
, *
FROM input

дает нам:

 session_id | id | usr |          ts           | amount 
------------+----+-----+-----------------------+--------
          0 |  1 |   1 | 2019-10-29 16:35:00   |  10.00
          0 |  1 |   1 | 2019-10-29 16:35:01.5 |  10.26
          0 |  1 |   1 | 2019-10-29 16:35:03   |  10.52
          0 |  1 |   1 | 2019-10-29 16:35:04.5 |  10.78
          0 |  1 |   1 | 2019-10-29 16:35:06   |  11.03
          0 |  1 |   1 | 2019-10-29 16:35:07.5 |  11.29
          0 |  1 |   1 | 2019-10-29 16:35:09   |  11.55
          0 |  1 |   1 | 2019-10-29 16:35:10.5 |  11.81
          1 |  1 |   1 | 2019-10-29 16:35:18   |  13.10
          1 |  1 |   1 | 2019-10-29 16:35:19.5 |  13.36
          1 |  1 |   1 | 2019-10-29 16:35:21   |  13.62
          2 |  1 |   1 | 2019-10-29 16:35:27   |  14.66
          2 |  1 |   1 | 2019-10-29 16:35:28.5 |  14.91
          0 |  3 |   2 | 2019-10-29 16:35:00   |  12.00
          0 |  3 |   2 | 2019-10-29 16:35:01.5 |  12.10
          0 |  3 |   2 | 2019-10-29 16:35:03   |  12.21
          0 |  3 |   2 | 2019-10-29 16:35:04.5 |  12.31
          1 |  3 |   2 | 2019-10-29 16:35:12   |  12.83
          1 |  3 |   2 | 2019-10-29 16:35:13.5 |  12.93
          1 |  3 |   2 | 2019-10-29 16:35:15   |  13.03
          1 |  3 |   2 | 2019-10-29 16:35:16.5 |  13.14
          2 |  3 |   2 | 2019-10-29 16:35:24   |  13.66
          2 |  3 |   2 | 2019-10-29 16:35:25.5 |  13.76
          2 |  3 |   2 | 2019-10-29 16:35:27   |  13.86
          2 |  3 |   2 | 2019-10-29 16:35:28.5 |  13.97                     

И, чтобы получить первый ряд каждой группы, мы используем специфическое для Vertica аналитическое предложение LIMIT :

WITH
with_sess_id AS (
  SELECT
    CONDITIONAL_TRUE_EVENT(ts - LAG(ts) > INTERVAL '2000 msec') OVER(
      PARTITION BY usr ORDER BY ts
    ) AS session_id
  , *
  FROM input
)
SELECT 
  id
, usr
, ts
, amount
FROM with_sess_id
LIMIT 1 OVER(PARTITION BY usr,session_id ORDER BY ts);

Вы получаете:

 id | usr |         ts          | amount 
----+-----+---------------------+--------
  1 |   1 | 2019-10-29 16:35:00 |  10.00
  1 |   1 | 2019-10-29 16:35:18 |  13.10
  1 |   1 | 2019-10-29 16:35:27 |  14.66
  3 |   2 | 2019-10-29 16:35:00 |  12.00
  3 |   2 | 2019-10-29 16:35:12 |  12.83
  3 |   2 | 2019-10-29 16:35:24 |  13.66

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

WITH
with_sess_id AS (
  SELECT
    CONDITIONAL_TRUE_EVENT(ts - LAG(ts) > INTERVAL '2000 msec') OVER(
      PARTITION BY usr ORDER BY ts
    ) AS session_id
  , *
  FROM input
)
,
session_summary AS (
  SELECT
    usr
  , session_id
  , COUNT(*) AS rows_per_session
  , AVG(amount) AS avg_amt_per_session
  FROM with_sess_id
  GROUP BY 1,2
  -- this returns:
  --  usr | session_id | rows_per_session | avg_amt_per_session 
  -- -----+------------+------------------+---------------------
  --    1 |          0 |                8 |              10.905
  --    1 |          1 |                3 |               13.36
  --    1 |          2 |                2 |              14.785
  --    2 |          0 |                4 |              12.155
  --    2 |          1 |                4 |             12.9825
  --    2 |          2 |                4 |             13.8125
)
SELECT
  AVG(rows_per_session) AS avg_rows_per_session
, AVG(avg_amt_per_session) AS avg_avg_amount_per_session
FROM session_summary;
avg_rows_per_session | avg_avg_amount_per_session
 ----------------------+----------------------------
      4.16666666666667 |                         13                                                                                                                            
...