Как найти повторяющиеся последовательные значения в этой таблице? - PullRequest
7 голосов
/ 21 июля 2010

Скажем, у меня есть таблица, которую я запрашиваю примерно так:

select date, value from mytable order by date

, и это дает мне результаты:

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:48:29   2          (c)
02/26/2009 14:55:17   3
02/26/2009 14:59:28   4

Меня интересуют строки этого набора результатов, гдезначение совпадает со значением в предыдущей или следующей строке, как строка b, значение которой равно 2, так же, как строка a.Меня не волнуют строки типа строки c, значение которой равно 2, но не идет сразу после строки со значением = 2.Как я могу запросить таблицу, чтобы получить все строки, такие как только a и b?Это на Oracle, если это имеет значение.

Ответы [ 3 ]

11 голосов
/ 21 июля 2010

Используйте аналитические функции опережения и отставания.

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
;

Соответствующие соседи отмечены * в столбце соответствия,

альтернативный текст http://i28.tinypic.com/2drrojt.png

3 голосов
/ 21 июля 2010

Это упрощенная версия ответа @Bob Jarvis, основное отличие в которой заключается в использовании только одного подзапроса вместо четырех,

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
;
1 голос
/ 21 июля 2010

Как отметил @Janek Bogucki, LEAD и LAG - это, вероятно, самый простой способ сделать это - но для интереса, давайте попробуем сделать это, используя только основные операции соединения:

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 = '*';

Делись и наслаждайся.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...