我是SQL新手,但我了解获取节点和查询值的基础知识。我现在的问题是处理未知深度的层次结构。
关系是合同 - >项目 - >线;看起来像这样:
<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="i10">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">Project A</Name>
<_lines>
<ZEstimateLine z:Id="i41">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">00008813</Name>
<_lines>
<ZEstimateLine z:Id="i43">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">002-2075-4 MAIN COLUMN</Name>
<_lines />
</ZEstimateLine>
</_lines>
</ZEstimateLine>
<ZEstimateLine z:Id="i44">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">0.080 Aluminum 2ft x 4ft</Name>
<_lines />
</ZEstimateLine>
</_lines>
<_projects>
<ZEstimateProject z:Id="i101">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">Project A1</Name>
<_lines>
<ZEstimateLine z:Id="i132">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy" />
<_lines />
</ZEstimateLine>
</_lines>
<_projects />
</ZEstimateProject>
</_projects>
</ZEstimateProject>
<ZEstimateProject z:Id="i189">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">Project B</Name>
<_lines>
<ZEstimateLine z:Id="i205">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">#8X8SPOOL</Name>
<_lines />
</ZEstimateLine>
</_lines>
<_projects />
</ZEstimateProject>
</_projects>
<_rebateSources />
</ZEstimateContract>
因此,合同可以包含任意数量的项目,这些项目可以包含任意数量的行和任意数量的子项目。这些行可以有任意数量的子行。
我正在编写SQL查询以返回结果集中的所有行(编辑:以及其他数据)。以下是我到目前为止的情况:
-- TEST DATA
DECLARE @QuoteDate DATETIME = '12/12/2011'
DECLARE @QuoteNumber VARCHAR(15) = 'QGPET0000000218'
DECLARE @RevLevel VARCHAR(50) = '0'
;WITH XMLNAMESPACES('http://schemas.datacontract.org/2004/07/Zeller.Gp' AS ZC,
'http://schemas.datacontract.org/2004/07/Zynergy' AS ZYN,
'http://schemas.microsoft.com/2003/10/Serialization/' AS Z)
SELECT CM.Contract, CM.RevisionLevel, CM.CustomerGpId,
p.value('(./ZYN:Name)[1]', 'varchar(50)') as ProjectName,
l.value('(./ZYN:Name)[1]', 'varchar(50)') as ItemNumber
FROM dbo.tblContractMaster AS CM
CROSS APPLY CM.FullContract.nodes('/ZC:ZEstimateContract/ZC:_projects/ZC:ZEstimateProject') as Proj(p)
CROSS APPLY Proj.p.nodes('./ZC:_lines/ZC:ZEstimateLine') as Line(l)
WHERE CM.[Contract] = @QuoteNumber AND CM.RevisionLevel = @RevLevel
-- Order by the default "ID" that gets assigned to the XML element.
-- This is the same order that the object is in when in a collection in GPET
ORDER BY p.value('(./@Z:Id)[1]', 'varchar(50)'), l.value('(./@Z:Id)[1]', 'varchar(50)')
正如你所看到的,这只会让我“一级”,但我需要更深入(想想初始!......项目中的一个项目......你明白了)
有什么想法吗?
编辑添加了部分解决方案。这让我得到子项目(注意“//”),而不是子行:
CROSS APPLY CM.FullContract.nodes('/ZC:ZEstimateContract//ZC:_projects/ZC:ZEstimateProject') as Proj(p)
CROSS APPLY Proj.p.nodes('./ZC:_lines/ZC:ZEstimateLine') as Line(l) LEFT OUTER JOIN
编辑:这是一个更好的示例:
<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">
<_key xmlns="http://schemas.datacontract.org/2004/07/Zynergy">ZynergyDefault</_key>
<_dataStoreGuid xmlns="http://schemas.datacontract.org/2004/07/Zynergy">88381fa0-5901-4513-9ccb-b2f576341db1</_dataStoreGuid>
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">QGPET0000000218</Name>
<_projects>
<ZEstimateProject z:Id="i10">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">Project A</Name>
<Parent i:nil="true" />
<_lines>
<ZEstimateLine z:Id="i41">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">00008813</Name>
<Description>Epic circular connector w/ 12 inserts.</Description>
<Parent i:nil="true" />
<_lines>
<ZEstimateLine z:Id="i43">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">002-2075-4 MAIN COLUMN</Name>
<Description>CUSTOM JBOX, PER DWG REV -, PUNCHED, TAPPED, CUT OUTS, PBT4-70003 TEXTURE BLACK INSIDE AND OUTSIDE</Description>
<Parent z:Id="i44">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">00008813</Name>
<Description>Epic circular connector w/ 12 inserts.</Description>
<Parent i:nil="true" />
<_lines>
<ZEstimateLine z:Id="i46">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">002-2075-4 MAIN COLUMN</Name>
<Description>CUSTOM JBOX, PER DWG REV -, PUNCHED, TAPPED, CUT OUTS, PBT4-70003 TEXTURE BLACK INSIDE AND OUTSIDE</Description>
<Parent z:Ref="i44" />
<_lines />
</ZEstimateLine>
</_lines>
</Parent>
<_lines />
</ZEstimateLine>
</_lines>
</ZEstimateLine>
<ZEstimateLine z:Id="i47">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">AG30</Name>
<Description>480V 30A CLASS G FUSE</Description>
<Parent i:nil="true" />
<_lines />
</ZEstimateLine>
</_lines>
<_projects>
<ZEstimateProject z:Id="i105">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">Project A1</Name>
<_lines>
<ZEstimateLine z:Id="i136">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">0026153</Name>
<Description>Olflex 810 16awg 7cond</Description>
<_lines />
</ZEstimateLine>
</_lines>
<_projects>
<ZEstimateProject z:Id="i193">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy"><BOM></Name>
<Parent z:Ref="i105" />
<_lines>
<ZEstimateLine z:Id="i224">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">PROSINE 1000</Name>
<Parent i:nil="true" />
<_lines />
</ZEstimateLine>
</_lines>
<_projects />
<_savedBudgets />
</ZEstimateProject>
</_projects>
<_savedBudgets />
</ZEstimateProject>
</_projects>
</ZEstimateProject>
<ZEstimateProject z:Id="i281">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">Project B</Name>
<Parent i:nil="true" />
<_lines>
<ZEstimateLine z:Id="i297">
<Name xmlns="http://schemas.datacontract.org/2004/07/Zynergy">#8X8SPOOL</Name>
<Description>1-8"x14.05" flg x flg. DIP, Black</Description>
<Parent i:nil="true" />
<_lines />
</ZEstimateLine>
</_lines>
<_projects />
</ZEstimateProject>
</_projects>
</ZEstimateContract>
答案 0 :(得分:2)
你非常接近。我认为您需要做的就是使用评论中的更新版本并将第二个CROSS应用更改为:
CROSS APPLY Proj.p.nodes('.//ZC:_lines/ZC:ZEstimateLine') as Line(l)
这使用你之前发现的相同的额外斜杠来递减并查找所有行。
您希望针对您的数据对此进行测试,但针对您的示例,它似乎正常运行。
修改强> :
好吧,我想我现在拥有它。它复杂得多,虽然我试图用递归CTE来做,但是我无法找到直接链接两个递归CTE的方法,也不能用一个递归CTE。更多的古茹人可能能够改善这一点。我最终得到的是两个表值UDF,一个用于递归递送所有项目,另一个用于获取每个项目并递归地删除所有行:
CREATE FUNCTION fn_explode_projects (@xdata xml)
RETURNS TABLE
AS
RETURN
WITH XMLNAMESPACES('http://schemas.datacontract.org/2004/07/Zeller.Gp' AS ZC,
'http://schemas.datacontract.org/2004/07/Zynergy' AS ZYN,
'http://schemas.microsoft.com/2003/10/Serialization/' AS Z),
ProjList (ProjectName, ChildProjects, ChildLines)
AS
(
SELECT CAST(NULL as varchar(50)) AS ProjectName,
@xdata.query('/ZC:ZEstimateContract/ZC:_projects') AS ChildProjects,
CAST(NULL AS xml) AS ChildLines
UNION ALL
SELECT CP.ChildProject.value('(./ZYN:Name)[1]', 'varchar(50)') AS ProjectName,
CP.ChildProject.query('./ZC:_projects') AS ChildProjects,
CP.ChildProject.query('./ZC:_lines') AS ChildLines
FROM ProjList
CROSS APPLY ProjList.ChildProjects.nodes('/ZC:_projects/ZC:ZEstimateProject') AS CP(ChildProject)
)
SELECT ProjectName, ChildProjects, ChildLines
FROM ProjList
GO
CREATE FUNCTION fn_explode_lines (@xdata xml)
RETURNS TABLE
AS
RETURN
WITH XMLNAMESPACES('http://schemas.datacontract.org/2004/07/Zeller.Gp' AS ZC,
'http://schemas.datacontract.org/2004/07/Zynergy' AS ZYN,
'http://schemas.microsoft.com/2003/10/Serialization/' AS Z),
ItemList (ItemNumber, ChildLines)
AS
(
SELECT CAST(NULL as varchar(50)) AS ItemNumber,
@xdata.query('/ZC:_lines') AS ChildLines
UNION ALL
SELECT CL.ChildLine.value('(./ZYN:Name)[1]', 'varchar(50)') AS ItemNumber,
CL.ChildLine.query('./ZC:_lines') AS ChildLines
FROM ItemList
CROSS APPLY ItemList.ChildLines.nodes('/ZC:_lines/ZC:ZEstimateLine') AS CL(ChildLine)
)
SELECT ItemNumber, ChildLines
FROM ItemList
GO
然后,您可以使用它们来执行查询:
SELECT CM.Contract, CM.RevisionLevel, CM.CustomerGpId,
Proj.ProjectName,
Line.ItemNumber
FROM dbo.tblContractMaster AS CM
CROSS APPLY dbo.fn_explode_projects(CM.FullContract) Proj
CROSS APPLY dbo.fn_explode_lines(Proj.ChildLines) Line
WHERE Proj.ProjectName IS NOT NULL AND Line.ItemNumber IS NOT NULL
这假设合同不直接包含行 - 所有行必须包含在项目或其他行中。