Search code examples
sqlpostgresqlsubquerycasecoalesce

How to use sub queries with case when or coalesce functions


I have a log table in which a new time stamp is added to the column ts as soon as a change is made, at the same time the time stamp of the last change is written to the column prevts. What I would like to know is the newest update date of a certain field, if a certain field, like in this example the last name, was never updated and is the same since it was created, I would like to know the creation date.

id ts prevts operation firstname middlename lastname
1 2023-02-03T14 2023-01-17T08 update John S Doe
1 2023-01-17T08 2022-10-20T03 update John S Doe
1 2022-10-20T03 2022-10-06T14 update Johnny S Doe
1 2022-10-06T14 create Johnny Doe

I am able to retrieve the update timestamps for single values like firstname and middle name (like in the code example below) but this does not work for lastname because this condition curr.firstname!=prev.firstname or prev.firstname is null is not fulfilled. In such cases I would like to know the creation date.

SELECT 
DISTINCT ON (curr.id)
curr.id,
prev.ts   AS curr_firstname_ts,
curr.prevts
FROM log_table curr
JOIN log_table prev 
  ON curr.prevts=prev.ts AND prev.id=curr.id
WHERE curr.firstname is not null
AND curr.firstname!='' 
AND (curr.firstname!=prev.firstname or prev.firstname is null)
ORDER BY curr.kolid, curr.prevts DESC NULLS LAST, prev.ts;

What I get as a result with this query is:

id curr_firstname_ts
1 2023-01-17T08

What I would like to get is something like this:

id curr_firstname_ts curr_middlename_ts curr_lastname_ts
1 2023-01-17T08 2022-10-20T03 2022-10-06T14

Solution

  • select * from log1;
    

    Original data set

    id currts prevts ops firstname lastname middlename
    1 2023-02-01 13:00:00 create Johnny Doe
    1 2023-02-02 13:00:00 2023-02-01 13:00:00 update Johnny Doe S
    1 2023-02-03 13:00:00 2023-02-02 13:00:00 update John Doe S
    1 2023-02-04 13:00:00 2023-02-03 13:00:00 update John Doe S
    2 2023-02-01 13:00:00 create Mike Smith J

    (5 rows)

    Run the query using window functions:

    with a as (
        select id, currts,prevts, ops,
        firstname,lastname,middlename, 
        max(currts) over (partition by id) as maxts,
        min(currts) over (partition by id, firstname) as      minfirstnamets ,
        min(currts) over (partition by id, lastname) as minlastnamets ,
        min(currts) over (partition by id, middlename) as minmiddlenamets 
        from log1
    )
    select * from a where currts = maxts;
    

    Result data set

    id currts prevts ops firstname lastname middlename
    1 2023-02-01 13:00:00 create Johnny Doe
    1 2023-02-02 13:00:00 2023-02-01 13:00:00 update Johnny Doe S
    1 2023-02-03 13:00:00 2023-02-02 13:00:00 update John Doe S
    1 2023-02-04 13:00:00 2023-02-03 13:00:00 update John Doe S
    2 2023-02-01 13:00:00 create Mike Smith J