Как получить строки с последним обновлением столбца - PullRequest
2 голосов
/ 30 апреля 2019

Цель: для каждого «IDCONT» мне нужно получить «DAY_ID», где у меня есть последнее изменение / обновление «STATE_ID».

Пример:

with reftable as (
 select 1 as PROCESSID, 'A' as IDCONT, 'X' as STATEID, '10' AS DAY_ID union all
 select 2 as PROCESSID, 'A' as IDCONT, 'X' as STATEID, '11' AS DAY_ID union all
 select 3 as PROCESSID, 'A' as IDCONT, 'Y' as STATEID, '12' AS DAY_ID union all
 select 4 as PROCESSID, 'A' as IDCONT, 'Y' as STATEID, '13' AS DAY_ID union all

 select 1 as PROCESSID, 'B' as IDCONT, 'N' as STATEID, '14' AS DAY_ID union all
 select 2 as PROCESSID, 'B' as IDCONT, 'N' as STATEID, '15' AS DAY_ID union all
 select 3 as PROCESSID, 'B' as IDCONT, 'M' as STATEID, '16' AS DAY_ID union all

 select 1 as PROCESSID, 'C' as IDCONT, 'X' as STATEID, '11' AS DAY_ID union all
 select 2 as PROCESSID, 'C' as IDCONT, 'X' as STATEID, '18' AS DAY_ID union all
) ...

Ожидаетсярезультат:

PROCESSID   IDCONT   STATID   DAYID
3           A        Y        12
2           B        N        15
1           C        X        11        

Я решил проблему следующим образом:

...
SELECT IDCONT, STATEID, MIN(DAY_ID)
FROM REFTABLE 
WHERE (IDCONT, STATEID) IN (
   SELECT IDCONT, FIRST_VALUE(STATEID) OVER PARTITION BY IDCONT ORDER BY PROCESSID DESC) AS STATEID
   FROM REFTABLE
)

Но я хочу сделать то же самое без необходимости вызова таблицы во второй раз.

Thx!

Ответы [ 3 ]

1 голос
/ 30 апреля 2019

Было бы проще, если бы вам не нужно было возвращать IDCONT, чье STATEID не изменилось (это было бы C).Одна REFTABLE поездка может выглядеть так;посмотрим, принесет ли это пользу в реальности .

SQL> with reftable as (
  2   select 1 as PROCESSID, 'A' as IDCONT, 'X' as STATEID, '10' AS DAY_ID from dual union all
  3   select 2 as PROCESSID, 'A' as IDCONT, 'X' as STATEID, '11' AS DAY_ID from dual union all
  4   select 3 as PROCESSID, 'A' as IDCONT, 'Y' as STATEID, '12' AS DAY_ID from dual union all
  5   select 4 as PROCESSID, 'A' as IDCONT, 'Y' as STATEID, '13' AS DAY_ID from dual union all
  6   --
  7   select 1 as PROCESSID, 'B' as IDCONT, 'N' as STATEID, '14' AS DAY_ID from dual union all
  8   select 2 as PROCESSID, 'B' as IDCONT, 'N' as STATEID, '15' AS DAY_ID from dual union all
  9   select 3 as PROCESSID, 'B' as IDCONT, 'M' as STATEID, '16' AS DAY_ID from dual union all
 10   --
 11   select 1 as PROCESSID, 'C' as IDCONT, 'X' as STATEID, '11' AS DAY_ID from dual union all
 12   select 2 as PROCESSID, 'C' as IDCONT, 'X' as STATEID, '18' AS DAY_ID from dual
 13  ),
 14  inter as
 15    (select processid, idcont, stateid, day_id,
 16            case when nvl(lag(stateid) over
 17                            (partition by idcont order by processid  ), '?') <> stateid then
 18                      row_number() over (partition by idcont order by processid )
 19            end grp
 20     from reftable
 21    )
 22  select processid, idcont, stateid, day_id
 23  from inter i
 24  where grp = (select max(i1.grp)
 25              from inter i1
 26              where i1.idcont = i.idcont)
 27  order by idcont, processid;

 PROCESSID IDCONT     STATEID    DAY_ID
---------- ---------- ---------- ----------
         3 A          Y          12
         3 B          M          16
         1 C          X          11

SQL>
1 голос
/ 01 мая 2019

Вот один из методов:

select r.*
from (select r.*,
             lag(stateid) over (partition by idcont order by day_id) as prev_stateid,
             first_value(stateid) over (partition by idcont order by day_id desc) as last_stateid
      from reftable r
     ) r
where stateid = last_stateid and (prev_stateid is null or prev_stateid <> stateid);

Однако это не относится к случаю, когда состояние возвращается обратно в предыдущее состояние. Эта логика может быть добавлена ​​в случае необходимости.

0 голосов
/ 30 апреля 2019

Использование «FIRST_VALUE» дает вам изменение, но можете ли вы рассчитывать, что в таблице будет только одно изменение? Разве другие изменения не сделают это недействительным и не приведут ли к неверным данным?

Вместо этого я использовал функцию LAG, но она не возвращает IDCONT C, поскольку в ней не было изменений.

Использование CTE для захвата данных и последующего запроса к фильтру может быть быстрее (поскольку вы не можете поместить LAG или FIRST_VALUE в предложение where). Это предотвратит очередную поездку в базу данных.

CREATE TABLE REFTABLE
    ([PROCESSID] int, [IDCONT] varchar(1), [STATEID] varchar(1), [DAY_ID] int)
;

INSERT INTO REFTABLE
    ([PROCESSID], [IDCONT], [STATEID], [DAY_ID])
VALUES
    (1, 'A', 'X', 10),
    (2, 'A', 'X', 11),
    (3, 'A', 'Y', 12),
    (4, 'A', 'Y', 13),
    (1, 'B', 'N', 14),
    (2, 'B', 'N', 15),
    (3, 'B', 'M', 16),
    (1, 'C', 'X', 11),
    (2, 'C', 'X', 18)
;

with chgfound as (SELECT TOP 100 PERCENT PROCESSID, IDCONT, STATEID, DAY_ID, LAG(STATEID) OVER(PARTITION BY IDCONT ORDER BY IDCONT, PROCESSID) as LastState
from REFTABLE
order by IDCONT, PROCESSID
)
select * from chgfound where STATEID !=LastState

http://www.sqlfiddle.com/#!18/086134

Также только что заметил, что у вас есть тег Oracle. Я сделал это в SQL Server, но он должен быть очень похожим.

...