Un modo molto semplice per creare set nidificati è XML:
--Tabella mockup
DECLARE @tbl TABLE([State] VARCHAR(100), Project INT, ClassOfPlant VARCHAR(100),[Description] VARCHAR(100),ProjApprovalDate DATE);
INSERT INTO @tbl VALUES
('FL',4139904,'TR','2016 CO161 OA341 SPECIAL SERVICES BLANKET',{d'2016-10-11'})
,('FL',4144128,'TR','WSSD RWB M6 GPON CARD ADDITION TO SUPPORT GROWTH',{d'2016-10-11'})
,('FL',4145813,'OP','BRND-RBB-FTTP-GFLD-CROSSINGS-FISHHAWK RANCH W PH4B',{d'2016-10-11'})
,('FL',4146018,'OP','LKLDN-TMF-GFLD 56 SFU DONOVAN RD ESTATES DESIGN',{d'2016-10-11'});
--La domanda
SELECT t1.[State] AS [@value]
,(
SELECT t2.ClassOfPlant AS [@value]
,(
SELECT t3.Project AS [@value]
,t3.[Description] AS [@desription]
,t3.ProjApprovalDate AS [@apporval_date]
FROM @tbl AS t3
WHERE t3.[State]=t1.[State] AND t3.ClassOfPlant=t2.ClassOfPlant
FOR XML PATH('project'),TYPE
)
FROM @tbl AS t2
WHERE t1.[State]=t2.[State]
GROUP BY t2.ClassOfPlant
FOR XML PATH('plant'),TYPE
)
FROM @tbl AS t1
GROUP BY t1.[State]
FOR XML PATH('state'),ROOT('root')
Il risultato
<root>
<state value="FL">
<plant value="OP">
<project value="4145813" desription="BRND-RBB-FTTP-GFLD-CROSSINGS-FISHHAWK RANCH W PH4B" apporval_date="2016-10-11" />
<project value="4146018" desription="LKLDN-TMF-GFLD 56 SFU DONOVAN RD ESTATES DESIGN" apporval_date="2016-10-11" />
</plant>
<plant value="TR">
<project value="4139904" desription="2016 CO161 OA341 SPECIAL SERVICES BLANKET" apporval_date="2016-10-11" />
<project value="4144128" desription="WSSD RWB M6 GPON CARD ADDITION TO SUPPORT GROWTH" apporval_date="2016-10-11" />
</plant>
</state>
</root>
AGGIORNAMENTO
Puoi creare il risultato in base alla tabella dall'XML in questo modo
SELECT CASE WHEN nd.value('local-name(.)','nvarchar(max)')=N'state' THEN nd.value('@value','nvarchar(max)') END AS [State]
,CASE WHEN nd.value('local-name(.)','nvarchar(max)')=N'plant' THEN nd.value('@value','nvarchar(max)') END AS [ClassOfPlant]
,CASE WHEN nd.value('local-name(.)','nvarchar(max)')=N'project' THEN nd.value('@value','nvarchar(max)') END AS [Project]
,CASE WHEN nd.value('local-name(.)','nvarchar(max)')=N'project' THEN nd.value('@desription','nvarchar(max)') END AS [Description]
,CASE WHEN nd.value('local-name(.)','nvarchar(max)')=N'project' THEN nd.value('@apporval_date','date') END AS [ProjApprovalDate]
FROM @xml.nodes('//*[local-name(.)!="root"]') AS A(nd)
Il risultato
State ClassOfPlant Project Description ProjApprovalDate
FL NULL NULL NULL NULL
NULL OP NULL NULL NULL
NULL NULL 4145813 BRND-RBB ... 2016-10-11
NULL NULL 4146018 LKLDN-TMF... 2016-10-11
NULL TR NULL NULL NULL
NULL NULL 4139904 2016 CO16... 2016-10-11
NULL NULL 4144128 WSSD RWB ... 2016-10-11
Usa ISNULL
per restituire una stringa vuota invece di un NULL
se hai bisogno di questo...