Reputation: 607
Yesterday, I posted this question here: MSSQL 2008: Get last updated record by specific field
Gordon Linoff came up with a good solution and I was happy until today, when I realized I posted only half of the scenarios. Here's my new Question:
Given this table Content
:
ContentId lastUpdate FileId IrrelevantField
1 2014-01-01 00:00:00 File-A Dr. Hoo /* user uploads file*/
1 2014-01-02 00:00:00 File-B Dr. Hoo /* (!) user uploads new file */
1 2014-01-03 00:00:00 File-B Dr. Who /* user updates info */
2 2014-02-01 00:00:00 File-M 41 /* (!) user uploads file */
2 2014-02-02 00:00:00 File-M 42 /* user updates info */
3 2014-03-01 00:00:00 File-S Donald Duck /* user uploads file*/
Basically what I want is to get all rows that meet these conditions:
FileId
than it's previous row with the same ContentId
.FileId
has never changed, get the first ever submitted row (this applies in the example to ContentId
= 2 & 3.)IrrelevantField
triggers a row update. My goal is, to get the rows, when FileId
has changed.
The output would be following:
ContentId lastUpdate FileId IrrelevantField
1 2014-01-02 00:00:00 File-B Dr. Hoo
2 2014-02-01 00:00:00 File-M 41
3 2014-03-01 00:00:00 File-S Donald Duck
FileId
is never NULL
.
I have tried to add a OUTER APPLY
to Gordon Linoff's solution, so I can check, whether the FileId
is still the same as in the initial upload. But that has gotten me irrelevant Updates as well.
Upvotes: 0
Views: 107
Reputation: 32392
The query below uses lead
to create a derived table containing all rows where FileId has changed plus the 1st row. It then uses row_number()
to display either the 1st row if there are no changed FileIds for that ContentId (rn_asc = 1 and rn_desc = 1
) or all other rows where FileId has changed (rn_asc > 1
). If you just want the 1st row where FileId changed, use rn_asc = 2
instead of rn_asc > 1
.
select * from (
select * ,
row_number() over (partition by ContentId order by lastUpdate asc) rn_asc,
row_number() over (partition by ContentId order by lastUpdate desc) rn_desc
from (
select *
from (
select * ,
lead(FileId) over (partition by ContentId order by lastUpdate) previousFileId
from content c
) t1 where previousFileId <> FileId or previousFileId IS NULL
) t2
) t3 where (rn_asc = 1 and rn_desc = 1) or rn_asc > 1
Upvotes: 1
Reputation: 29
select ContentId, lastUpdate, FileId, IrrelevantField
from (
select row_number() over(partition by contentid order by lastupdate desc) LastChgsl, *
from
(
select
row_number() over(partition by fileid order by lastupdate) FileChgSl, *
from tablename
)V where FileChgSl = 1
)V1 where LastChgsl = 1
Upvotes: 0
Reputation: 69769
You were along the right lines changing it to an outer apply, then you can change the WHERE
clause slightly to allow for records where there is no previous record.
SELECT c.ContentID,
c.LastUpdate,
c.FileID,
c.IrrelevantField,
FileID2 = c2.FileID
FROM Content AS c
OUTER APPLY
( SELECT TOP 1 c2.FileID
FROM Content AS c2
WHERE c2.ContentID = c.ContentID
AND c2.LastUpdate < c.LastUpdate
ORDER BY c2.LastUpdate DESC
) AS c2
WHERE c.FileId != c2.FileId
OR c2.FileID IS NULL;
This means though that two records are returned for ContentID = 1 (and any other content with changes):
ContentID LastUpdate FileID IrrelevantField FileID2
1 2014-01-01 File-A Dr. Hoo NULL
1 2014-01-02 File-B Dr. Hoo File-A
2 2014-02-01 File-M 41 NULL
3 2014-03-01 File-S Donald Duck NULL
So you will need to use a further ranking function to limit this to only the latest record:
WITH CTE AS
( SELECT c.ContentID,
c.LastUpdate,
c.FileID,
c.IrrelevantField,
RowNumber = ROW_NUMBER() OVER(PARTITION BY c.ContentID ORDER BY c.LastUpdate DESC)
FROM Content AS c
OUTER APPLY
( SELECT TOP 1 c2.FileID
FROM Content AS c2
WHERE c2.ContentID = c.ContentID
AND c2.LastUpdate < c.LastUpdate
ORDER BY c2.LastUpdate DESC
) AS c2
WHERE c.FileId != c2.FileId
OR c2.FileID IS NULL
)
SELECT c.ContentID,
c.LastUpdate,
c.FileID,
c.IrrelevantField
FROM CTE AS c
WHERE RowNumber = 1;
Upvotes: 2
Reputation: 93724
Try this should work with all your scenario..
;with cte
as
(
select rank() over(partition by fileid,contentid order by lastupdate ) id, ContentId,lastUpdate,FileId,IrrelevantField from tablename
)
select ContentId,lastUpdate,FileId,IrrelevantField from(
select row_number() over(partition by contentid order by lastupdate desc) fstid, * from cte where id=1) a where fstid=1
Upvotes: 2