[英]Oracle SQL query : finding the last time a data was changed
我想檢索自上次更改特定列的數據以來經過的天數,例如:
TABLE_X包含
ID PDATE DATA1 DATA2
A 10-Jan-2013 5 10
A 9-Jan-2013 5 10
A 8-Jan-2013 5 11
A 7-Jan-2013 5 11
A 6-Jan-2013 14 12
A 5-Jan-2013 14 12
B 10-Jan-2013 3 15
B 9-Jan-2013 3 15
B 8-Jan-2013 9 15
B 7-Jan-2013 9 15
B 6-Jan-2013 14 15
B 5-Jan-2013 14 8
我出於示例目的簡化了表格。
結果應為:
ID DATA1_LASTUPDATE DATA2_LASTUPDATE
A 4 2
B 2 5
也就是說,-A最后更新的data1是4天前,-A最后更新的data2是2天前,-B最后更新的data1是2天前,-B最后更新的data2是5天前。
可以在下面使用查詢,但是如果我將其應用於具有大量記錄的真實表並添加2個以上數據列以查找其最新更新日期,則需要花費很長時間才能完成。 為此,我使用了LEAD功能。 還有其他替代方法可以加快查詢速度嗎?
with qdata1 as
(
select ID, pdate from
(
select a.*, row_number() over (partition by ID order by pdate desc) rnum from
(
select a.*,
lead(data1,1,0) over (partition by ID order by pdate desc) - data1 as data1_diff
from table_x a
) a
where data1_diff <> 0
)
where rnum=1
),
qdata2 as
(
select ID, pdate from
(
select a.*, row_number() over (partition by ID order by pdate desc) rnum from
(
select a.*,
lead(data2,1,0) over (partition by ID order by pdate desc) - data2 as data2_diff
from table_x a
) a
where data2_diff <> 0
)
where rnum=1
)
select a.ID,
trunc(sysdate) - b.pdate data1_lastupdate,
trunc(sysdate) - c.pdate data2_lastupdate,
from table_master a, qdata1 b, qdata2 c
where a.ID=b.ID(+) and a.ID=b.ID(+)
and a.ID=c.ID(+) and a.ID=c.ID(+)
非常感謝。
您的查詢沒有為我返回正確的結果,也許我錯過了一些東西,但是下面的查詢也得到了正確的結果(您可以檢查此SQLFiddle演示 ):
with ranked as (
select ID,
data1,
data2,
rank() over(partition by id order by pdate desc) r
from table_x
)
select id,
sum(DATA1_LASTUPDATE) DATA1_LASTUPDATE,
sum(DATA2_LASTUPDATE) DATA2_LASTUPDATE
from (
-- here I get when data1 was updated
select id,
count(1) DATA1_LASTUPDATE,
0 DATA2_LASTUPDATE
from ranked
start with r = 1
CONNECT BY (PRIOR data1 = data1)
and PRIOR r = r - 1
group by id
union
-- here I get when data2 was updated
select id,
0 DATA1_LASTUPDATE,
count(1) DATA0_LASTUPDATE
from ranked
start with r = 1
CONNECT BY (PRIOR data2 = data2)
and PRIOR r = r - 1
group by id
)
group by id
您可以通過同時進行兩個滯后(或超前)計算來避免表和聯接上的多個匹配項:
with t as (
select id, pdate, data1, data2,
lag(data1) over (partition by id order by pdate) as lag_data1,
lag(data2) over (partition by id order by pdate) as lag_data2
from table_x
),
u as (
select t.*,
case when lag_data1 is null or lag_data1 != data1 then pdate end as pdate1,
case when lag_data2 is null or lag_data2 != data2 then pdate end as pdate2
from t
),
v as (
select u.*,
rank() over (partition by id order by pdate1 desc nulls last) as rn1,
rank() over (partition by id order by pdate2 desc nulls last) as rn2
from u
)
select v.id,
max(trunc(sysdate) - (case when rn1 = 1 then pdate1 end))
as data1_last_update,
max(trunc(sysdate) - (case when rn2 = 1 then pdate2 end))
as data2_last_update
from v
group by v.id
order by v.id;
我假設您的意思是您的數據適用於Jun-2014
,而不是Jan-2013
; 並且您正在將最新更改日期與當前日期進行比較。 調整數據以使用10-Jun-2014
等,得出的結果是:
ID DATA1_LAST_UPDATE DATA2_LAST_UPDATE
-- ----------------- -----------------
A 4 2
B 2 5
第一個CTE( t
)獲取實際的表數據,並使用lag(這與按降序排列的lead相同)添加了兩個額外的列,每個數據列一個。
第二個CTE( u
)添加了兩個日期列,這些日期列僅在更改數據列時設置(或在第一次設置時,以防萬一它們從未更改過)。 因此,如果一行的data1
與上一行相同,則其pdate1
將為空白。 您可以通過重復計算滯后時間來合並前兩者,但我將其分開以使其更加清晰。
第三CTE( v
)為這些pdate
列分配排名,以使最新的列第一。
最終查詢將計算出從當前日期到每個數據列排名最高(即最新)的更改之間的差異。
SQL Fiddle包括所有CTE單獨運行,因此您可以查看它們的運行情況。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.