Мин. / Макс. Отметка времени медленно меняющегося измерения - PullRequest
0 голосов
/ 01 января 2019

У меня есть мысли по поводу запроса SQL (Redshift), который мне нужен.Итак, в основном, у меня есть следующая таблица

userid | timestamp           | fruit
  1    | 2018-12-10T14:46:50 | banana 
  1    | 2018-12-10T15:46:50 | banana
  1    | 2018-12-10T16:46:50 | apple
  1    | 2018-12-10T17:46:50 | banana

Можно ли придумать новую таблицу со следующей информацией

userid | start               | end                 | fruit
  1    | 2018-12-10T14:46:50 | 2018-12-10T16:46:50 | banana 
  1    | 2018-12-10T16:46:50 | 2018-12-10T17:46:50 | apple
  1    | 2018-12-10T17:46:50 |                     | banana

, показывающей диапазон времени, в котором пользователь хранил своивыбор любимых фруктов.

Заранее спасибо!

D

Ответы [ 2 ]

0 голосов
/ 01 января 2019

Это типичная gaps and islands проблема, аналитические функции lag и lead могут использоваться следующим образом:

with fruits(userid,timestamp,fruit) as (
values 
  (1,'2018-12-10T14:46:50','banana'), 
  (1,'2018-12-10T15:46:50','banana'),
  (1,'2018-12-10T16:46:50','apple'),
  (1,'2018-12-10T17:46:50','banana')    
)
 select userid, min(timestamp) as start, max(ld) as end, fruit
   from
   (
        select f2.*,
               sum(case when lg = fruit then 0 else 1 end) over
                         (partition by userid, fruit order by timestamp) sm
          from
          (
             select f1.*,
                    lead(timestamp) over (partition by userid order by timestamp) as ld,
                    lag(fruit) over (partition by userid order by timestamp) as lg
               from fruits f1
          ) f2
   ) f    
  group by userid, fruit, sm
  order by start;

userid     start                    end           fruit
------- ------------------- -------------------   ------
  1     2018-12-10T14:46:50 2018-12-10T16:46:50   banana
  1     2018-12-10T16:46:50 2018-12-10T17:46:50   apple
  1     2018-12-10T17:46:50         NULL          banana

Rextester Demo

0 голосов
/ 01 января 2019

Схема (MySQL v8.0)

CREATE TABLE t1 (
  `userid` INTEGER,
  `timestamp` VARCHAR(19),
  `fruit` VARCHAR(6)
);

INSERT INTO t1
  (`userid`, `timestamp`, `fruit`)
VALUES
  ('1', '2018-12-10T14:46:50', 'banana'),
  ('1', '2018-12-10T15:46:50', 'banana'),
  ('1', '2018-12-10T16:46:50', 'apple'),
  ('1', '2018-12-10T17:46:50', 'banana');

Запрос № 1

Простой подход, если вы не возражаете против несколькихзаписи для последовательных фруктов

select userid, fruit, timestamp `start`, 
  lead(timestamp) over (order by timestamp) `end`
from t1;

| userid | fruit  | start               | end                 |
| ------ | ------ | ------------------- | ------------------- |
| 1      | banana | 2018-12-10T14:46:50 | 2018-12-10T15:46:50 |
| 1      | banana | 2018-12-10T15:46:50 | 2018-12-10T16:46:50 |
| 1      | apple  | 2018-12-10T16:46:50 | 2018-12-10T17:46:50 |
| 1      | banana | 2018-12-10T17:46:50 |                     |

Или Запрос № 2

SELECT t2.* 
FROM   ( 
                SELECT   userid, 
                         fruit, 
                         timestamp `tstart`, 
                         CASE 
                                  WHEN fruit = Lead(fruit) over(ORDER BY timestamp) THEN lead(timestamp, 2) over ( ORDER BY timestamp)
                                  ELSE lead(timestamp, 1) over ( ORDER BY timestamp) 
                         end `tend`, 
                         CASE 
                                  WHEN fruit = lag(fruit) over (ORDER BY timestamp) THEN 1 
                                  ELSE 0 
                         end del 
                FROM     t1 ) t2 
WHERE  del = 0;


| userid | fruit  | tstart              | tend                | del |
| ------ | ------ | ------------------- | ------------------- | --- |
| 1      | banana | 2018-12-10T14:46:50 | 2018-12-10T16:46:50 | 0   |
| 1      | apple  | 2018-12-10T16:46:50 | 2018-12-10T17:46:50 | 0   |
| 1      | banana | 2018-12-10T17:46:50 |                     | 0   |

Просмотр в БД Fiddle

...