This is probably a duplicate question, but I couldn’t find it. Maybe I’m thinking about this backwards.
How do I format a query to return the results like this with the source tables below?
Filename | Attr1 | Attr2 | Attr3 | Configuration |
---|---|---|---|---|
file1.txt | Val1 | Val2 | Val3 | Default |
file1.txt | Val1 | Val2 | Val3 | First |
Documents Table
DocumentID | Filename |
---|---|
1 | file1.txt |
VariableValues table
VariableID | DocumentID | ValueCache | ConfigurationID |
---|---|---|---|
55 | 1 | Val1 | 1 |
56 | 1 | Val2 | 1 |
172 | 1 | Val3 | 1 |
55 | 1 | Val1 | 2 |
56 | 1 | Val2 | 2 |
172 | 1 | Val3 | 2 |
Configuration Table
ConfigurationID | ConfigName |
---|---|
1 | Default |
2 | First |
I originally wrote this with subqueries
select top 10 d.Filename, (select ValueCache from VariableValue vv where d.DocumentID = vv.DocumentID and vv.VariableID = 55) as Description, (select ValueCache from VariableValue vv where d.DocumentID = vv.DocumentID and vv.VariableID = 56) as PartNumber, (select ValueCache from VariableValue vv where d.DocumentID = vv.DocumentID and vv.VariableID = 172) as CrossReference, dc.ConfigurationName FROM Documents d INNER JOIN VariableValue vv ON d.DocumentID = vv.DocumentID inner join DocumentConfiguration dc ON dc.ConfigurationID = vv.ConfigurationID
But that doesn’t handle configurations properly, the subqueries return multiple results when there are multiple configurations. So I tried converting it to a table valued query, but this returns each variable on a separate line and I can’t figure out how to transpose them.
select top 10 d.Filename, d.DocumentID, ConfigurationID, d.CurrentStatusID into #temp FROM Documents d INNER JOIN VariableValue vv ON d.DocumentID = vv.DocumentID WHERE vv.VariableID = 172 and ValueCache is not null select t.Filename, vv.ValueCache, v.VariableName, s.Name from #temp t inner join VariableValue vv ON t.DocumentID = vv.DocumentID and t.ConfigurationID = vv.ConfigurationID inner join Variable v ON vv.VariableID = v.VariableID and v.VariableID in (55, 56, 172) inner join [Status] s ON s.StatusID = t.CurrentStatusID drop table #temp
Advertisement
Answer
You can use the PIVOT
function on your INNER JOIN
query in two scenarios:
1st one: if the number of ValueCache
values is known i.e. only (val1, val2, val3)
select Filename, Val1 as att1, Val2 as att2, Val3 as att3, ConfigName from ( select Documents.Filename, VariableValues.ValueCache,Configuration.ConfigName from Documents inner join VariableValues on Documents.DocumentID=VariableValues.DocumentID inner join Configuration on Configuration.ConfigurationID = VariableValues.ConfigurationID ) D PIVOT (MAX(ValueCache) for ValueCache in (Val1, Val2, Val3)) P
2nd one: if the number of ValueCache
values is unknown then you can use Dynamic SQL Query
DECLARE @valCols AS NVARCHAR(MAX), @sqlQr AS NVARCHAR(MAX) select @valCols = STUFF((SELECT distinct ',' + QUOTENAME(ValueCache) from VariableValues FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'') set @sqlQr = 'SELECT Filename, ' + @valCols + ', ConfigName from ( select Documents.Filename, VariableValues.ValueCache,Configuration.ConfigName from Documents inner join VariableValues on Documents.DocumentID=VariableValues.DocumentID inner join Configuration on Configuration.ConfigurationID = VariableValues.ConfigurationID ) D PIVOT (MAX(ValueCache) for ValueCache in ('+ @valCols+ ')) P' execute(@sqlQr)
See the result form dbfiddle.