如何获取列上最后更新的行
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 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>
这是一种方法:
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);
但是,这不处理状态变回先前状态的情况。如有必要,可以添加该逻辑。
目标: 对于每个 "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 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>
这是一种方法:
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);
但是,这不处理状态变回先前状态的情况。如有必要,可以添加该逻辑。