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.