Reputation: 12141
I have a history table where it has all the values and if the value changed then it will be a new row. This is the example
name mod_date create_user_id is_active other_column
name1 2020-01-06 22:06:58+00 1 1 value1
name1 2020-01-06 22:07:01+00 2 1 value2
name2 2020-01-06 22:07:27+00 1 1 value2
Then after a query I want the result to be like this
name mod_date create_user_id is_active other_column
name1 2020-01-06 22:06:58+00 1 1 value1
2020-01-06 22:07:01+00 2 value2
name2 2020-01-06 22:07:27+00 1
The point I'm trying to make is it's easier to check which value got changed after a timestamp. The first row will always be there as it's default. Then the next row only shows create_user_id
and other_column
as it's changed from 1
to 2
and value1
to value2
is_active
would just be empty as it's never changed
I read about lag
and partition
but it seems like it only works for one column as I want to check every column
This is my example
select name
from (select h.*,
lag(name) over(partition by h.id order by h.mod_date) lag_name
from history h
) h
where name <> lag_name;
Upvotes: 0
Views: 710
Reputation: 1269773
You are going to have to list all the columns, but I think the simplest expression is probably:
select nullif(name, lag(name) over (order by mod_date)) as name,
mod_date,
nullif(create_user_id, lag(create_user_id) over (order by mod_date)) as create_user_id,
nullif(is_active, lag(is_active) over (order by mod_date)) as is_active,
nullif(other_column, lag(name) over (order by mod_date)) as other_column
from t
order by mod_date;
You can construct the query for any audit table using information_schema.columns
to get all the columns in the table.
This assumes that the column values are not NULL
-- and if they are, then your results are ambiguous anyway.
Upvotes: 2
Reputation: 246513
For each column, use an expression like
CASE WHEN lag(col) OVER (ORDER BY mod_date) IS DISTINCT FROM col THEN col END
That will produce NULL if the column value is the same for neighboring rows.
Upvotes: 1
Reputation: 271
If you don't have too many columns then you can use lag separately for previous value of each column. you can also use alias for window as you will be running this for same window in order to make query easy to read.
select name
from (select h.*,
lag(name) over main_window as lag_name,
lag(create_user_id) over main_window as prev_user_id,
lag(is_active) over main_window as prev_is_active,
lag(other_column) over main_window as prev_other_column
from history h
window main_window as (partition by h.id order by h.mod_date)
) h
where name <> lag_name
or create_user_id <> prev_user_id
or is_active <> prev_is_active
or other_column <> prev_other_column
Upvotes: 1