【问题标题】:Get values from XML using XQuery使用 XQuery 从 XML 中获取值
【发布时间】:2012-12-12 13:25:11
【问题描述】:

我是 T-SQL 和 XQuery 的新手。

我在 DB 中有这样结构的 XML 列

     <GPC xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="...">
  <GP>
    <N>Amount1</N>
    <V i:type="X_AMT">
      <AMT>100001</AMT>
      <X_CODE>Dollar</X_CODE>
    </V>
  </GP>
  <GP>
    <N>Amount2</N>
    <V i:type="X_AMT">
      <AMT>0</AMT>
      <X_CODE />
    </V>
  </GP>
  <GP>
    <N>Amount3</N>
    <V i:type="X_AMT">
      <AMT>100001</AMT>
      <X_CODE>Dollar</X_CODE>
    </V>
  </GP>
  <GP>
    <N>Amount4</N>
    <V i:type="X_AMT">
      <AMT>0</AMT>
      <X_CODE />
    </V>
  </GP>
  <GP>
    <N>Amount5</N>
    <V i:type="X_AMT">
      <AMT>100001</AMT>
      <X_CODE>Dollar</X_CODE>
    </V>
  </GP>
  <GP>
    **<N>NeededAmount</N>**
    <V i:type="Y">
      <DETAILS>
        <REFERENCE>
          <N>**ReferenceName1**</N>
          <OId>111111</OId>
        </REFERENCE>
      </DETAILS>
      <DETAILS>
        <REFERENCE>
          <N>**ReferenceName2**</N>
          <OId>22222</OId>
        </REFERENCE>
      </DETAILS>
    </V>
  </GP>

  ...

  </GPC>

这是我正在使用的 SQL Server 中的查询。 Query 只返回一个名称 - Name1。 但是有两个名字,可以有 100 个名字,我想得到那个名字。

 SELECT v.Content.query(N'declare default element namespace "..."; 
    for $i in (GPC/GP) where ($i/N[1] eq "NeededAmount") return ($i)').value('declare default element namespace "..."; 
    (GP/V/DETAILS/REFERENCE/N)[1]', 'nvarchar(max)') AS NeededName
    FROM DB1.protected.WorkItem as v
    where v.Id = 1111

我的问题是:如何修改它以获取文档中的所有名称?有人可以帮我吗?

提前致谢。

【问题讨论】:

    标签: sql sql-server xml tsql xquery


    【解决方案1】:

    试试这样的:

    ;WITH XMLNAMESPACES(DEFAULT '...')
    SELECT 
        Amount = XTbl.GP.value('(N)[1]', 'nvarchar(100)'),
        NeededName = XTbl2.DetRef.value('(N)[1]', 'nvarchar(200)')
    FROM 
        Table1 AS t
    CROSS APPLY
        t.XmlContent.nodes('/GPC/GP') AS XTbl(GP)
    CROSS APPLY
        XTbl.GP.nodes('V/DETAILS/REFERENCE') AS XTbl2(DetRef)
    WHERE 
        wi.Id = 1111
    

    【讨论】:

    • 感谢回复。我已经在我的尝试下面发布了。您还有其他建议吗?
    • @Olinad:嗯,很明显,您必须使 ;WITH XMLNAMESPACES(DEFAULT '.....') 适应您实际使用的 XML 命名空间 - 您这样做了吗?
    • 同样的事情。是否可以修改 SQL Server 中的查询(上面的查询)以获取所有 OId 的 WHERE 节点为 REFERENCE?类似于 2 用于集合的嵌套循环,但使用 T-SQL 和 XQuery?
    【解决方案2】:

    您需要使用nodes() Transact-SQL XML datatype method 将 xml 分解成行。 nodes() 方法用于 FROM 子句,并为 xml 文档中的每个匹配节点生成 1 行。

    这是一个使用存储在变量中的 xml 的示例:

     DECLARE @x XML
     SET @x = N'     <GPC xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" >
       <GP>
       <GP>
          <N>Amount5</N>
          <V i:type="X_AMT">
            <AMT>100001</AMT>
            <X_CODE>Dollar</X_CODE>
          </V>
       </GP>
       <GP>
          **<N>NeededAmount</N>**
          <V i:type="Y">
            <DETAILS>
               <REFERENCE>
                 <N>**ReferenceName1**</N>
                 <OId>111111</OId>
               </REFERENCE>
            </DETAILS>
            <DETAILS>
               <REFERENCE>
                 <N>**ReferenceName2**</N>
                 <OId>22222</OId>
               </REFERENCE>
            </DETAILS>
          </V>
       </GP>
       </GPC>
     '
    
    
     SELECT x.n.query('.') FROM @x.nodes('/GPC/GP/V/DETAILS/REFERENCE/N') AS x (n)
     /* returns 
     <N>**ReferenceName1**</N>
     <N>**ReferenceName2**</N> */
    

    您还可以使用 CROSS APPLY 来分解表中的 xml 列

     CREATE TABLE #t (id INT, doc XML)
     go
      DECLARE @x XML
     SET @x = N'     <GPC xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" >
       <GP>
          <N>Amount5</N>
          <V i:type="X_AMT">
            <AMT>100001</AMT>
            <X_CODE>Dollar</X_CODE>
          </V>
       </GP>
       <GP>
          **<N>NeededAmount</N>**
          <V i:type="Y">
            <DETAILS>
               <REFERENCE>
                 <N>**ReferenceName1**</N>
                 <OId>111111</OId>
               </REFERENCE>
            </DETAILS>
            <DETAILS>
               <REFERENCE>
                 <N>**ReferenceName2**</N>
                 <OId>22222</OId>
               </REFERENCE>
            </DETAILS>
          </V>
       </GP>
       </GPC>
     '
     INSERT INTO #t (id, doc) VALUES (1, @x)
     INSERT INTO #t (id, doc) VALUES (2, @x)
    
    
     SELECT t.id, x.n.query('.') RefName FROM #t t CROSS APPLY doc.nodes('/GPC/GP/V/DETAILS/REFERENCE/N') AS x (n)
     --returns 4 rows, 2 for each document
     /*
     id            RefName
     1     <N>**ReferenceName1**</N>
     1     <N>**ReferenceName2**</N>
     2     <N>**ReferenceName1**</N>
     2     <N>**ReferenceName2**</N> */
    

    【讨论】:

    • txh 回复。在我对 marc_s 的回答中,我可以像上面那样将列设置为 @x 变量吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-27
    • 1970-01-01
    • 1970-01-01
    • 2015-08-06
    • 1970-01-01
    相关资源
    最近更新 更多