2016-10-06 10 views
0

SQL 의 varchar (max) xml 필드에 포함 된 서버 정보를 반환하는 쿼리가 있습니다. 내 문제는 드라이브 열과 관련이 있습니다. 서버에는 여러 드라이브가있을 수 있지만 여러 자식이 있습니다 선이 컬럼에 드라이브를 분리 할 때 XML에있는 서버 부모 노드 아래의 항목은, 나는 CASE를 사용하고 있지만, 각 드라이브 문자는 자신의 행을 생성하므로이 개 드라이브 서버는 2 행XML에서 여러 열을 그룹화 할 수 없습니다

STName   STDescription   RTName   RTDescription    RTQty RTCode NTName   NTDescription    NTPVLAN NTSVLAN NTDomain NTRam NTCpus NTVMTemplate NTSCOM RTCode Cdrive Ddrive Edrive Fdrive Gdrive 
Basic Service Single Server Service Standard Server Basic server configuration 1  STD Standard Server Basic server configuration {{int}} NULL {{primary}} 4  2  1NIC2012R2CLUST TRUE STD  50  NULL NULL NULL NULL 
Basic Service Single Server Service Standard Server Basic server configuration 1  STD Standard Server Basic server configuration {{int}} NULL {{primary}} 4  2  1NIC2012R2CLUST TRUE STD  NULL 20  NULL NULL NULL 

나는 희망을 만듭니다 두 드라이브를 같은 행에 배치하도록 코드를 조정하는 것은 매우 간단합니다.

STName   STDescription   RTName   RTDescription    RTQty RTCode NTName   NTDescription    NTPVLAN NTSVLAN NTDomain NTRam NTCpus NTVMTemplate NTSCOM RTCode Cdrive Ddrive Edrive Fdrive Gdrive 
Basic Service Single Server Service Standard Server Basic server configuration 1  STD Standard Server Basic server configuration {{int}} NULL {{primary}} 4  2  1NIC2012R2CLUST TRUE STD  50  20  NULL NULL NULL 

이 여기 내 쿼리

DECLARE @XML xml; SET @XML = (SELECT CONVERT(XML, CONVERT(NVARCHAR(max), TemplateXml)) FROM dbTemplates FOR XML AUTO, Root('ACME')) 
SELECT 
ST.C.value('(Name/text())[1]', 'nvarchar(max)') as STName, 
ST.C.value('(Description/text())[1]', 'nvarchar(max)') as STDescription, 
RT.C.value('(Name/text())[1]', 'nvarchar(max)') as RTName, 
RT.C.value('(Description/text())[1]', 'nvarchar(max)') as RTDescription, 
RT.C.value('(Quantity/text())[1]', 'nvarchar(max)') as RTQty, 
RT.C.value('(Code/text())[1]', 'nvarchar(max)') as RTCode, 
NT.C.value('(Name/text())[1]', 'nvarchar(max)') as NTName, 
NT.C.value('(Description/text())[1]', 'nvarchar(max)') as NTDescription, 
NT.C.value('(PrimaryVlan/text())[1]', 'nvarchar(max)') as NTPVLAN, 
NT.C.value('(SecondaryVlan/text())[1]', 'nvarchar(max)') as NTSVLAN, 
NT.C.value('(Domain/text())[1]', 'nvarchar(max)') as NTDomain, 
NT.C.value('(RamSize/text())[1]', 'nvarchar(max)') as NTRam, 
NT.C.value('(CpuCores/text())[1]', 'nvarchar(max)') as NTCpus, 
NT.C.value('(VmTemplate/text())[1]', 'nvarchar(max)') as NTVMTemplate, 
NT.C.value('(ScomInstall/text())[1]', 'nvarchar(max)') as NTSCOM, 
NT.C.value('(SccmInstall/text())[1]', 'nvarchar(max)') as NTSCCM, 
CASE WHEN DP.C.value('(Letter/text())[1]', 'nvarchar(max)') = 'C' THEN DP.C.value('(Capacity/text())[1]', 'nvarchar(max)') END AS Cdrive, 
CASE WHEN DP.C.value('(Letter/text())[1]', 'nvarchar(max)') = 'D' THEN DP.C.value('(Capacity/text())[1]', 'nvarchar(max)') END AS Ddrive, 
CASE WHEN DP.C.value('(Letter/text())[1]', 'nvarchar(max)') = 'E' THEN DP.C.value('(Capacity/text())[1]', 'nvarchar(max)') END AS Edrive, 
CASE WHEN DP.C.value('(Letter/text())[1]', 'nvarchar(max)') = 'F' THEN DP.C.value('(Capacity/text())[1]', 'nvarchar(max)') END AS Fdrive, 
CASE WHEN DP.C.value('(Letter/text())[1]', 'nvarchar(max)') = 'G' THEN DP.C.value('(Capacity/text())[1]', 'nvarchar(max)') END AS Gdrive 
from @XML.nodes('ACME/dbTemplates/ServiceTemplate') as ST(C) 
outer apply ST.C.nodes('Roles') as RO(C) 
outer apply RO.C.nodes('RoleTemplate') as RT(C) 
outer apply RT.C.nodes('NodeTemplate') as NT(C) 
outer apply NT.C.nodes('Drives') as DR(C) 
outer apply DR.C.nodes('DriveParameter') as DP(C) 
ORDER BY STName,RTName 

입니다 <DriveParameter>nodes() 당신이 그들 모두 행 방향 얻을 사용하여 요청

<ACME> 
    <dbTemplates> 
    <ServiceTemplate xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
     <TemplateId>3205ac97-6396-4acb-8f93-5704297f1bbc</TemplateId> 
     <Name>Basic Service</Name> 
     <Description>Single Server Service</Description> 
     <Roles> 
     <RoleTemplate> 
      <TemplateId xsi:nil="true" /> 
      <Name>Standard Server</Name> 
      <Description>Basic server configuration</Description> 
      <Quantity>1</Quantity> 
      <Code>STD</Code> 
      <NodeTemplate> 
      <TemplateId xsi:nil="true" /> 
      <Name>Standard Server</Name> 
      <Description>Basic server configuration</Description> 
      <PrimaryVlan>{{int}}</PrimaryVlan> 
      <Domain>{{primary}}</Domain> 
      <RamSize>4</RamSize> 
      <CpuCores>2</CpuCores> 
      <Drives> 
       <DriveParameter> 
       <Letter>C</Letter> 
       <Capacity>50</Capacity> 
       </DriveParameter> 
       <DriveParameter> 
       <Letter>D</Letter> 
       <Capacity>20</Capacity> 
       </DriveParameter> 
       <DriveParameter> 
       <Letter>E</Letter> 
       <Capacity>50</Capacity> 
       </DriveParameter> 
      </Drives> 
      <VmTemplate>1NIC2012R2CLUST</VmTemplate> 
      <ScomInstall>True</ScomInstall> 
      <SccmInstall>True</SccmInstall> 
      </NodeTemplate> 
     </RoleTemplate> 
     </Roles> 
    </ServiceTemplate> 
    </dbTemplates> 
</ACME> 

답변

0

과 XML의 한 부분이다. 이점은 모든 번호를 처리 할 수 ​​있다는 것입니다.

은 (는)과 같은 결과입니다. 이 경우에는 어떤 문자를 사용해야하는지 알려 주어야하며 그 문자를 XQuery -filter로 사용해야합니다 (그리고 XQuery은 대소 문자를 구분합니다.) 다음 해결책은 대문자로만 작동합니다 ...

그리고 한 가지 힌트 : It 당신이 A(ST)처럼 B(RO), C(RT) 당신의 CROSS APPLY의 전화 등등. 그런 다음 ST.value(...)를 호출 할 수 있습니다 및 쿼리의 반복 .C.value을 피하면 ...,

DECLARE @xml XML= 
'<ACME> 
    <dbTemplates> 
    <ServiceTemplate xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
     <TemplateId>3205ac97-6396-4acb-8f93-5704297f1bbc</TemplateId> 
     <Name>Basic Service</Name> 
     <Description>Single Server Service</Description> 
     <Roles> 
     <RoleTemplate> 
      <TemplateId xsi:nil="true" /> 
      <Name>Standard Server</Name> 
      <Description>Basic server configuration</Description> 
      <Quantity>1</Quantity> 
      <Code>STD</Code> 
      <NodeTemplate> 
      <TemplateId xsi:nil="true" /> 
      <Name>Standard Server</Name> 
      <Description>Basic server configuration</Description> 
      <PrimaryVlan>{{int}}</PrimaryVlan> 
      <Domain>{{primary}}</Domain> 
      <RamSize>4</RamSize> 
      <CpuCores>2</CpuCores> 
      <Drives> 
       <DriveParameter> 
       <Letter>C</Letter> 
       <Capacity>50</Capacity> 
       </DriveParameter> 
       <DriveParameter> 
       <Letter>D</Letter> 
       <Capacity>20</Capacity> 
       </DriveParameter> 
       <DriveParameter> 
       <Letter>E</Letter> 
       <Capacity>50</Capacity> 
       </DriveParameter> 
      </Drives> 
      <VmTemplate>1NIC2012R2CLUST</VmTemplate> 
      <ScomInstall>True</ScomInstall> 
      <SccmInstall>True</SccmInstall> 
      </NodeTemplate> 
     </RoleTemplate> 
     </Roles> 
    </ServiceTemplate> 
    </dbTemplates> 
</ACME>'; 

--The 쿼리를 읽고 간단

SELECT 
ST.C.value('(Name/text())[1]', 'nvarchar(max)') as STName, 
ST.C.value('(Description/text())[1]', 'nvarchar(max)') as STDescription, 
RT.C.value('(Name/text())[1]', 'nvarchar(max)') as RTName, 
RT.C.value('(Description/text())[1]', 'nvarchar(max)') as RTDescription, 
RT.C.value('(Quantity/text())[1]', 'nvarchar(max)') as RTQty, 
RT.C.value('(Code/text())[1]', 'nvarchar(max)') as RTCode, 
NT.C.value('(Name/text())[1]', 'nvarchar(max)') as NTName, 
NT.C.value('(Description/text())[1]', 'nvarchar(max)') as NTDescription, 
NT.C.value('(PrimaryVlan/text())[1]', 'nvarchar(max)') as NTPVLAN, 
NT.C.value('(SecondaryVlan/text())[1]', 'nvarchar(max)') as NTSVLAN, 
NT.C.value('(Domain/text())[1]', 'nvarchar(max)') as NTDomain, 
NT.C.value('(RamSize/text())[1]', 'nvarchar(max)') as NTRam, 
NT.C.value('(CpuCores/text())[1]', 'nvarchar(max)') as NTCpus, 
NT.C.value('(VmTemplate/text())[1]', 'nvarchar(max)') as NTVMTemplate, 
NT.C.value('(ScomInstall/text())[1]', 'nvarchar(max)') as NTSCOM, 
NT.C.value('(SccmInstall/text())[1]', 'nvarchar(max)') as NTSCCM, 

NT.C.value('(Drives/DriveParameter[Letter="C"]/Capacity)[1]','int') AS CDrive, 
NT.C.value('(Drives/DriveParameter[Letter="D"]/Capacity)[1]','int') AS DDrive, 
NT.C.value('(Drives/DriveParameter[Letter="E"]/Capacity)[1]','int') AS EDrive, 
NT.C.value('(Drives/DriveParameter[Letter="F"]/Capacity)[1]','int') AS FDrive, 
NT.C.value('(Drives/DriveParameter[Letter="G"]/Capacity)[1]','int') AS GDrive 

from @XML.nodes('ACME/dbTemplates/ServiceTemplate') as ST(C) 
outer apply ST.C.nodes('Roles') as RO(C) 
outer apply RO.C.nodes('RoleTemplate') as RT(C) 
outer apply RT.C.nodes('NodeTemplate') as NT(C) 
ORDER BY STName,RTName 
+0

코드를 표시하는 더 좋은 방법은 항상 확인해 주셔서 감사합니다. 실제로는 다른 곳에서 발견 된 다른 코드 조각을 해킹하여이 코드를 보았습니다. – markyb0y

관련 문제