Проблемы SQL XQuery и Cross Apply ... слишком много строк в результатах - PullRequest
1 голос
/ 12 декабря 2011

У меня есть таблица контрактов.Есть несколько столбцов и, наконец, столбец XML, представляющий весь контракт.Внутри контракта находятся проекты (1 или более), а внутри каждого проекта - 1 или более строк.Мне нужно иметь возможность выбрать все строки и проекты, над которыми они работают, но сейчас я получаю странные результаты с моим примером запроса.

Вот пример 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>

А вот мой пример запроса:

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)

Результаты:

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

Проблема в том, что «0.080 Aluminium 2ft x 4ft» только для «BOM1», а «# 8X8SPOOL» только для «BOM2», поэтому в результатах должно быть только 2 строки.Пожалуйста, помогите, спасибо!

1 Ответ

3 голосов
/ 12 декабря 2011

Это должно сработать. Обратите внимание, что второй CROSS APPLY связан с первым (Proj.ProjName.nodes() в отличие от CM.FullContract.nodes()), а не повторно разделяет ваш XML в совершенно новую таблицу. Это делает ваши дочерние данные связанными с правильным именем проекта:

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)
...