我对XPath和XQuery相对较新。我正在使用存储在名为tblXML
的表中的XML。
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,它看起来就像这样。例如,这是data
'12345'的caseID
列中的XML:
<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
属性为"1"
的XML文档的所有级别/节点选择所有元素的所有值。我想看到每个值都在它自己的行中输出一个名为'Value'的列,如下所示:
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语句中的上下文节点集中在XML的patient
部分,但我希望能够在XML树的所有级别上下搜索。我知道//
@Tier
允许我在文档的所有级别进行搜索,但我的上下文节点似乎在某种程度上推动/约束我可以搜索的文档的深度。
我的理解是我可以深入研究XML(也许是follow_up
?),然后从上到下进行搜索。但是,最深的节点将从caseID更改为caseID和XML文档到XML文档。有没有办法将我的CROSS APPLY语句通配到给定XML文档中最深的节点,然后在该文档中查找@Tier
的任何出现,然后检索其对应的值?
我意识到这种方法缺乏优雅,并且不具备高效性。到目前为止,我还没有找到明确的文档给我正在寻找的结果。
提前感谢您的帮助。
编辑:我应该指定这个SQL将是SQL Server中表值函数的核心。
答案 0 :(得分:2)
定义一个键:
<xsl:key name="t" match="*[@tier]" use="@tier"/>
并使用
查找所有tier = 1个元素<xsl:for-each select="key('t', '1')">
....
</xsl:for-each>
答案 1 :(得分: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'
select中的xpath已根据匹配的属性值过滤节点,因此您无需在where约束中再次执行此操作。 xpath谓词类似于where。
答案 2 :(得分:0)
试试这个:
SELECT
x.caseID,
bar.value('.','varchar(max)') as value
FROM tblXML as x
CROSS APPLY data.nodes('//*[@tier=1]') AS foo(bar)
答案 3 :(得分:0)
您基本上可以从CROSS APPLY语句执行层查找,并在select('。'作为第一个参数)中获取root的值。
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;