Вы очень близки.Я думаю, все, что вам нужно сделать, это использовать обновленную версию из вашего комментария и изменить свой второй CROSS APPLY на следующее:
CROSS APPLY Proj.p.nodes('.//ZC:_lines/ZC:ZEstimateLine') as Line(l)
При этом используется тот же дополнительный слеш, который вы обнаружили ранее, чтобы откатить и найти все строки..
Возможно, вы захотите проверить это на своих данных, но с вашим образцом оно работает корректно.
РЕДАКТИРОВАТЬ :
Хорошо, я думаю, что у меня есть это сейчас.Это существенно сложнее, и хотя я пытался сделать это с помощью рекурсивных 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
Это предполагает, что контракт не содержит строк напрямую - всестроки должны содержаться проектом или другой строкой.