我在SQL 2008数据库中使用类似于以下内容的XML,存储在XML字段中。如果某个节点存在于XML的特定部分,我想返回一个真或假的指示。
<root>
<node attribute1='value1' attribute2='value2'>
<sub1 name='ID' value="1" />
<sub2 name='project' value="abc" />
<sub3 name='Lead' value="John" />
</node>
<entry attribute1='value1' attribute2='value2'>
<message>start</message>
</entry>
<entry attribute1='value1' attribute2='value2'>
<attribute name='project' value='done'>
</entry>
<node attribute1='value1'>
<sub1 name='ID' value="2" />
<sub2 name='project' value="abc" />
<sub3 name='Lead' value="John" />
</node>
<entry attribute1='value1' attribute2='value2'>
<message>start</message>
</entry>
<node attribute1='value1'>
<sub1 name='ID' value="3" />
<sub2 name='project' value="abc" />
<sub3 name='Lead' value="John" />
</node>
<entry attribute1='value1' attribute2='value2'>
<message>start</message>
</entry>
<node attribute1='value1'>
<sub1 name='ID' value="4" />
<sub2 name='project' value="abc" />
<sub3 name='Lead' value="John" />
</node>
<entry attribute1='value1' attribute2='value2'>
<message>start</message>
</entry>
<entry attribute1='value1' attribute2='value2'>
<attribute name='project' value='done'>
</entry>
</root>
正如您将注意到的,<attribute>
节点在具有“ID”的节点之后可能会或可能不会发生。在这个例子中,你可以在第一个和第四个“部分”中看到它缺少一个更好的术语。
使用以下表格结构:
ID (PK)
EventID (FK)
RawXML (XML)
Created (datetime)
以下是我到目前为止的SQL / xQuery摘录:
WITH XMLNAMESPACES(
'http://www.w3.org/2001/XMLSchema-instance' as xsi,
),
t1 as(
SELECT distinct
x.EventId
, c.value ('(//node/sub[@name=''ID'']/@value)[1]', 'nvarchar(max)') as ID
, c.value ('(//node/sub[@name=''ID''][1][descendant::attribute/@name=''project''])[1]', 'nvarchar(max)' ) as Exists
FROM
Table1 x
CROSS APPLY
RawXML.nodes('./.') as t(c)
)
select distinct
t1.ID
, t1.Exists
from t1
我将运行脚本4次或更多次(在每次运行之前递增所有单例值)
对于给定的XML,我需要在运行查询4次后得到以下结果: (不会知道ID的值,所以我不能在查询中使用它们)
ID Exists
---- -------
1 true
2 false
3 false
4 true
有了SQL,我没有得到任何错误,但它需要永远(超过45分钟),我还没有让它完成。解析XML真的不需要这么长时间。
更新:我限制了我的查询,以确保它只解析一行(一个XML文件),并在57秒内完成。但是,对于ID 1和ID 2,我得到了'0'的结果,当我应该为ID 1设置'1'时。
我相信你们大多数人都知道SQL Server不支持跟随兄弟等,所以不幸的是,这不是一个选择。
仅供参考,我已成功使用它来查找'Project'的两个实例,但它忽略了xml中的位置。:
c.value ('(//node[descendant::attribute/@name=''Project''])[1]', 'nvarchar(max)' ) as TrueFalse
基本上,我需要知道名称='Project'的节点是否存在名称='ID'BUT的节点之后,名称为'ID'的节点的下一个实例
答案 0 :(得分:2)
您的XML中存在一些错误,并且根据您使用的查询判断我也更改了子节点。
您可以使用row_number()
枚举您的ID和项目节点,然后使用常规SQL而不是XQuery检查“下一行”是项目节点还是ID行。
-- Temp table to hold the extracted values from the XML
create table #C
(
rn int primary key,
ID int
);
-- Get the enumerated rows with ID.
-- project nodes will have NULL in ID
insert into #C
select row_number() over(order by T.N) as rn,
T.N.value('sub[@name = "ID"][1]/@value', 'int') as ID
from table1
cross apply RawXML.nodes('/root/*[sub/@name = "ID" or attribute/@name = "project"]') as T(N)
-- Get the ID's and check if the next row is a project node
select C1.ID,
case when exists (
select *
from #C as C2
where C1.rn + 1 = C2.rn and
C2.ID is null
)
then 1
else 0
end as [Exists]
from #C as C1
where C1.ID is not null;
drop table #C;
你可以在没有使用CTE的临时表的情况下进行,但我怀疑临时表版本会更快。
with C as
(
select row_number() over(order by T.N) as rn,
T.N.value('sub[@name = "ID"][1]/@value', 'int') as ID
from table1
cross apply RawXML.nodes('/root/*[sub/@name = "ID" or attribute/@name = "project"]') as T(N)
)
select C1.ID,
case when exists (
select *
from C as C2
where C1.rn + 1 = C2.rn and
C2.ID is null
)
then 1
else 0
end as [Exists]
from C as C1
where C1.ID is not null;