Reputation: 3715
I have to write this question "conceptually" because I am not sure what approach to actually take. The way I am asking my question might hit the XY problem -- please suggest other alternatives if you see them.
I am writing a reporting query on a database that is already in production. Consider the following table (similar to my current result set):
Id | Code1 | Code2 | Code3 | Code4 | Code5
-----------------------------------------------------------
1 1 2 3 4 5
1 2 3 4 5 6
2 1 null null null null
All of the codes are the same "type", both literally (as data types) and conceptually (as in, they represent the same "kind" of code, for the same kind of event, etc). Obviously, this data isn't properly normalized, but I still need to transform it.
I would like to write a query that "groups by" the id, and returns a collection of all the unique codes in the 5 code columns.
Ultimately, my goal will be to transform the table to:
Id Codes
1 [1, 2, 3, 4, 5, 6]
2 [1]
(Where the []
at least conceptually represents some kind of collection or table or list type)
(Actually, I need to join against those codes for a quick look up, so the "actual" result should look like)
Id CodeStrings
1 [Foo, Bar, Baz, Bon, Fizz, Buzz]
2 [Foo]
Can you describe a pattern that will let me form a "collection" per row, and aggregate them?
Upvotes: 0
Views: 86
Reputation: 1270081
You need to unpivot and re-aggregate. This is pretty easy in SQL Server 2017+:
select t.id, string_agg(c.code, ',')
from t cross apply
(select distinct v.code
from (values (code1), (code2), (code3), (code4), (code5)
) v(code)
where v.code is not null
) c;
In earlier versions, you can use for xml path
:
select t.id, stuff(c.codes, 1, 1, '') as codes
from t cross apply
(select distinct ',' + v.code
from (values (code1), (code2), (code3), (code4), (code5)
) v(code)
where v.code is not null
for xml path ('')
) c(codes)
Upvotes: 1
Reputation: 145
I would unpivot the table first, then concatenate rows grouped by Id using For xml path.
Upvotes: 1
Reputation: 4154
For just 5, the easiest option might be:
Select ID, '[' + ISNULL(Code1, '')
+ ISNULL(' ,' + Code2, '')
+ ISNULL(' ,' + Code3, '')
+ ISNULL(' ,' + Code4, '')
+ ISNULL(' ,' + Code5, '') + ']'
From MyTable
Note that you might need to wrap the codes in a cast
or convert
to varchar
if they are stored as numerics.
Upvotes: 0