如何获取列上最后更新的行

How to get rows with last update on column

目标: 对于每个 "IDCONT",我需要在 "STATE_ID" 上获得最后一个 change/update 的 "DAY_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
)

但我想做同样的事情而不需要第二次调用 table。

谢谢!

使用 "FIRST_VALUE" 确实给了你零钱,但你能相信 table 中只有一个零钱吗?其他更改不会使此无效并导致错误数据吗?

我改用了 LAG 函数,但它没有 return IDCONT C,因为它没有发生变化。

使用 CTE 获取数据然后使用查询进行过滤可能会更快(因为您不能在 where 子句中放置 LAG 或 FIRST_VALUE)。这将防止再次访问数据库。

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 服务器上做了这个,但它必须非常接近相同。

如果你不需要 return IDCONTSTATEID 没有改变(那就是 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>

这是一种方法:

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);

但是,这不处理状态变回先前状态的情况。如有必要,可以添加该逻辑。