Reputation: 6988
I'm comparing 2 tables. One has new data and the other has last months old data. The data comes monthly and it's all the data each time. There is no PK and any field can change. I need to show what fields and their old values for records that changed. It could be 1 or more fields. To do this I created inner joins where all fields are joined on except 1 and then in the where I say the old value is not equal to the new value and then I add 2 columns that tell me what field we are looking at and what the old value was. I do this query for each field and union the results so my final table looks like:
FieldA, FieldB, FieldC, FieldChanged, OldValue
FieldChanged will have field names that changed for that record and OldValue will say what the old value was.
If a record has more than 1 field changed (which there are) then I get that Field A-C duplicated in the result, with a different FieldChanged and OldValue values. However, I want to do a group by FieldA, FieldB, FieldC, and somehow contact FieldChanged from all the same records and OldValue from all the same records.
The union query result would look like (the first 3 fields is how the new data looks like):
"Tiger", "74", "Masters", "FieldC", "The Masters"
"Tiger", "74", "Masters", "FieldB", "68"
I would like to group by fields 1-3 and concat the last 2 fields in the group:
"Tiger", "74", "Masters", "FieldB,FieldC", "68,The Masters"
Now this is just an example so it's simple and might be easy to say this is a new record, however my table has 12 fields and so if everything matches but 1 field, chances are it's the same record and they just updated one of the fields.
The key here is being able to group by certain columns and concat other field values from the grouped columns together so that the same record isn't repeated and I have 1 line that shows every field that has changed for that record and it's old values.
Upvotes: 1
Views: 85
Reputation: 93694
try this.
CREATE TABLE #test
(
FieldA VARCHAR(25),
FieldB VARCHAR(25),
FieldC VARCHAR(25),
FieldChanged VARCHAR(25),
OldValue VARCHAR(25)
)
INSERT #test
VALUES ('Tiger','74','Masters','FieldC','The Masters'),
('Tiger','74','Masters','FieldB','68')
Method 1: For XML PATH
SELECT my_column AS [text()]
FROM my_table
FOR XML PATH('')
This gives you the concatenated values of all of the values of this column in the table
SELECT FieldA,
FieldB,
FieldC,
Stuff((SELECT ', ' + FieldChanged
FROM #test b
WHERE b.FieldA = a.FieldA
AND b.FieldB = a.FieldB
AND b.FieldC = a.FieldC
FOR XML PATH('')), 1, 2, '') FieldChanged,
Stuff((SELECT ', ' + OldValue
FROM #test b
WHERE b.FieldA = a.FieldA
AND b.FieldB = a.FieldB
AND b.FieldC = a.FieldC
FOR XML PATH('')), 1, 2, '') OldValue
FROM #test a
GROUP BY FieldA,
FieldB,
FieldC
Method 2: Using Cross Apply
SELECT FieldA,
FieldB,
FieldC,
Substring(d.FieldChanged, 1, Len(d.FieldChanged) - 1) FieldChanged,
Substring(d.OldValue, 1, Len(d.OldValue) - 1) OldValue
FROM (SELECT DISTINCT FieldA,
FieldB,
FieldC
FROM #test) a
CROSS APPLY (SELECT (SELECT FieldChanged + ', '
FROM #test AS B
WHERE b.FieldA = a.FieldA
AND b.FieldB = a.FieldB
AND b.FieldC = a.FieldC
FOR XML PATH('')),
(SELECT OldValue + ', '
FROM #test AS B
WHERE b.FieldA = a.FieldA
AND b.FieldB = a.FieldB
AND b.FieldC = a.FieldC
FOR XML PATH(''))) D (FieldChanged, OldValue)
Upvotes: 2