跟踪SQL Server中XML节点的流
我在SQL Server中有一个跟踪SQL Server中XML节点的流,sql,sql-server,xml,Sql,Sql Server,Xml,我在SQL Server中有一个进程表,如下所示: workflowXML列具有如下值: 样本1: <process> <Event type="start" id="StartEvent_1"> <outgoing>SequenceFlow_0h5l5vu</outgoing> </Event> <Flow type="s
进程
表,如下所示:
workflowXML
列具有如下值:
样本1:
<process>
<Event type="start" id="StartEvent_1">
<outgoing>SequenceFlow_0h5l5vu</outgoing>
</Event>
<Flow type="sequence"
id="SequenceFlow_0h5l5vu"
sourceRef="StartEvent_1"
targetRef="Task_1qc93ha"/>
<Flow type="sequence"
id="SequenceFlow_120gi3p"
sourceRef="Task_1qc93ha"
targetRef="Task_0x1pjee"/>
<Task type="service" id="Task_1qc93ha">
<incoming>SequenceFlow_0h5l5vu</incoming>
<outgoing>SequenceFlow_120gi3p</outgoing>
</Task>
<Task type="user" id="Task_0x1pjee">
<incoming>SequenceFlow_120gi3p</incoming>
</Task>
</process>
<process id="Process_1" isExecutable="false">
<Event type="start" id="StartEvent_142xowk">
<outgoing>SequenceFlow_03yocm5</outgoing>
</Event>
<Flow type="sequence"
id="SequenceFlow_03yocm5"
sourceRef="StartEvent_142xowk"
targetRef="Task_12g1q69"/>
<Task type="user" id="Task_0x1pjee">
<incoming>SequenceFlow_120gi3p</incoming>
</Task>
<Task type="user" id="Task_12g1q69">
<incoming>SequenceFlow_03yocm5</incoming>
</Task>
</process>
如果有人能解释这个问题的解决方案,那将非常有帮助
谢谢。我希望我没有弄错: 从type=“start”开始,沿着层次结构走下去,其中out数据是下一个节点的Id。此行深度未定义,应以type=“user”的节点结束 您的第二个示例有两个type=“user”的任务,但其中只有一个被引用为链上更高节点中的out数据 我的示例将使用额外的
EXISTS
子句过滤第二个
第一个CTE DerivedTable包含一个查询,您也可以使用它。它将以表格形式显示全部信息
第二个CTE是递归的,从start开始并沿链向下遍历。列秩是链的顺序
第三个CTE添加了反向排名,因为您似乎只对最后一项感兴趣。您可以通过获取此信息,其中RevRank=1
DECLARE @process TABLE(ID INT IDENTITY, workflowXML XML);
INSERT INTO @process(workflowXML) VALUES
('<process>
<Event type="start" id="StartEvent_1">
<outgoing>SequenceFlow_0h5l5vu</outgoing>
</Event>
<Flow type="sequence"
id="SequenceFlow_0h5l5vu"
sourceRef="StartEvent_1"
targetRef="Task_1qc93ha"/>
<Flow type="sequence"
id="SequenceFlow_120gi3p"
sourceRef="Task_1qc93ha"
targetRef="Task_0x1pjee"/>
<Task type="service" id="Task_1qc93ha">
<incoming>SequenceFlow_0h5l5vu</incoming>
<outgoing>SequenceFlow_120gi3p</outgoing>
</Task>
<Task type="user" id="Task_0x1pjee">
<incoming>SequenceFlow_120gi3p</incoming>
</Task>
</process>')
,('<process id="Process_1" isExecutable="false">
<Event type="start" id="StartEvent_142xowk">
<outgoing>SequenceFlow_03yocm5</outgoing>
</Event>
<Flow type="sequence"
id="SequenceFlow_03yocm5"
sourceRef="StartEvent_142xowk"
targetRef="Task_12g1q69"/>
<Task type="user" id="Task_0x1pjee">
<incoming>SequenceFlow_120gi3p</incoming>
</Task>
<Task type="user" id="Task_12g1q69">
<incoming>SequenceFlow_03yocm5</incoming>
</Task>
</process>');
结果(您的预期输出为RevRank=1):
更新:你的评论
我使用您评论中的XML测试了我的查询:
INSERT INTO @process(workflowXML) VALUES
('<process>
<Event type="start" id="e1">
<outgoing>s1</outgoing>
</Event>
<Flow type="sequence" id="s1" sourceRef="e1" targetRef="t1" />
<Flow type="sequence" id="s3" sourceRef="t1" targetRef="t2" />
<Task type="user" id="t3">
<incoming>s2</incoming>
</Task>
<Task type="user" id="t1">
<incoming>s1</incoming>
<outgoing>s3</outgoing>
</Task>
<Flow type="sequence" id="s2" sourceRef="t2" targetRef="t3" />
<Task type="service" id="t2">
<incoming>s3</incoming>
<outgoing>s2</outgoing>
</Task>
</process>');
如果我正确理解了逻辑,我的查询就可以正常工作:
- 事件id=e1指向s1
- 流s1指向t1
- 任务t1指向s3
- 流s3指向t2
- 任务t2指向s2
- 流s2指向t3
- 任务t3结束了
ReverseRank
-CTE,并将最后的选择设置为like
SELECT t.*
FROM recCTE AS t
WHERE t.[Rank]<=ISNULL((SELECT MIN(x.[Rank]) FROM recCTE AS x WHERE x.tblID=t.tblID AND x.[Type]='user' AND x.[Name]='Task'),999)
ORDER BY t.tblID,t.[Rank]
选择t.*
从记录为t
其中t.[Rank]我用这个查询解决了这个问题。如果有更好的问题,很乐意指出
--================== @tempProcess(result)=========================
declare @tempProcess table
(
ID int,
FirstTaskID nvarchar(max)
)
--===============================================================
declare @currentType nvarchar(max)
declare @FirstUserTaskID nvarchar(max)
declare @outgoing nvarchar(max)
declare @elementID nvarchar(max)
--================================================================
declare @ID int
declare @WorkflowXML xml
declare cur CURSOR LOCAL for
select ID, WorkflowXML from Process
open cur
fetch next from cur into @ID, @WorkflowXML
while @@FETCH_STATUS = 0 BEGIN
set @currentType = '$$$$$'--defult value
set @elementID = '$$$$$'--defult value
select @outgoing =
(
select p.WorkflowXML.value('(process/Event[@type=''start'']/outgoing)[1]','nvarchar(max)')
from Process as p
where ID = @ID
)
--====================== while(Tracking flow) ========================
while (@currentType != 'user')
begin
------- Get target element with Flow Id (outgoing)-----------------
select @elementID = (
select t.c.value('@id','nvarchar(max)')
from Process as p
cross apply p.WorkflowXML.nodes('process/*') AS t(c)
where ID = @ID
and
t.c.value('incoming[1]','nvarchar(max)') = @outgoing
)
-------------- Get Type of current element ------------------------
select @currentType =
(
select t.c.value('@type','nvarchar(max)')
from Process as p
cross apply p.WorkflowXML.nodes('process/*') AS t(c)
where ID = @ID
and
t.c.value('@id','nvarchar(max)') = @elementID
)
-------------- Get outgoing of current element ---------------------
select @outgoing =
(
select t.c.value('(outgoing)[1]','nvarchar(max)')
from Process as p
cross apply p.WorkflowXML.nodes('process/*') AS t(c)
where ID = @ID
and
t.c.value('@id','nvarchar(max)') = @elementID
)
---------------------------------------------------------------
end
--========================= End while ========================
if(@elementID != '$$$$$')
begin
set @FirstUserTaskID = @elementID
-- Insert to @tempProcess
INSERT INTO @tempProcess
SELECT @ID,@FirstUserTaskID
end
--select @FirstUserTaskID
fetch next from cur into @ID,@WorkflowXML
END
select * from @tempProcess
close cur
deallocate cur
您不想将数据存储在适当的表中而不是XML中吗?@EvaldasBuinauskas否,我需要以XML格式存储数据。根据所使用的方法,XML已经有了检索重复节点('/'
)的方法或在水平列中返回特定重复节点的方法('
),非常感谢您的回答,我贴出了答案。请看这个。@AliSoltani你试过我的方法吗?你的问题-如果它返回你需要的-是可以的,但是一个程序性的方法。对于SQL,建议始终遵循基于集合的路径。。。我的查询将返回整个流链,并且应该比您的查询快得多。您的方法的主要问题是,您一次又一次地从XML中提取一段数据,而我的方法是一次读取所有数据<代码>光标
和,而
-如果可能,应该避免循环。。。我建议尝试一下我的方法,并决定什么对你更有利……我测试你的查询。我认为这样更好。但有一个问题。有时,节点中会有几个传入和传出节点。在这种情况下,您的代码是否正常工作?@AliSoltani请尝试一下。。。递归方法应该是一个完整的树。但是我不知道你的数据我已经用这个查询再次测试了你的查询。结果不正确。
INSERT INTO @process(workflowXML) VALUES
('<process>
<Event type="start" id="e1">
<outgoing>s1</outgoing>
</Event>
<Flow type="sequence" id="s1" sourceRef="e1" targetRef="t1" />
<Flow type="sequence" id="s3" sourceRef="t1" targetRef="t2" />
<Task type="user" id="t3">
<incoming>s2</incoming>
</Task>
<Task type="user" id="t1">
<incoming>s1</incoming>
<outgoing>s3</outgoing>
</Task>
<Flow type="sequence" id="s2" sourceRef="t2" targetRef="t3" />
<Task type="service" id="t2">
<incoming>s3</incoming>
<outgoing>s2</outgoing>
</Task>
</process>');
+-------+-------+----------+----+------+------+------+---------+
| tblID | Name | Type | Id | In | Out | Rank | RevRank |
+-------+-------+----------+----+------+------+------+---------+
| 1 | Event | start | e1 | NULL | s1 | 1 | 7 |
+-------+-------+----------+----+------+------+------+---------+
| 1 | Flow | sequence | s1 | e1 | t1 | 2 | 6 |
+-------+-------+----------+----+------+------+------+---------+
| 1 | Task | user | t1 | s1 | s3 | 3 | 5 |
+-------+-------+----------+----+------+------+------+---------+
| 1 | Flow | sequence | s3 | t1 | t2 | 4 | 4 |
+-------+-------+----------+----+------+------+------+---------+
| 1 | Task | service | t2 | s3 | s2 | 5 | 3 |
+-------+-------+----------+----+------+------+------+---------+
| 1 | Flow | sequence | s2 | t2 | t3 | 6 | 2 |
+-------+-------+----------+----+------+------+------+---------+
| 1 | Task | user | t3 | s2 | NULL | 7 | 1 |
+-------+-------+----------+----+------+------+------+---------+
SELECT t.*
FROM recCTE AS t
WHERE t.[Rank]<=ISNULL((SELECT MIN(x.[Rank]) FROM recCTE AS x WHERE x.tblID=t.tblID AND x.[Type]='user' AND x.[Name]='Task'),999)
ORDER BY t.tblID,t.[Rank]
--================== @tempProcess(result)=========================
declare @tempProcess table
(
ID int,
FirstTaskID nvarchar(max)
)
--===============================================================
declare @currentType nvarchar(max)
declare @FirstUserTaskID nvarchar(max)
declare @outgoing nvarchar(max)
declare @elementID nvarchar(max)
--================================================================
declare @ID int
declare @WorkflowXML xml
declare cur CURSOR LOCAL for
select ID, WorkflowXML from Process
open cur
fetch next from cur into @ID, @WorkflowXML
while @@FETCH_STATUS = 0 BEGIN
set @currentType = '$$$$$'--defult value
set @elementID = '$$$$$'--defult value
select @outgoing =
(
select p.WorkflowXML.value('(process/Event[@type=''start'']/outgoing)[1]','nvarchar(max)')
from Process as p
where ID = @ID
)
--====================== while(Tracking flow) ========================
while (@currentType != 'user')
begin
------- Get target element with Flow Id (outgoing)-----------------
select @elementID = (
select t.c.value('@id','nvarchar(max)')
from Process as p
cross apply p.WorkflowXML.nodes('process/*') AS t(c)
where ID = @ID
and
t.c.value('incoming[1]','nvarchar(max)') = @outgoing
)
-------------- Get Type of current element ------------------------
select @currentType =
(
select t.c.value('@type','nvarchar(max)')
from Process as p
cross apply p.WorkflowXML.nodes('process/*') AS t(c)
where ID = @ID
and
t.c.value('@id','nvarchar(max)') = @elementID
)
-------------- Get outgoing of current element ---------------------
select @outgoing =
(
select t.c.value('(outgoing)[1]','nvarchar(max)')
from Process as p
cross apply p.WorkflowXML.nodes('process/*') AS t(c)
where ID = @ID
and
t.c.value('@id','nvarchar(max)') = @elementID
)
---------------------------------------------------------------
end
--========================= End while ========================
if(@elementID != '$$$$$')
begin
set @FirstUserTaskID = @elementID
-- Insert to @tempProcess
INSERT INTO @tempProcess
SELECT @ID,@FirstUserTaskID
end
--select @FirstUserTaskID
fetch next from cur into @ID,@WorkflowXML
END
select * from @tempProcess
close cur
deallocate cur