【问题标题】:Choose the XML node if child element exist and based on the value of a child element + SQL Server如果子元素存在并基于子元素的值 + SQL Server 选择 XML 节点
【发布时间】:2020-04-06 22:47:13
【问题描述】:

我只想提取那些具有特定子节点并且该子节点应该具有值的节点。 例如:

   xmlDoc = <Report>
      <Version>
        <RecordId>1</RecordId>
        <Note>abcd</Note>
      </Version>
      <Version>
        <RecordId>2</RecordId>
        <Note>efgh</Note>
        <Rindicator>1</Rindicator>
      </Version>
    <Version>
        <RecordId>3</RecordId>
        <Note>ijkl</Note>
      <Rindicator>1</Rindicator>
      </Version>
    <Version>
        <RecordId>4</RecordId>
        <Note>ijkl</Note>
      <Rindicator>0</Rindicator>
      </Version>
    </Report>

结果应该是

   <Report>
          <Version>
            <RecordId>2</RecordId>
            <Note>efgh</Note>
            <Rindicator>1</Rindicator>
          </Version>
        <Version>
            <RecordId>3</RecordId>
            <Note>ijkl</Note>
          <Rindicator>1</Rindicator>
          </Version>
        </Report>

我尝试了以下但没有得到预期的结果。

DECLARE @RindVal varchar(2) = '1'
 UPDATE #TempTable
 SET xmlDoc.modify('delete /*:Report/*:Version[*:Rindicator != sql:variable("@RindVal")]');

【问题讨论】:

  • 你可以否定 Rindicator 对变量的相等性。这将包括缺少 Rindicator 元素的版本节点:.modify('delete /*:Report/*:Version[not(*:Rindicator = sql:variable("@RindVal"))]');
  • 谢谢你的工作。如果您可以将其作为答案,我可以将其标记为。
  • ..@BumbleBee...:),您可以发布答案(在命名空间通配符下划线)以供参考。它对遇到类似问题的任何人都非常有用。

标签: sql-server xml xpath


【解决方案1】:

查看下面的解决方案。它正在使用 XQuery 及其 FLWOR 表达式。

SQL

-- DDL and sample data population. start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmlDoc XML);
INSERT INTO @tbl (xmlDoc) VALUES
(N'<Report>
    <Version>
        <RecordId>1</RecordId>
        <Note>abcd</Note>
    </Version>
    <Version>
        <RecordId>2</RecordId>
        <Note>efgh</Note>
        <Rindicator>1</Rindicator>
    </Version>
    <Version>
        <RecordId>3</RecordId>
        <Note>ijkl</Note>
        <Rindicator>1</Rindicator>
    </Version>
    <Version>
        <RecordId>4</RecordId>
        <Note>ijkl</Note>
        <Rindicator>0</Rindicator>
    </Version>
</Report>');
-- DDL and sample data population. end

-- before
SELECT * FROM @tbl;

DECLARE @RindVal char(1) = '1';

UPDATE @tbl
SET xmlDoc = xmlDoc.query('<Report>
 {
     for $x in /Report/Version[(Rindicator/text())[1] eq sql:variable("@RindVal")]
     return $x
 }
 </Report>');

 -- after
 SELECT * FROM @tbl;

【讨论】:

  • 谢谢你。您能否指出我在这种方式上遗漏了什么或做错了什么。
  • (1) 我不明白您为什么尝试使用通配符命名空间前缀。 (2) 您可以尝试使用与我对 Rindicator 元素所做的相同的构造。
  • 我正在使用通配符命名空间前缀,因为我在 xml 中有多个命名空间。
  • 您需要了解如何在提出问题时提供最小的可重复样本。命名空间是其中的一部分。
【解决方案2】:

这也应该有效。删除没有 Rindicator 或 Rindicator 值不为 1 的节点(如您的预期输出所示)。

update @XML set data.modify('delete //Version[not(Rindicator[.="1"])]')

【讨论】:

    猜你喜欢
    • 2011-03-04
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多