【问题标题】:Parse nested xml using sql server使用 sql server 解析嵌套的 xml
【发布时间】:2018-08-28 18:27:23
【问题描述】:

我想使用 SQL 查询解析 XML。下面是查询和 XML。请在下面找到当前结果和预期结果的屏幕截图。它只从嵌套节点中获取一个值。请推荐

DECLARE @xml XML =
'<FileGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <FileGroup>
		<FileName>Test1</FileName>		  
        <Files>
             <File>
			   <FilePath>\\Server\Test1</FilePath>
			   <FileGUID>3006989A-725E-40E8-BAF7-A094CB710AC3</FileGUID>			   
			   <DependentOnFileNames></DependentOnFileNames>				
			</File>
			<File>
				<FilePath>\\Server\Test2</FilePath>
				<FileGUID>A584CE87-CC76-484E-ACE4-53C6CAD27B7F</FileGUID>				
				<DependentOnFileNames></DependentOnFileNames>
			</File>
             <File>
				<FilePath>\\Server\Test3</FilePath>
				<FileGUID>727A6BBE-E820-4431-9958-93D0863F65B8</FileGUID>
				<Comments></Comments>
				<DependentOnFileNames>
					<FileGUID>3006989A-725E-40E8-BAF7-A094CB710AC3</FileGUID>
					<FileGUID>A584CE87-CC76-484E-ACE4-53C6CAD27B7F</FileGUID>
				</DependentOnFileNames>
			</File>
         </Files>
     </FileGroup>
	 <FileGroup>
		<FileName>Test2</FileName>		  
        <Files>
             <File>
			   <FilePath>\\Server\Test4</FilePath>
			   <FileGUID>EA422762-58CD-423D-92D4-1DC18A312F48</FileGUID>			   
			   <DependentOnFileNames></DependentOnFileNames>				
			</File>			
         </Files>  
	  </FileGroup>  
</FileGroups>'



SELECT              
    FileGroup.value('FileName[1]', 'VARCHAR(1000)') FileName,	
	tbl1.Files.value('FilePath[1]', 'VARCHAR(1000)') FilePath,
	tbl2.DependentOnFileNames.value('FileGUID[1]', 'UNIQUEIDENTIFIER') DependentFileGUID
FROM    @xml.nodes('/FileGroups/FileGroup') tbl(FileGroup)
CROSS APPLY tbl.FileGroup.nodes('Files/File') tbl1(Files) 
CROSS APPLY tbl1.Files.nodes('DependentOnFileNames') tbl2(DependentOnFileNames) 

Current Result:

Expected Result:

【问题讨论】:

    标签: sql-server xml


    【解决方案1】:

    您的最后一行存在 2 个问题:(1) 它应该是 OUTER APPLY,因为文件可能没有依赖关系;(2) 您需要更深入一层,进入 DependentOnFileNames/FileGUID 而不是 DependentOnFileNames .应该是:

    OUTER APPLY tbl1.Files.nodes('DependentOnFileNames/FileGUID') tbl2(DependentOnFileNames) 
    

    并相应地修改您的SELECT 子句:

    tbl2.DependentOnFileNames.value('.', 'UNIQUEIDENTIFIER') DependentFileGUID
    

    对于未来的 Google 员工,一些在 SQL Server 中处理 XML 的技巧:

    • 使用nodes() 在 XML 级别展开嵌套元素
    • 使用value() 获取XML 节点的值。 value(...) 中的选择器始终返回一个值数组,即使它是一个 1 的数组。您必须从该数组中仅选择 1 个元素。元素索引从 1 开始。value(.) 例外,它返回一个单例。
    • 使用CROSS APPLY / OUTER APPLY 在 SQL 级别展开嵌套元素。它们的行为类似于 INNER JOIN / LEFT JOIN,只是不需要加入条件。
    • 如果遇到困难,请将 T1.[FileGroup].query('.') 之类的内容放在 SELECT 子句中,然后探索 XML 结构。

    代码:

    SELECT          
                    T1.[FileGroup].value('FileName[1]', 'varchar(30)')      AS FileName
            ,       T2.[File].value('FilePath[1]', 'varchar(500)')          AS FilePath
            ,       T2.[File].value('FileGUID[1]', 'UNIQUEIDENTIFIER')      AS FileGUID
            ,       T3.DependentFileGUID.value('.', 'UNIQUEIDENTIFIER')     AS DependentFileGUID
    FROM            
                    @xml.nodes('FileGroups/FileGroup')                  T1([FileGroup])
    CROSS APPLY     T1.[FileGroup].nodes('Files/File')                  T2([File])
    OUTER APPLY     T2.[File].nodes('DependentOnFileNames/FileGUID')    T3(DependentFileGUID)
    

    【讨论】:

    • 非常感谢!!!感谢提供的提示。这对其他人非常有用。
    • 好答案! +1形成我的身边。只有一个提示:在大多数情况下,在.value() 中使用'.' 并不是最好的主意。您可以阅读this answer 以找到一些详细信息...
    猜你喜欢
    • 2022-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多