简体   繁体   English

是否有 SQL 仅显示所有列的前一行更改的值?

[英]Is there an SQL to show only the value that got changed from the previous row for all columns?

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然后下一行只显示create_user_idother_column因为它从1更改为2 ,将value1更改为value2

is_active would just be empty as it's never changed is_active将是空的,因为它从未改变

I read about lag and partition but it seems like it only works for one column as I want to check every column我读过lagpartition但它似乎只适用于一列,因为我想检查每一列

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;

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

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.如果相邻行的列值相同,则将产生 NULL。

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.您可以使用information_schema.columns为任何审计表构造查询以获取表中的所有列。

This assumes that the column values are not NULL -- and if they are, then your results are ambiguous anyway.这假设列值不是NULL —— 如果它们是,那么你的结果无论如何都是不明确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM