使用 SQL Server 2005 的 XQuery 选择具有特定属性值或缺少该属性的所有节点

发布于 2024-07-05 01:05:54 字数 2367 浏览 6 评论 0原文

更新:给出一个更彻底的例子。

提供的前两个解决方案正好符合我想要说不做的事情。 我不知道位置,它需要能够查看整个文档树。 因此,按照这些思路,将 /Books/ 指定为上下文的解决方案将不起作用:带有

SELECT x.query('.') FROM @xml.nodes('/Books/*[not(@ID) or @ID = 5]') x1(x)

更好示例的原始问题:

使用 SQL Server 2005 的 XQuery 实现,我需要选择 XML 文档中的所有节点,每个节点一次并保持其原始结构,但前提是它们缺少特定属性,或者该属性具有特定值(通过参数传入)。 查询还必须作用于整个 XML 文档(后代或自身轴),而不是在预定义的深度进行选择。

也就是说,只有当每个单独的节点及其每个祖先都缺少该属性或具有具有单个特定值的属性时,每个单独的节点才会出现在结果文档中。

例如:

如果这是 XML:

    DECLARE @Xml XML
    SET @Xml =
    N'
<Library>
  <Novels>
    <Novel category="1">Novel1</Novel>
    <Novel category="2">Novel2</Novel>
    <Novel>Novel3</Novel>
    <Novel category="4">Novel4</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
      <Volume category="2">G-L</Volume>
      <Volume category="3">M-S</Volume>
      <Volume category="4">T-Z</Volume>
    </Encyclopedia>
  </Encyclopedias>
  <Dictionaries category="1">
    <Dictionary>Webster</Dictionary>
    <Dictionary>Oxford</Dictionary>
  </Dictionaries>
</Library>
    '

类别参数为 1 将导致这样的结果:

<Library>
  <Novels>
    <Novel category="1">Novel1</Novel>
    <Novel>Novel3</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
    </Encyclopedia>
  </Encyclopedias>
  <Dictionaries category="1">
    <Dictionary>Webster</Dictionary>
    <Dictionary>Oxford</Dictionary>
  </Dictionaries>
</Library>

类别参数为 2 将导致这样的结果:

<Library>
  <Novels>
    <Novel category="2">Novel2</Novel>
    <Novel>Novel3</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
      <Volume category="2">G-L</Volume>
    </Encyclopedia>
  </Encyclopedias>
</Library>

我知道 XSLT 非常适合这项工作,但它不是一个选项。 我们必须完全在 SQL Server 2005 中完成此任务。任何不使用 XQuery 的实现也可以,只要它可以完全在 T-SQL 中完成即可。

Update: giving a much more thorough example.

The first two solutions offered were right along the lines of what I was trying to say not to do. I can't know location, it needs to be able to look at the whole document tree. So a solution along these lines, with /Books/ specified as the context will not work:

SELECT x.query('.') FROM @xml.nodes('/Books/*[not(@ID) or @ID = 5]') x1(x)

Original question with better example:

Using SQL Server 2005's XQuery implementation I need to select all nodes in an XML document, just once each and keeping their original structure, but only if they are missing a particular attribute, or that attribute has a specific value (passed in by parameter). The query also has to work on the whole XML document (descendant-or-self axis) rather than selecting at a predefined depth.

That is to say, each individual node will appear in the resultant document only if it and every one of its ancestors are missing the attribute, or have the attribute with a single specific value.

For example:

If this were the XML:

    DECLARE @Xml XML
    SET @Xml =
    N'
<Library>
  <Novels>
    <Novel category="1">Novel1</Novel>
    <Novel category="2">Novel2</Novel>
    <Novel>Novel3</Novel>
    <Novel category="4">Novel4</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
      <Volume category="2">G-L</Volume>
      <Volume category="3">M-S</Volume>
      <Volume category="4">T-Z</Volume>
    </Encyclopedia>
  </Encyclopedias>
  <Dictionaries category="1">
    <Dictionary>Webster</Dictionary>
    <Dictionary>Oxford</Dictionary>
  </Dictionaries>
</Library>
    '

A parameter of 1 for category would result in this:

<Library>
  <Novels>
    <Novel category="1">Novel1</Novel>
    <Novel>Novel3</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
    </Encyclopedia>
  </Encyclopedias>
  <Dictionaries category="1">
    <Dictionary>Webster</Dictionary>
    <Dictionary>Oxford</Dictionary>
  </Dictionaries>
</Library>

A parameter of 2 for category would result in this:

<Library>
  <Novels>
    <Novel category="2">Novel2</Novel>
    <Novel>Novel3</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
      <Volume category="2">G-L</Volume>
    </Encyclopedia>
  </Encyclopedias>
</Library>

I know XSLT is perfectly suited for this job, but it's not an option. We have to accomplish this entirely in SQL Server 2005. Any implementations not using XQuery are fine too, as long as it can be done entirely in T-SQL.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

维持三分热 2024-07-12 01:05:54

这个问题不太清楚,但这就是你要找的吗?

DECLARE @Xml AS XML
        SET @Xml =
        N'
        <Books>
                <Book ID="1">Book1</Book>
                <Book ID="2">Book2</Book>
                <Book ID="3">Book3</Book>
                <Book>Book4</Book>
                <Book ID="5">Book5</Book>
                <Book ID="6">Book6</Book>
                <Book>Book7</Book>
                <Book ID="8">Book8</Book>
        </Books>
        '
DECLARE @BookID AS INT
SET @BookID = 5
DECLARE @Result AS XML

SET @result = (SELECT @xml.query('//Book[not(@ID) or @ID = sql:variable("@BookID")]'))
SELECT @result

The question is not really clear, but is this what you're looking for?

DECLARE @Xml AS XML
        SET @Xml =
        N'
        <Books>
                <Book ID="1">Book1</Book>
                <Book ID="2">Book2</Book>
                <Book ID="3">Book3</Book>
                <Book>Book4</Book>
                <Book ID="5">Book5</Book>
                <Book ID="6">Book6</Book>
                <Book>Book7</Book>
                <Book ID="8">Book8</Book>
        </Books>
        '
DECLARE @BookID AS INT
SET @BookID = 5
DECLARE @Result AS XML

SET @result = (SELECT @xml.query('//Book[not(@ID) or @ID = sql:variable("@BookID")]'))
SELECT @result
梦里°也失望 2024-07-12 01:05:54

从你的例子中我不清楚你实际上想要实现什么目标。 您是否想要返回一个新的 XML,其中除满足条件的节点外的所有节点均被删除? 如果是,那么这看起来像是 XSLT 转换的工作,我认为它不是内置在 MSSQL 2005 中的(可以作为 UDF 添加: http://www.topxml.com/rbnews/SQLXML/ re-23872_Performing-XSLT-Transforms-on-XML-Data-Stored-in-SQL-Server-2005.aspx)。

如果您只需要返回节点列表,那么您可以使用此表达式:

//Book[not(@ID) or @ID = 5]

但我的印象是这不是您所需要的。 如果您能提供一个更清晰的示例,将会有所帮助。

编辑:这个例子确实更清楚了。 我能找到的最好的办法是:

SET @Xml.modify('delete(//*[@category!=1])')
SELECT @Xml

这个想法是从 XML 中删除所有不需要的节点,这样就保留了原始结构和所需的节点。 我用你的两个例子进行了测试,它产生了想要的结果。

然而modify有一些限制 - 似乎你不能在 select 语句中使用它,它必须就地修改数据。 如果您需要通过选择返回此类数据,您可以使用临时表来复制原始数据,然后更新该表。 像这样:

INSERT INTO #temp VALUES(@Xml)
UPDATE #temp SET data.modify('delete(//*[@category!=2])')

希望有帮助。

It's not clear for me from your example what you're actually trying to achieve. Do you want to return a new XML with all the nodes stripped out except those that fulfill the condition? If yes, then this looks like the job for an XSLT transform which I don't think it's built-in in MSSQL 2005 (can be added as a UDF: http://www.topxml.com/rbnews/SQLXML/re-23872_Performing-XSLT-Transforms-on-XML-Data-Stored-in-SQL-Server-2005.aspx).

If you just need to return the list of nodes then you can use this expression:

//Book[not(@ID) or @ID = 5]

but I get the impression that it's not what you need. It would help if you can provide a clearer example.

Edit: This example is indeed more clear. The best that I could find is this:

SET @Xml.modify('delete(//*[@category!=1])')
SELECT @Xml

The idea is to delete from the XML all the nodes that you don't need, so you remain with the original structure and the needed nodes. I tested with your two examples and it produced the wanted result.

However modify has some restrictions - it seems you can't use it in a select statement, it has to modify data in place. If you need to return such data with a select you could use a temporary table in which to copy the original data and then update that table. Something like this:

INSERT INTO #temp VALUES(@Xml)
UPDATE #temp SET data.modify('delete(//*[@category!=2])')

Hope that helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文