Tiene un poco de lío aquí porque tiene dos tablas en diferentes estructuras y desea pivotar varias columnas. Primero comenzaría escribiendo una versión estática de su consulta para obtener la lógica correcta, luego pasaría por el proceso de escribir una versión dinámica.
Dado que desea girar varias columnas, deberá deshacer la rotación de varias columnas en los Controls
primero la mesa, luego pivotar. Ha etiquetado esto como SQL Server 2008, por lo que puede usar CROSS APPLY
para des-pivotar las columnas.
Sugiero tomar los siguientes pasos. Primero, quita el pivote de los controls
tabla:
select
ProjectId,
col = ControlCode +'_'+col,
val
from
(
select
c.ProjectId,
c.ControlCode,
c.ControlPoint,
c.ControlScore,
c.ControlValue
from controls c
) d
cross apply
(
select 'ControlPoint', cast(controlpoint as varchar(10)) union all
select 'ControlScore', cast(ControlScore as varchar(10)) union all
select 'ControlValue', ControlValue
) c (col, val)
Consulte SQL Fiddle con demostración . Esto va a convertir sus múltiples filas en múltiples columnas similares a:
| PROJECTID | COL | VAL |
|-----------|----------------|---------|
| P001 | A_ControlPoint | 30.44 |
| P001 | A_ControlScore | 65.00 |
| P001 | A_ControlValue | Invalid |
| P001 | C_ControlPoint | 45.30 |
| P001 | C_ControlScore | 85.00 |
| P001 | C_ControlValue | Valid |
En segundo lugar, obtenga los datos de ControlChilds
tabla en un formato similar pero use su row_number()
para asignar una secuencia para cada niño:
select
projectId,
col = ControlCode+'_'+'Child'+cast(seq as varchar(10)),
ControlChildValue
from
(
select c.ProjectId,
c.ControlCode,
cc.ControlChildValue,
row_number() over(partition by c.ProjectId, c.ControlCode
order by cc.ControlChildId) seq
from controls c
inner join controlchilds cc
on c.controlid = cc.controlid
) d
Consulte SQL Fiddle con demostración . Esto obtiene los datos de esta tabla en el formato:
| PROJECTID | COL | CONTROLCHILDVALUE |
|-----------|----------|-------------------|
| P001 | A_Child1 | Yes |
| P001 | A_Child2 | No |
| P001 | A_Child3 | NA |
| P001 | A_Child4 | Others |
| P001 | C_Child1 | Yes |
| P001 | C_Child2 | SomeValue |
Ahora, puede usar fácilmente UNION ALL
entre las dos consultas y aplique la función PIVOT:
select ProjectId,
A_ControlPoint, A_ControlScore, A_ControlValue,
A_Child1, A_Child2, A_Child3, A_Child4,
C_ControlPoint, C_ControlScore, C_ControlValue,
C_Child1, C_Child2
from
(
select
ProjectId,
col = ControlCode +'_'+col,
val
from
(
select
c.ProjectId,
c.ControlCode,
c.ControlPoint,
c.ControlScore,
c.ControlValue
from controls c
) d
cross apply
(
select 'ControlPoint', cast(controlpoint as varchar(10)) union all
select 'ControlScore', cast(ControlScore as varchar(10)) union all
select 'ControlValue', ControlValue
) c (col, val)
union all
select
projectId,
col = ControlCode+'_'+'Child'+cast(seq as varchar(10)),
ControlChildValue
from
(
select c.ProjectId,
c.ControlCode,
cc.ControlChildValue,
row_number() over(partition by c.ProjectId, c.ControlCode
order by cc.ControlChildId) seq
from controls c
inner join controlchilds cc
on c.controlid = cc.controlid
) d
) src
pivot
(
max(val)
for col in (A_ControlPoint, A_ControlScore, A_ControlValue,
A_Child1, A_Child2, A_Child3, A_Child4,
C_ControlPoint, C_ControlScore, C_ControlValue,
C_Child1, C_Child2)
) piv;
Consulte SQL Fiddle con demostración .
Ahora que tiene la lógica correcta, puede convertir esto a una versión SQL dinámica:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(col)
from
(
select ControlCode,
col = ControlCode +'_'+col,
seq,
so
from controls
cross apply
(
select 'ControlPoint', 0, 0 union all
select 'ControlScore', 0, 1 union all
select 'ControlValue', 0, 2
) c (col, seq, so)
union all
select ControlCode,
col = ControlCode+'_'+'Child'+cast(seq as varchar(10)),
seq,
3
from
(
select ControlCode,
row_number() over(partition by c.ProjectId, c.ControlCode
order by cc.ControlChildId) seq
from controls c
inner join controlchilds cc
on c.controlid = cc.controlid
) d
) src
group by ControlCode, seq, col, so
order by ControlCode, so, seq
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT ProjectId, ' + @cols + '
from
(
select ProjectId,
col = ControlCode +''_''+col,
val
from
(
select
c.ProjectId,
c.ControlCode,
c.ControlPoint,
c.ControlScore,
c.ControlValue
from controls c
) d
cross apply
(
select ''ControlPoint'', cast(controlpoint as varchar(10)) union all
select ''ControlScore'', cast(ControlScore as varchar(10)) union all
select ''ControlValue'', ControlValue
) c (col, val)
union all
select
projectId,
col = ControlCode+''_Child''+cast(seq as varchar(10)),
ControlChildValue
from
(
select c.ProjectId,
c.ControlCode,
cc.ControlChildValue,
row_number() over(partition by c.ProjectId, c.ControlCode
order by cc.ControlChildId) seq
from controls c
inner join controlchilds cc
on c.controlid = cc.controlid
) d
) x
pivot
(
max(val)
for col in (' + @cols + ')
) p '
exec sp_executesql @query;
Consulte SQL Fiddle con demostración . Escribí la versión dinámica para mantener las columnas en el orden que usó en su muestra. Esto se puede hacer usando un tipo de valor de orden de clasificación.
Esto da un resultado final de:
| PROJECTID | A_CONTROLPOINT | A_CONTROLSCORE | A_CONTROLVALUE | A_CHILD1 | A_CHILD2 | A_CHILD3 | A_CHILD4 | C_CONTROLPOINT | C_CONTROLSCORE | C_CONTROLVALUE | C_CHILD1 | C_CHILD2 |
|-----------|----------------|----------------|----------------|----------|----------|----------|----------|----------------|----------------|----------------|----------|-----------|
| P001 | 30.44 | 65.00 | Invalid | Yes | No | NA | Others | 45.30 | 85.00 | Valid | Yes | SomeValue |