开发者

How can I find duplicate consecutive values in this table?

开发者 https://www.devze.com 2023-01-08 18:26 出处:网络
Say I have a table which I query like so: select date, value from mytable order by date and this gives me results:

Say I have a table which I query like so:

select date, value from mytable order by date

and this gives me results:

date                  value
02/26/2009 14:03:39   1                
02/26/2009 14:10:52   2          (a)
02/26/2009 14:27:49   2          (b)
02/26/2009 14:34:33   3
02/26/2009 14:4开发者_运维技巧8:29   2          (c)
02/26/2009 14:55:17   3
02/26/2009 14:59:28   4

I'm interested in the rows of this result set where the value is the same as the one in the previous or next row, like row b which has value=2 the same as row (a). I don't care about rows like row (c) which has value=2 but does not come directly after a row with value=2. How can I query the table to give me all rows like (a) and (b) only? This is on Oracle, if it matters.


Use the lead and lag analytic functions.

create table t3 (d number, v number);
insert into t3(d, v) values(1, 1);
insert into t3(d, v) values(2, 2);
insert into t3(d, v) values(3, 2);
insert into t3(d, v) values(4, 3);
insert into t3(d, v) values(5, 2);
insert into t3(d, v) values(6, 3);
insert into t3(d, v) values(7, 4);

select d, v, case when v in (prev, next) then '*' end match, prev, next from (
  select
    d,
    v,
    lag(v, 1) over (order by d) prev,
    lead(v, 1) over (order by d) next
  from
    t3
)
order by
  d
;

Matching neighbours are marked with * in the match column,

How can I find duplicate consecutive values in this table?


This is a simplified version of @Bob Jarvis' answer, the main difference being the use of just one subquery instead of four,

with f as (select row_number() over(order by d) rn, d, v from t3)
select
  a.d, a.v,
  case when a.v in (prev.v, next.v) then '*' end match
from
  f a
    left join
  f prev
    on a.rn = prev.rn + 1
    left join
  f next
    on a.rn = next.rn - 1
order by a.d
;


As @Janek Bogucki has pointed out LEAD and LAG are probably the easiest way to accomplish this - but just for fun let's try to do it by using only basic join operations:

SELECT mydate, VALUE FROM
  (SELECT a.mydate, a.value,
          CASE WHEN a.value = b.value THEN '*' ELSE NULL END AS flag1,
          CASE WHEN a.value = c.value THEN '*' ELSE NULL END AS flag2
     FROM
       (SELECT ROWNUM AS outer_rownum, mydate, VALUE
         FROM mytable
         ORDER BY mydate) a
     LEFT OUTER JOIN
       (select ROWNUM-1 AS inner_rownum, mydate, VALUE
         from mytable
         order by myDATE) b
       ON b.inner_rownum = a.outer_rownum
     LEFT OUTER JOIN
       (select ROWNUM+1 AS inner_rownum, mydate, VALUE
         from mytable
         order by myDATE) c
       ON c.inner_rownum = a.outer_rownum
     ORDER BY a.mydate)
  WHERE flag1 = '*' OR
        flag2 = '*';

Share and enjoy.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号