3

我对 XPath 和 XQuery 比较陌生。我正在使用存储在名为tblXML. XML 存储在此表中caseID。对于此示例,此值是唯一的。XML 本身存储在标记为 的列中Data

如果你去select * from tblXML where caseID = '12345'你会看到这个:

caseID        data
------        ------
12345         <root><patient><diagnosis preferred_name="diagnosis" tier="1">Melanoma</diagnosis> (XML file stored as blob in database)

如果您要深入研究 XML,它看起来像这样。例如,这是“12345”data列中的 XML:caseID

<root>
    <patient>
        <diagnosis preferred_name="diagnosis" tier="1">Melanoma</diagnosis>
        <month_of_birth preferred_name="month_of_birth" tier="1">02</month_of_birth>
        <day_of_birth preferred_name="day_of_birth" tier="2">01</day_of_birth>
        <year_of_birth preferred_name="year_of_birth" tier="1">1960</year_of_birth>
        <new_tumor_events>
            <month_of_nte preferred_name="month_of_nte" tier="1">12</month_of_nte>
            <day_of_nte preferred_name="day_of_nte" tier="2">30</day_of_nte>
            <year_of_nte preferred_name="year_of_nte" tier="1">1994</year_of_nte>
        </new_tumor_events>
        <follow_ups>
            <follow_up>
                <month_of_fu preferred_name="month_of_fu" tier="1">12</month_of_fu>
                <day_of_fu preferred_name="day_of_fu" tier="2">31</day_of_fu>
                <year_of_fu preferred_name="year_of_fu" tier="1">1995</year_of_fu>
            </follow_up>
            <follow_up>
                <month_of_fu preferred_name="month_of_fu" tier="1">12</month_of_fu>
                <day_of_fu preferred_name="day_of_fu" tier="2">31</day_of_fu>
                <year_of_fu preferred_name="year_of_fu" tier="1">1996</year_of_fu>
            </follow_up>
        </follow_ups>
    </patient>
</root>

目标: 我正在尝试为具有@Tier属性的 XML 文档的所有级别/节点上的所有元素选择所有值"1"。我希望看到每个值都在它自己的行中的一个名为“值”的列中输出,如下所示:

caseID     Value
------     ------
12345      Melanoma
12345      02
12345      1960
12345      12
12345      1994
12345      12
12345      1995
12345      12
12345      1996

这是类似于我正在尝试编写的 SQL:

DECLARE @tier int 
SET @tier = '1' --To search by tier explicitly via variable

    select 
        x.caseID,
    bar.value('(//*[@tier = sql:variable("@tier")])[1]','varchar(max)') as value
from tblXML as x
    CROSS APPLY data.nodes('//*:patient') AS foo(bar)
where
    x.caseID = '12345'
    and x.data.value('(//@tier)[1]', 'varchar(3)') = '1'

这给了我...

case ID        value
------         ------  
12345          Melanoma

...但不是我正在寻找的其他行。

[1]我认为我的困惑集中在我的 CROSS APPLY 语句中的单例和上下文节点所施加的约束上。我不确定如何获取文档中第 1 层的所有内容,而不仅仅是查询找到的第 1 层的第一个实例。

对于这个示例,我知道我的 CROSS APPLY 语句中的上下文节点专注于patientXML 部分,但我希望能够在 XML 树的所有级别上下搜索。我知道//for@Tier让我可以搜索文档的所有级别,但我的上下文节点似乎在某种程度上驱动/限制了我可以搜索到文档的深度。

我的理解是我可以深入研究 XML(follow_up也许?),然后从上到下进行搜索。但是,最深的节点将从 caseID 变为 caseID,从 XML 文档变为 XML 文档。有没有办法将我的 CROSS APPLY 语句通配到给定 XML 文档中最深的节点中,然后@Tier在该文档中查找任何出现,然后检索其相应的值?

我意识到这种方法缺乏优雅并且没有性能。到目前为止,我还没有找到明确的文档来给我正在寻找的结果。

在此先感谢您的帮助。

编辑:我应该指定这个 SQL 将是 SQL Server 中表值函数的核心。

4

4 回答 4

2

定义一个键:

<xsl:key name="t" match="*[@tier]" use="@tier"/>

并使用找到所有 teir=1 元素

<xsl:for-each select="key('t', '1')">
  ....
</xsl:for-each>
于 2013-02-27T16:50:21.757 回答
1

尝试在您的选择中删除单例:

DECLARE @tier int 
SET @tier = '1' --To search by tier explicitly via variable
    select 
        x.caseID,
        bar.value('/string()','varchar(max)')
from tblXML as x
    CROSS APPLY data.nodes('//*[@tier = sql:variable("@tier")]') AS foo(bar)
where
    x.caseID = '12345'

您选择中的 xpath 已经根据匹配的属性值过滤节点,因此您无需在 where 约束中再次执行此操作。xpath 谓词类似于 where。

于 2013-02-27T16:42:14.687 回答
0

您基本上可以从 CROSS APPLY 语句中进行层查找,并在您的选择中获取根的值(“。”作为第一个参数)。

DECLARE @s XML;
SET @s='<root>
    <patient>
        <diagnosis preferred_name="diagnosis" tier="1">Melanoma</diagnosis>
        <month_of_birth preferred_name="month_of_birth" tier="1">02</month_of_birth>
        <day_of_birth preferred_name="day_of_birth" tier="2">01</day_of_birth>
        <year_of_birth preferred_name="year_of_birth" tier="1">1960</year_of_birth>
        <new_tumor_events>
            <month_of_nte preferred_name="month_of_nte" tier="1">12</month_of_nte>
            <day_of_nte preferred_name="day_of_nte" tier="2">30</day_of_nte>
            <year_of_nte preferred_name="year_of_nte" tier="1">1994</year_of_nte>
        </new_tumor_events>
        <follow_ups>
            <follow_up>
                <month_of_fu preferred_name="month_of_fu" tier="1">12</month_of_fu>
                <day_of_fu preferred_name="day_of_fu" tier="2">31</day_of_fu>
                <year_of_fu preferred_name="year_of_fu" tier="1">1995</year_of_fu>
            </follow_up>
            <follow_up>
                <month_of_fu preferred_name="month_of_fu" tier="1">12</month_of_fu>
                <day_of_fu preferred_name="day_of_fu" tier="2">31</day_of_fu>
                <year_of_fu preferred_name="year_of_fu" tier="1">1996</year_of_fu>
            </follow_up>
        </follow_ups>
    </patient>
</root>';

DECLARE @tblXML TABLE(caseID INT PRIMARY KEY,data XML);
INSERT INTO @tblXML(caseID,data)VALUES(12345,@s);

DECLARE @tier INT;
SET @tier=1;

SELECT
    t.caseID,
    node.value('.','NVARCHAR(512)') AS value
FROM
    @tblXML AS t
    CROSS APPLY t.data.nodes('//*[@tier=sql:variable("@tier")]') AS t1n(node)
WHERE
    t.caseID=12345;
于 2014-08-31T08:38:33.727 回答
0

尝试这个:

SELECT  
    x.caseID,
    bar.value('.','varchar(max)') as value
FROM tblXML as x
    CROSS APPLY data.nodes('//*[@tier=1]') AS foo(bar)
于 2014-08-31T04:34:18.563 回答