Reputation: 113
There is a table that stores account data for everyday. I want to find out the difference in data between today and yesterday. The query for table creation and insert statements are below :
CREATE TABLE daily_account_data (id varchar(6), Name varchar (20), DS_DW_Id varchar(4), flag_1 varchar(5), flag_2 varchar(5), Insert_date date );
INSERT INTO daily_account_data VALUES('A01R11', 'Gene Graham', 'PT12', 'TRUE', 'FALSE', '2023-06-01');
INSERT INTO daily_account_data VALUES('A01R16', 'Molly Ringwald', 'PT15', 'TRUE', 'TRUE', '2023-06-01');
INSERT INTO daily_account_data VALUES('A01R19', 'John Doe', 'PT24', 'FALSE','TRUE', '2023-06-01');
INSERT INTO daily_account_data VALUES('A01R34', 'Jane Doe', 'PT26', 'TRUE', 'FALSE', '2023-06-01');
INSERT INTO daily_account_data VALUES('A01R11', 'Gene Wilder', 'PT12', 'TRUE', 'FALSE', '2023-06-02');
INSERT INTO daily_account_data VALUES('A01R16', 'Molly Ringwald', 'PT15', 'TRUE', 'TRUE', '2023-06-02');
INSERT INTO daily_account_data VALUES('A01R19', 'John Doe', 'PT24', 'TRUE', 'TRUE', '2023-06-02');
INSERT INTO daily_account_data VALUES('A01R34', 'Jane Doe', 'PT26', 'TRUE', 'FALSE', '2023-06-02');
I have the query to find the difference in the data of the 2 days.
SELECT id, name, DS_DW_Id, flag_1, flag_2 FROM daily_account_data WHERE Insert_date = '2023-06-02'
EXCEPT
SELECT id, name, DS_DW_Id, flag_1, flag_2 FROM daily_account_data WHERE Insert_date = '2023-06-01';
But I can't figure out to get the data in the pseudo column. The last column is changed data. On 1st June data the name of the id A01R11 is Gene Graham and on 2nd it is Gene Wilder. The pseudo column should display "Name change".
Similarly for id A01R19 (John Doe) the value for flag_1 has changed to TRUE. The pseudo column should display "flag_1 change".
The output should look like :
id | Name | DS_DW_Id | flag_1 | flag_2 | Data Change |
---|---|---|---|---|---|
A01R11 | Gene Wilder | PT12 | TRUE | FALSE | Name Change |
A01R19 | John Doe | PT24 | TRUE | TRUE | flag_1 Change |
Upvotes: 2
Views: 280
Reputation: 21
Added test rows to see what if everything changed...
/*
INSERT INTO daily_account_data VALUES('A01R99', 'Bruce', 'PT71', 'TRUE', 'FALSE', '2023-06-01');
INSERT INTO daily_account_data VALUES('A01R99', 'Caitlyn', 'PT17', 'FALSE', 'TRUE', '2023-06-02');
*/
with
daily_entries as (
select *, row_number() over (partition by id order by Insert_date) entry_id
from daily_account_data
)
select
de.id,
de.insert_date,
de.name,
de.ds_dw_id,
de.flag_1,
de.flag_2,
case when de.name <> pe.name then 'name ' else '' end
+ case when de.ds_dw_id <> pe.ds_dw_id then 'ds_dw_id ' else '' end
+ case when de.flag_1 <> pe.flag_1 then 'flag_1 ' else '' end
+ case when de.flag_2 <> pe.flag_2 then 'flag_2 ' else '' end
data_chage
from
daily_entries de
join daily_entries pe on /*previous entries*/
de.id = pe.id
and de.entry_id = pe.entry_id + 1
where
de.name <> pe.name
or de.ds_dw_id <> pe.ds_dw_id
or de.flag_1 <> pe.flag_1
or de.flag_2 <> pe.flag_2
And got:
ID | INSERT_DATE | NAME | DS_DW_ID | FLAG_1 | FLAG_2 | DATA_CHAGE |
---|---|---|---|---|---|---|
A01R11 | 2023-06-02 | Gene Wilder | PT12 | TRUE | FALSE | name |
A01R19 | 2023-06-02 | John Doe | PT24 | TRUE | TRUE | flag_1 |
A01R99 | 2023-06-02 | Caitlyn | PT17 | FALSE | TRUE | name ds_dw_id flag_1 flag_2 |
Upvotes: 2
Reputation: 32614
You can use apply
to join the previous row and then simply check each required column for equivalence, then concatenate into your new column:
select d.id, d.name, d.DS_DW_Id, d.flag_1, d.flag_2, yd.*
from daily_account_data d
cross apply (
select Concat(data_change, ' change') data_change
from daily_account_data x
cross apply(values(
Concat_Ws(', ',
case when d.name != x.name then 'Name' end,
case when d.flag_1 != x.flag_1 then 'Flag1' end,
case when d.flag_2 != x.flag_2 then 'Flag2' end
)))c(data_Change)
where x.insert_date = DateAdd(day, -1, d.insert_date)
and d.Id = x.Id
and Data_Change !=''
)yd
where d.Insert_date = '20230602';
Here's a Fiddle demo
Upvotes: 1
Reputation: 2368
You can join the table and subtract the date. If the order of the record is correct (the previous day must be the previous record, you can use the window function(LEAD ))
select
a.id
,a.Name
,a.DS_DW_Id
,a.flag_1
,a.flag_2
,iif(a.Name=b.Name ,'',' Name Change')
+iif(a.DS_DW_Id=b.DS_DW_Id ,'',' DS_DW_Id Change')
+iif(a.flag_1=b.flag_1 ,'',' flag_1 Change')
+iif(a.flag_2=b.flag_2 ,'',' flag_2 Change') AS [Data Change]
from daily_account_data a
inner join(
select *
from daily_account_data b
)b on a.id=b.id
and DATEADD(day,-1, b.Insert_date)=a.Insert_date
where a.Name<>b.Name
or a.DS_DW_Id<>b.DS_DW_Id
or a.flag_1<>b.flag_1
or a.flag_2<>b.flag_2
Upvotes: 2
Reputation: 355
here is my solution, but only if you have the same user order and number of users for all your data
select * from (select *, case when lead(Name,(select count(Insert_date)/count (distinct Insert_date) from daily_account_data)) over (order by (select null)) != Name then 'Name Change'
when lead(DS_DW_Id,(select count(Insert_date)/count (distinct Insert_date) from daily_account_data)) over (order by (select null)) != DS_DW_Id then 'DS_DW_Id Change'
when lead(flag_1,(select count(Insert_date)/count (distinct Insert_date) from daily_account_data)) over (order by (select null)) != flag_1 then 'flag_1 Change'
when lead(flag_2,(select count(Insert_date)/count (distinct Insert_date) from daily_account_data)) over (order by (select null)) != flag_2 then 'flag_2 Change' end as test from daily_account_data) as tbl where tbl.test is not null;
fiddle here
Upvotes: 0