简体   繁体   中英

SQL XQuery and Cross Apply problems…too many rows in results

I have a table of contracts. There are several columns and finally an XML column representing the whole contract. Inside the contract are projects (1 or more) and inside each project are 1 or more lines. I need to be able to select all of the lines and the projects they are on, but I'm getting odd results right now with my sample query.

Here is a sample of the XML:

<ZEstimateContract xmlns="http://schemas.datacontract.org/2004/07/Zeller.Gp" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">
  <Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">QGPET0000000218</Name>
  <_projects>
    <ZEstimateProject z:Id="i9">
      <Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">&lt;BOM1&gt;</Name>
      <Parent i:nil="true" />
      <Quantity>1</Quantity>
      <_lines>
        <ZEstimateLine z:Id="i40">
          <Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">0.080 Aluminum 2ft x 4ft</Name>
          <_lines />
        </ZEstimateLine>
      </_lines>
      <_projects />
    </ZEstimateProject>
    <ZEstimateProject z:Id="i97">
      <Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">&lt;BOM2&gt;</Name>
      <Parent i:nil="true" />
      <Quantity>1</Quantity>      
      <_lines>
        <ZEstimateLine z:Id="i113">          
          <Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">#8X8SPOOL</Name>
        </ZEstimateLine>
      <_projects />
    </ZEstimateProject>
  </_projects>
</ZEstimateContract>

And here is my sample query:

WITH XMLNAMESPACES('http://schemas.datacontract.org/2004/07/Zeller.Gp' AS ZC, 
    'http://schemas.datacontract.org/2004/07/Zynergy' AS ZYN)

SELECT Contract, LineName.value('.', 'varchar(50)') as LineItemName, ProjName.value('.', 'varchar(50)') as ProjectName
FROM dbo.tblContractMaster AS CM 
CROSS APPLY CM.FullContract.nodes('/ZC:ZEstimateContract/ZC:_projects/ZC:ZEstimateProject/ZYN:Name') as Proj(ProjName)
CROSS APPLY CM.FullContract.nodes('/ZC:ZEstimateContract/ZC:_projects/ZC:ZEstimateProject/ZC:_lines/ZC:ZEstimateLine/ZYN:Name') as Line(LineName)

The results are:

QGPET0000000218    0.080 Aluminum 2ft x 4ft          <BOM1>
QGPET0000000218    #8X8SPOOL                         <BOM1>
QGPET0000000218    0.080 Aluminum 2ft x 4ft          <BOM2>
QGPET0000000218    #8X8SPOOL                         <BOM2>

The problem is that "0.080 Aluminum 2ft x 4ft" is only on "BOM1" and "#8X8SPOOL" is only on "BOM2", so there should only be 2 rows in the results. Please help, thanks!

This ought to work. Note that the second CROSS APPLY is chained to the first one ( Proj.ProjName.nodes() as opposed to CM.FullContract.nodes() ), rather than re-shredding your XML into an entirely new table. Doing this is what keeps your child data associated with the correct project name:

WITH XMLNAMESPACES('http://schemas.datacontract.org/2004/07/Zeller.Gp' AS ZC, 
    'http://schemas.datacontract.org/2004/07/Zynergy' AS ZYN)

SELECT Contract, LineName.value('.', 'varchar(50)') as LineItemName, ProjName.value('.', 'varchar(50)') as ProjectName
FROM @contract AS CM 
CROSS APPLY CM.FullContract.nodes('/ZC:ZEstimateContract/ZC:_projects/ZC:ZEstimateProject/ZYN:Name') as Proj(ProjName)
CROSS APPLY Proj.ProjName.nodes('../ZC:_lines/ZC:ZEstimateLine/ZYN:Name') as Line(LineName)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM