【问题标题】:Finding Unknown XML Grandchildren Using SQL使用 SQL 查找未知的 XML 孙子
【发布时间】:2014-06-06 13:09:58
【问题描述】:

有没有办法使用 SQL 搜索 XML 节点以查看父节点是否有子节点和孙子节点?我正在尝试测试一些 XML 文件,看看是否有任何未知的孩子:

<form>
  <ItemType>New Regular</ItemType>
  <FirstBuyDate>02/01/2007</FirstBuyDate>
  <FirstShipDate>02/05/2007</FirstShipDate>
  <ItemBrand>Gillette Blade/Razors</ItemBrand>
  <ItemDescription>...</ItemDescription>
  <Size>8.00</Size>
  <InnerOffInvoice />
  <MasterOffInvoice />
  <PalletItems>
    <ID>908402</ID> 
    <PalletShipDate>04/03/13</PalletShipDate>
  </PalletItems>
  <ReviewComments />
</form>

在这个例子中,我知道 PalletItems 有孩子。所以我可以制作表格,相应地插入数据。但是我怎么能确定我已经得到了&lt;form&gt; 的所有孙子孙女呢?如果有像&lt;ItemDescription&gt; 这样的不认识的孩子怎么办 - 我如何找到我不认识的孩子?如何测试所有这些节点以查看 &lt;form&gt; 是否有孙子?

这里的代码告诉我有多少孩子:

SELECT distinct Parent.Items.value('local-name(.)', 'varchar(100)') as 'Item'
    FROM    dbo.FormResults 
    CROSS APPLY xmlformfields.nodes('/form/*') as Parent(Items)

你们有没有找到孙辈的建议? 谢谢!

另外作为旁注 - 有谁知道如何让这个 SELECT 语句按照它们在 xml 中出现的顺序排列子项?目前,当代码抓取孩子时,它将以随机顺序显示在列中:

    Items
1. FirstBuyDate
2. Size
3. ItemType
4. PalletItems... etc. 

我希望它们像这样显示:

    Items:
1. ItemType
2. FirstBuyDate 
3. FirstShipDate
4. ItemBrand... etc. 

---------更新----------

现在我们知道 (/form//*) 将得到子孙,这要感谢 valex

我怎样才能把孩子放在一列,孙子放在下一列?会不会是这样的:

SELECT distinct Parent.Items.value('local-name(.)', 'varchar(100)') as 'Child of Form',
CASE when child.items.value('local-name(.)', 'varchar(100)') IS NULL then NULL ELSE 'Has Child' end as 'Grandchild of Form'
FROM    dbo.FormResults 
CROSS APPLY xmlformfields.nodes('/form/*')  as Parent(Items) 
Cross Apply parent.items.nodes('/form//*')  as child(items)

【问题讨论】:

    标签: sql sql-server xml tsql parent-child


    【解决方案1】:

    不仅要从第一级获取所有节点,请使用 /form//*// 而不是 /form/*

    SELECT distinct Parent.Items.value('local-name(.)', 'varchar(100)') as 'Item'
        FROM    dbo.FormResults 
        CROSS APPLY xmlformfields.nodes('/form//*') as Parent(Items)
    

    SQLFiddle example

    要获取父节点,请在 local-name() 调用中使用语法 ../.。 要在父节点中获取子节点的索引并按其排序,您可以使用XQuery expression

    for $i in . return count(../*[. << $i])
    

    所以最后的查询顺序:

    SELECT distinct 
              Parent.Items.value('local-name(.)', 'varchar(100)') as 'Item',
              Parent.Items.value('local-name(../.)', 'varchar(100)') as 'ParentItem',
              Parent.Items.value('for $i in . return count(../*[. << $i])','int') 
                  as ChildIndex
        FROM    dbo.FormResults 
        CROSS APPLY xmlformfields.nodes('/form//*') as Parent(Items)
        ORDER BY ParentItem,ChildIndex
    

    SQLFiddle example

    【讨论】:

    • 太棒了!有用!非常感谢!你知道我怎么能把孩子放在一列,孙子放在另一列吗? (请参阅我提交的代码中添加的代码)非常感谢!
    • @user3281388 查看答案中的第二个查询。
    • 非常感谢您的帮助!对此,我真的非常感激! :) 这很好用。您是否知道如何让 ('local-name') 按它们在 xml 中的顺序选择元素?由于第一个 xml 子项是 ItemType - 我希望在我的行中排在第一位。但是我的行是随机的,而不是它们在 xml 中的顺序。有什么建议吗?
    • @user3281388 我已经更改了第二个查询,所以请尝试使用它。
    • 执行需要相当长的时间......大约 7 分钟,我还在等待......其他大约需要 3 分钟的时间更少。你认为它应该花那么长时间吗?
    猜你喜欢
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多