Redshift или ЛЮБОЙ SQL: обновите таблицу с помощью похожих строк, время которых не превышает 30 секунд - PullRequest
0 голосов
/ 11 июня 2018

У меня есть эта таблица:

prod | customer |   city  | num  |       time         | isextra
-----+----------+---------+------+--------------------+-------
 1   | Jim      |  Venice |  5   |2015-08-27 1:10:00  | 0
 1   | Jim      |  Venice |  5   |2015-08-27 1:10:15  | 0
 1   | Jim      |  Venice |  5   |2015-08-27 1:10:28  | 0
 4   | Jane     |  Vienna |  8   |2018-06-04 2:20:43  | 0
 4   | Jane     |  Vienna |  8   |2018-06-04 2:20:43  | 0
 4   | Jane     |  Vienna |  8   |2018-06-04 2:20:49  | 0
 4   | Jane     |  Vienna |  8   |2018-06-04 2:30:55  | 0
 7   | Jack     | Vilnius |  4   |2015-09-15 2:20:55  | 0
 7   | Jake     |   Vigo  |  9   |2018-01-01 10:20:05 | 0
 7   | Jake     |   Vigo  |  2   |2018-01-01 10:20:25 | 0

Теперь возьмем все строки, которые похожи по prod, customer, city, num, а затем по любой строке, время которой находится в пределах 30 секунд от первой в группе,его поле 'isextra' ОБНОВЛЕНО до 1, и это будет результат:

prod | customer |   city  | num  |       time         | isextra
-----+----------+---------+------+--------------------+-------
 1   | Jim      |  Venice |  5   |2015-08-27 1:10:00  | 0
 1   | Jim      |  Venice |  5   |2015-08-27 1:10:15  | 1
 1   | Jim      |  Venice |  5   |2015-08-27 1:10:28  | 1
 4   | Jane     |  Vienna |  8   |2018-06-04 2:20:43  | 0
 4   | Jane     |  Vienna |  8   |2018-06-04 2:20:43  | 1
 4   | Jane     |  Vienna |  8   |2018-06-04 2:20:49  | 1
 4   | Jane     |  Vienna |  8   |2018-06-04 2:30:55  | 0
 7   | Jack     | Vilnius |  4   |2015-09-15 2:20:55  | 0
 7   | Jake     |   Vigo  |  9   |2018-01-01 10:20:05 | 0
 7   | Jake     |   Vigo  |  2   |2018-01-01 10:20:25 | 0

Вот таблица и данные:

create table mytable (prod int, customer varchar, city varchar, num int, time timestamp, isextra smallint);


insert into mytable values (1, 'Jim', 'Venice', 5, '2015-08-27 1:10:00',  0);
insert into mytable values (1, 'Jim', 'Venice',  5, '2015-08-27 1:10:15',  0);
insert into mytable values (1, 'Jim', 'Venice',  5, '2015-08-27 1:10:28',  0);
insert into mytable values (4, 'Jane',  'Vienna',   8,   '2018-06-04 2:20:43',   0);
insert into mytable values (4, 'Jane',  'Vienna',   8,   '2018-06-04 2:20:43',   0);
insert into mytable values (4, 'Jane',  'Vienna',   8,   '2018-06-04 2:20:49',   0);
insert into mytable values (4, 'Jane',  'Vienna',   8,   '2018-06-04 2:30:55',   0);
insert into mytable values (7, 'Jack', 'Vilnius',   4,   '2015-09-15 2:20:55',   0);
insert into mytable values (7, 'Jake',   'Vigo',    9,   '2018-01-01 10:20:05',  0);
insert into mytable values (7, 'Jake',   'Vigo',    2,   '2018-01-01 10:20:25',  0);

Все, что у меня есть, это:1010 *

UPDATE mytable
SET isextra = 1
FROM ( 
  select *, 
  row_number() over (partition by prod, customer, city, num order by time asc)
    as t from mytable
) AS sequence

Застрял здесь ...

Любые идеи приветствуются, спасибо!

Ответы [ 2 ]

0 голосов
/ 11 июня 2018

Я бы написал select с использованием оконных функций как:

select t.*,
       (case when time > min_time and
                  time < dateadd(minute, 30, min_time)
             then 1 else 0 
        end) as is_extra
from (select t.*,
             min(time) over (partition by prod, customer, city, num) as min_time
      from t
     ) t;

Единственная проблема - дублирование времени в одной строке.Мы можем исправить это следующим образом:

select t.*,
       (case when time > min_time and time < dateadd(minute, 30, min_time) and seqnum <> 0
             then 1 else 0 
        end) as is_extra
from (select t.*,
             min(time) over (partition by prod, customer, city, num) as min_time,
             row_number() over (partition by prod, customer, city, num order by time) as seqnum
      from t
     ) t;

К сожалению, превратить это в update действительно сложно из-за точных повторяющихся строк в вашем примере.

Если у вас есть уникальный идентификатор накаждый ряд, то вы можете превратить это в update:

update t
    set t.is_extra = tt.new_is_extra
    from (select t.*,
                 (case when time > min_time and time < dateadd(minute, 30, min_time) and seqnum <> 0
             then 1 else 0 
                  end) as new_is_extra
          from (select t.*,
                       min(time) over (partition by prod, customer, city, num) as min_time,
                       row_number() over (partition by prod, customer, city, num order by time) as seqnum
                from t
                ) t
         ) tt
     where t.id = tt.id
0 голосов
/ 11 июня 2018

Не знаю, вылетает ли это в PostgreSQL 8.0 (красное смещение), но стоит попробовать:

update mytable a
  set isextra = 1 
  from (
    select prod, customer, city, num, min(time) as mintime
      from mytable 
      group by prod, customer, city, num
  ) b
  where a.prod = b.prod
    and a.customer = b.customer
    and a.city = b.city
    and a.num = b.num
    and a.time <= b.mintime + interval '30 seconds'
    and a.time <> b.mintime;

Результат:

prod  customer  city     num  time                   isextra
----  --------  ----     ---  ---------------------  -------
1     Jim       Venice   5    2015-08-27 01:10:00.0  0
1     Jim       Venice   5    2015-08-27 01:10:15.0  1
1     Jim       Venice   5    2015-08-27 01:10:28.0  1
4     Jane      Vienna   8    2018-06-04 02:20:43.0  0
4     Jane      Vienna   8    2018-06-04 02:20:43.0  0
4     Jane      Vienna   8    2018-06-04 02:20:49.0  1
4     Jane      Vienna   8    2018-06-04 02:30:55.0  0
7     Jack      Vilnius  4    2015-09-15 02:20:55.0  0
7     Jake      Vigo     2    2018-01-01 10:20:25.0  0
7     Jake      Vigo     9    2018-01-01 10:20:05.0  0
...