【问题标题】:How to merge the results of two divergent xpaths for Microsoft SQL Server如何合并 Microsoft SQL Server 的两个不同 xpath 的结果
【发布时间】:2017-02-21 04:19:46
【问题描述】:

我是新手,所以请多多包涵。我有两个 select 语句,其中包含我想要从 Microsoft SQL Server 2016 中的 XML 文档中获得的所有信息。我想将这两个 select 语句的内容组合起来,然后将其变成一个表。问题是 xpath 发散了。我不知道该怎么办。

这是我的第一个查询:

SELECT * 
FROM OPENXML (@hdoc, '/roll/bill', 1)
WITH (
[where] char(5) '../@where',
[session] tinyint '../@session',
[year] smallint '../@year',
roll smallint '../@roll',
[datetime] datetime '../@datetime',
number int)

这是我的第二个查询:

SELECT *
FROM OPENXML (@hdoc, '/roll/voter', 2)
WITH (
    id int '@id',
    [value] char(50) '@value',
    [state] char(2) '@state',
    [category] char(7)'../category',
    [type] varchar(1000)'../type',
    [question] varchar(1000)'../question',
    [result] varchar(20)'../result')

这是我的 xml 文档的婴儿大小版本:

<roll where="house" session="114" year="2015" roll="705" source="house.gov" datetime="2015-12-18T09:49:00-05:00" updated="2016-12-25T10:03:32-05:00" aye="316" nay="113" nv="5" present="0">
<category>passage</category>
<type>On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566</type>
<question>On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566: H R 2029 Making appropriations for military construction, the Department of Veterans Affairs, and related agencies for the fiscal year ending September 30, 2016, and for other purposes</question>
<required>1/2</required>
<result>Passed</result>
<bill session="114" type="h" number="2029" />
<option key="+">Yea</option>
<option key="-">Nay</option>
<option key="P">Present</option>
<option key="0">Not Voting</option>
<voter id="412607" vote="+" value="Yea" state="NC" />
<voter id="400004" vote="+" value="Yea" state="AL" />
<voter id="412615" vote="+" value="Yea" state="CA" />
<voter id="412625" vote="+" value="Yea" state="GA" />
</roll>

如果有人能准确地告诉我我需要做什么以及解释原因,我将不胜感激。

Here is a screenshot of my two select statements and their results

【问题讨论】:

    标签: sql sql-server xml xpath sql-server-2016


    【解决方案1】:

    FROM OPENXML 已过时,不应再使用...(存在罕见的例外情况)。更好地使用真正的 XML 方法。试试这个:

    我假设 XML 的上半部分是 meta-data&lt;voter&gt;elements 是 1:n 相关的work-data。因此,我的结果返回每个选民一行。我希望我没弄错!

    DECLARE @DummyTable TABLE(YourXML XML);
    INSERT INTO @DummyTable VALUES
    (
    N'<roll where="house" session="114" year="2015" roll="705" source="house.gov" datetime="2015-12-18T09:49:00-05:00" updated="2016-12-25T10:03:32-05:00" aye="316" nay="113" nv="5" present="0">
      <category>passage</category>
      <type>On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566</type>
      <question>On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566: H R 2029 Making appropriations for military construction, the Department of Veterans Affairs, and related agencies for the fiscal year ending September 30, 2016, and for other purposes</question>
      <required>1/2</required>
      <result>Passed</result>
      <bill session="114" type="h" number="2029" />
      <option key="+">Yea</option>
      <option key="-">Nay</option>
      <option key="P">Present</option>
      <option key="0">Not Voting</option>
      <voter id="412607" vote="+" value="Yea" state="NC" />
      <voter id="400004" vote="+" value="Yea" state="AL" />
      <voter id="412615" vote="+" value="Yea" state="CA" />
      <voter id="412625" vote="+" value="Yea" state="GA" />
    </roll>'
    );
    

    --查询

    SELECT --first level attributes
           r.value(N'@where',N'nvarchar(max)') AS roll_where
          ,r.value(N'@session',N'int') AS roll_session
          ,r.value(N'@updated',N'datetime') AS roll_updated
    
          --first level elements
          ,r.value(N'(category)[1]',N'nvarchar(max)') AS category
          ,r.value(N'(type)[1]',N'nvarchar(max)') AS [type]
          ,r.value(N'(result)[1]',N'nvarchar(max)') AS result
    
          --second level attributes
          ,r.value(N'(bill/@session)[1]',N'int') AS bill_session
    
          --named choice    
          ,r.value(N'(option[@key="+"])[1]',N'nvarchar(max)') AS option_plus
          ,r.value(N'(option[@key="-"])[1]',N'nvarchar(max)') AS option_minus
          ,r.value(N'(option[@key="P"])[1]',N'nvarchar(max)') AS option_P
          ,r.value(N'(option[@key="0"])[1]',N'nvarchar(max)') AS option_0
    
          --it seems to be, that your "voter" elements are a 1:n related list?
          --therefore I used a second CROSS APPLY with .nodes() to get them row-wise
          ,v.value(N'@id','int') AS voter_id
          ,v.value(N'@vote','nvarchar(max)') AS voter_vote
          ,v.value(N'@value','nvarchar(max)') AS voter_value
          ,v.value(N'@state','nvarchar(max)') AS voter_state
    FROM @DummyTable AS dt
    CROSS APPLY dt.YourXML.nodes(N'roll') AS A(r)
    CROSS APPLY A.r.nodes(N'voter') AS B(v)
    

    结果

    +------------+--------------+-------------------------+----------+--------------------------------------------------------------------------------+--------+--------------+-------------+--------------+----------+------------+----------+------------+-------------+-------------+
    | roll_where | roll_session | roll_updated            | category | type                                                                           | result | bill_session | option_plus | option_minus | option_P | option_0   | voter_id | voter_vote | voter_value | voter_state |
    +------------+--------------+-------------------------+----------+--------------------------------------------------------------------------------+--------+--------------+-------------+--------------+----------+------------+----------+------------+-------------+-------------+
    | house      | 114          | 2016-12-25 15:03:32.000 | passage  | On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566 | Passed | 114          | Yea         | Nay          | Present  | Not Voting | 412607   | +          | Yea         | NC          |
    +------------+--------------+-------------------------+----------+--------------------------------------------------------------------------------+--------+--------------+-------------+--------------+----------+------------+----------+------------+-------------+-------------+
    | house      | 114          | 2016-12-25 15:03:32.000 | passage  | On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566 | Passed | 114          | Yea         | Nay          | Present  | Not Voting | 400004   | +          | Yea         | AL          |
    +------------+--------------+-------------------------+----------+--------------------------------------------------------------------------------+--------+--------------+-------------+--------------+----------+------------+----------+------------+-------------+-------------+
    | house      | 114          | 2016-12-25 15:03:32.000 | passage  | On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566 | Passed | 114          | Yea         | Nay          | Present  | Not Voting | 412615   | +          | Yea         | CA          |
    +------------+--------------+-------------------------+----------+--------------------------------------------------------------------------------+--------+--------------+-------------+--------------+----------+------------+----------+------------+-------------+-------------+
    | house      | 114          | 2016-12-25 15:03:32.000 | passage  | On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566 | Passed | 114          | Yea         | Nay          | Present  | Not Voting | 412625   | +          | Yea         | GA          |
    +------------+--------------+-------------------------+----------+--------------------------------------------------------------------------------+--------+--------------+-------------+--------------+----------+------------+----------+------------+-------------+-------------+
    

    【讨论】:

      【解决方案2】:

      您希望如何组合语句中的列?例如,由于您的第一个语句返回 1 行,而第二个语句返回许多行,因此您可能希望第一个语句中的列与第二个语句中的列一起出现在每一行上。你可以这样做:

      SELECT * 
      FROM OPENXML (@hdoc, '/roll/bill', 1)
      WITH (
      [where] char(5) '../@where',
      [session] tinyint '../@session',
      [year] smallint '../@year',
      roll smallint '../@roll',
      [datetime] datetime '../@datetime',
      number int)
      ,OPENXML (@hdoc, '/roll/voter', 2)
      WITH (
          id int '@id',
          [value] char(50) '@value',
          [state] char(2) '@state',
          [category] char(7)'../category',
          [type] varchar(1000)'../type',
          [question] varchar(1000)'../question',
          [result] varchar(20)'../result')
      

      结果:

      where    session     year    roll    datetime                    number      id          value   state   category    type                                                                                question                                                                                                                                                                                                                                                                    result
      house    114         2015    705     2015-12-18 14:49:00.000     2029        412607      Yea     NC      passage     On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566      On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566: H R 2029 Making appropriations for military construction, the Department of Veterans Affairs, and related agencies for the fiscal year ending September 30, 2016, and for other purposes    Passed
      house    114         2015    705     2015-12-18 14:49:00.000     2029        400004      Yea     AL      passage     On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566      On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566: H R 2029 Making appropriations for military construction, the Department of Veterans Affairs, and related agencies for the fiscal year ending September 30, 2016, and for other purposes    Passed
      house    114         2015    705     2015-12-18 14:49:00.000     2029        412615      Yea     CA      passage     On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566      On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566: H R 2029 Making appropriations for military construction, the Department of Veterans Affairs, and related agencies for the fiscal year ending September 30, 2016, and for other purposes    Passed
      house    114         2015    705     2015-12-18 14:49:00.000     2029        412625      Yea     GA      passage     On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566      On Concurring in Senate Amdt with Amdt Specified in Section 3(a) of H.Res. 566: H R 2029 Making appropriations for military construction, the Department of Veterans Affairs, and related agencies for the fiscal year ending September 30, 2016, and for other purposes    Passed
      

      只要您的第一个语句只返回一行,这将为您提供与您的第二个语句相同的行数。如果您的第一个语句将返回 2 行,而您的第二个语句将返回 4 行,则这将返回 8 行:第一个表中的行和第二个表中的行的所有组合。这称为交叉连接

      如果您希望每个语句的行数超过 1 行,并且有一些明确的方法可以将每个语句中的行关联在一起,那么您需要一个 内连接

      我将在此停止,因为您似乎对 SQL 有所了解,只是对 XML 在其中的工作方式感到困惑。但是,如果您需要更多信息,请在 cmets 中说出来,我会尝试扩展答案。

      【讨论】:

      • 谢谢!这正是我想要的。你说得对,我对 SQL 非常缺乏经验,但交叉连接和内部连接这两个词对我来说实际上很熟悉。我只是没有建立联系,因为我太专注于 XML。我是否正确地认为对于交叉连接来说哪个先出现并不重要,但对于内部连接来说呢?另外,如果我使用的是 SQL 表而不是 xml,那么表的名称将取代 OPENXML,对吗?
      • 不管我的数据如何,交叉连接和内连接不会产生相同的结果吗?
      • 内部连接的顺序也不重要;它是对称的。唯一不对称的连接是 LEFT JOIN 和 RIGHT JOIN。如果连接条件使得内部连接返回更少的行。例如,如果第一个查询有一个 state 列,加入 State=State 将意味着您只会获得状态相同的行。但是,在您在此处显示的特定数据中,没有匹配的列,因此不可能进行内部连接。
      • 是的,如果您使用表,表名将代替 OPENXML 表达式。
      • (他或她……不确定性别,因为“ana ng”是歌名,显然是化名)
      猜你喜欢
      • 1970-01-01
      • 2012-08-09
      • 1970-01-01
      • 2021-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-09
      • 2016-10-27
      相关资源
      最近更新 更多