我有这个SQL查询:
DECLARE @process TABLE(ID INT IDENTITY, workflowXML XML, Name nvarchar(250),Description nvarchar(MAX));
INSERT INTO @process(workflowXML,Name,Description) VALUES
('<process>
<Event type="start" id="StartEvent_1">
<outgoing>SequenceFlow_1uj46ib</outgoing>
</Event>
<Task type="service" id="Task_0uurv2v">
<incoming>SequenceFlow_1uj46ib</incoming>
<outgoing>SequenceFlow_051szgj</outgoing>
</Task>
<Task type="user" id="Task_1yh7nak">
<incoming>SequenceFlow_051szgj</incoming>
<TaskUsers>
<TaskUser RoleName="myFirstRole" />
<TaskUser RoleName="mySecondRole" />
</TaskUsers>
</Task>
</process>'
,'Process1'
,'test Process 1')
,('<process>
<Event type="start" id="StartEvent_1" name="Start">
<outgoing>SequenceFlow_0z7u86p</outgoing>
<outgoing>SequenceFlow_1onkt3z</outgoing>
</Event>
<Task type="service" id="Task_0a7vu1x">
<incoming>SequenceFlow_108ajnm</incoming>
<incoming>SequenceFlow_1onkt3z</incoming>
<outgoing>SequenceFlow_01clcmz</outgoing>
</Task>
<Task type="user" id="Task_00ijt4n">
<incoming>SequenceFlow_17q1ecq</incoming>
<incoming>SequenceFlow_0q9j3et</incoming>
<outgoing>SequenceFlow_1ygvv8b</outgoing>
<outgoing>SequenceFlow_02glv1g</outgoing>
</Task>
<Task type="service" id="Task_1rnuz4y">
<incoming>SequenceFlow_1ygvv8b</incoming>
<incoming>SequenceFlow_0z7u86p</incoming>
<outgoing>SequenceFlow_108ajnm</outgoing>
<outgoing>SequenceFlow_17q1ecq</outgoing>
<outgoing>SequenceFlow_075iuj9</outgoing>
</Task>
<Task type="user" id="Task_1d4ykor">
<incoming>SequenceFlow_01clcmz</incoming>
<incoming>SequenceFlow_075iuj9</incoming>
<incoming>SequenceFlow_1djp3tu</incoming>
<outgoing>SequenceFlow_0q9j3et</outgoing>
<TaskUsers>
<TaskUser RoleName="myFirstRole" />
<TaskUser RoleName="mySecondRole" />
</TaskUsers>
</Task>
<Task type="user" id="Task_1sembw4">
<incoming>SequenceFlow_02glv1g</incoming>
<outgoing>SequenceFlow_1djp3tu</outgoing>
<TaskUsers>
<TaskUser RoleName="myFirstRole" />
<TaskUser RoleName="mySecondRole" />
</TaskUsers>
</Task>
</process>'
,'Process2'
,'test Process 2')
,('<process>
<Event type="start" id="StartEvent_0bivq0x">
<outgoing>SequenceFlow_0q5ik20</outgoing>
<outgoing>SequenceFlow_147xk2x</outgoing>
</Event>
<Task type="service" id="Task_141buye">
<incoming>SequenceFlow_0q5ik20</incoming>
<incoming>SequenceFlow_0wg37hn</incoming>
<outgoing>SequenceFlow_1pvpyhe</outgoing>
<outgoing>SequenceFlow_10is4pe</outgoing>
</Task>
<Task type="service" id="Task_1n3p00i" >
<incoming>SequenceFlow_147xk2x</incoming>
<incoming>SequenceFlow_10is4pe</incoming>
<outgoing>SequenceFlow_18ks1jr</outgoing>
<outgoing>SequenceFlow_08gxini</outgoing>
</Task>
<Task type="user" id="Task_0olxqpp">
<incoming>SequenceFlow_1pvpyhe</incoming>
<outgoing>SequenceFlow_03eekq0</outgoing>
</Task>
<Task type="user" id="Task_0zjgfkf">
<incoming>SequenceFlow_18ks1jr</incoming>
<incoming>SequenceFlow_03eekq0</incoming>
<outgoing>SequenceFlow_0wg37hn</outgoing>
<TaskUsers>
<TaskUser RoleName="mythirdRole" />
</TaskUsers>
</Task>
<Task type="service" id="Task_1q71efy">
<incoming>SequenceFlow_08gxini</incoming>
</Task>
</process>'
,'Process3'
,'test Process 3')
;
WITH DerivedTable AS
(
SELECT prTbl.ID AS tblID
,nd.value('local-name(.)','nvarchar(max)') AS NodeName
,nd.value('@type','nvarchar(max)') AS [Type]
,nd.value('@id','nvarchar(max)') AS Id
,nd.query('.') AS Task
,prTbl.Name AS [Name]
,prTbl.Description AS [Description]
FROM @process AS prTbl
CROSS APPLY prTbl.workflowXML.nodes('process') AS A(pr)
CROSS APPLY pr.nodes('*') AS B(nd)
)
,AllIncoming AS
(
SELECT tblId
,NodeName
,[Type]
,Id
,[Name]
,[Description]
,i.value('.','nvarchar(max)') AS [Target]
FROM DerivedTable
CROSS APPLY Task.nodes('Task/incoming') AS A(i)
WHERE NodeName='Task'
)
,recCTE AS
(
SELECT tblID,NodeName,[Type],Id,[Name],[Description],Task,1 AS Step,' | ' +CAST(Id AS NVARCHAR(MAX)) AS NodePath
FROM DerivedTable
WHERE [Type]='start'
UNION ALL
SELECT nxt.tblID,nxt.NodeName,nxt.[Type],nxt.Id,nxt.[Name],nxt.Description,nxt.Task,r.Step+1,r.NodePath + ' | ' + nxt.Id
FROM recCTE AS r
INNER JOIN DerivedTable AS nxt ON nxt.Id IN(SELECT x.Id
FROM AllIncoming AS x
WHERE x.[Target] IN (SELECT o.value('.','nvarchar(max)')
FROM r.Task.nodes('*/outgoing') AS A(o)
)
)
WHERE r.[Type]<>'user'
AND r.NodePath NOT LIKE '%| ' + nxt.Id + '%'
AND r.Step<=10
)
select a.tblID as ProcessID,[Name],[Description],a.NodePath,a.Id as TaskID
from
(
SELECT t.tblID
,t.[Name]
,t.Description
,t.NodePath
,t.Id
FROM recCTE AS t
WHERE t.[Type]='user'
AND t.Step<=ISNULL((SELECT MIN(x.Step) FROM recCTE AS x WHERE x.tblID=t.tblID AND x.[Type]='user' AND x.NodeName='Task'),10000)
) a
ORDER BY a.tblID
这将返回从开始事件(Task
)可以看到第一个节点的Event type="start"
个节点。 NodePath
解释了从开始事件到目标节点的路径。
此查询的结果如下:
我需要从RoleName
<TaskUsers>
<TaskUser RoleName="myFirstRole" />
<TaskUser RoleName="mySecondRole" />
</TaskUsers>
存在于SplitbyDelimiter
函数的输出中。
SplitbyDelimiter
函数按,
分割字符串。例如:
select * from SplitbyDelimiter('myFirstRole,mySecondRole',',')
返回
我编辑了DerivedTable
这样的部分:
WITH DerivedTable AS
(
SELECT prTbl.ID AS tblID
,nd.value('local-name(.)','nvarchar(max)') AS NodeName
,nd.value('@type','nvarchar(max)') AS [Type]
,nd.value('@id','nvarchar(max)') AS Id
,nd.query('.') AS Task
,prTbl.Name AS [Name]
,prTbl.Description AS [Description]
--,t.c.value('@RoleName','nvarchar(max)') as [Role]
FROM @process AS prTbl
CROSS APPLY prTbl.workflowXML.nodes('process') AS A(pr)
CROSS APPLY pr.nodes('*') AS B(nd)
CROSS APPLY prTbl.workflowXML.nodes('process/Task/TaskUsers/TaskUser') AS t(c)
where t.c.value('@RoleName','nvarchar(max)') in (select * from SplitbyDelimiter('myFirstRole,mySecondRole',','))
)
但它不正确并返回216条记录!(原因:存在额外的列,具有不同的值)。另外,我在查询结尾添加了inner join result
,但这不能正常工作。
更新
我使用了这个查询:
WITH DerivedTable AS
(
SELECT prTbl.ID AS tblID
,nd.value('local-name(.)','nvarchar(max)') AS NodeName
,nd.value('@type','nvarchar(max)') AS [Type]
,nd.value('@id','nvarchar(max)') AS Id
,nd.query('.') AS Task
,prTbl.Name AS [Name]
,prTbl.Description AS [Description]
,t.c.value('@RoleName','nvarchar(max)') as [Role]
FROM @process AS prTbl
CROSS APPLY prTbl.workflowXML.nodes('process') AS A(pr)
CROSS APPLY pr.nodes('*') AS B(nd)
CROSS APPLY prTbl.workflowXML.nodes('process/Task/TaskUsers/TaskUser') AS t(c)
)
,AllIncoming AS
(
SELECT tblId
,NodeName
,[Type]
,Id
,[Name]
,[Description]
,i.value('.','nvarchar(max)') AS [Target]
FROM DerivedTable
CROSS APPLY Task.nodes('Task/incoming') AS A(i)
WHERE NodeName='Task'
)
,recCTE AS
(
SELECT tblID,NodeName,[Type],Id,[Name],[Description],[Role],Task,1 AS Step,' | ' +CAST(Id AS NVARCHAR(MAX)) AS NodePath
FROM DerivedTable
WHERE [Type]='start'
UNION ALL
SELECT nxt.tblID,nxt.NodeName,nxt.[Type],nxt.Id,nxt.[Name],nxt.Description,nxt.Role,nxt.Task,r.Step+1,r.NodePath + ' | ' + nxt.Id
FROM recCTE AS r
INNER JOIN DerivedTable AS nxt ON nxt.Id IN(SELECT x.Id
FROM AllIncoming AS x
WHERE x.[Target] IN (SELECT o.value('.','nvarchar(max)')
FROM r.Task.nodes('*/outgoing') AS A(o)
)
)
WHERE r.[Type]<>'user'
AND r.NodePath NOT LIKE '%| ' + nxt.Id + '%'
AND r.Step<=10
)
select a.tblID as ProcessID,[Name],[Description],a.NodePath,a.Id as TaskID,count(*) as records
from
(
SELECT t.tblID
,t.[Name]
,t.Description
,t.NodePath
,t.Id
,t.Role
FROM recCTE AS t
WHERE t.[Type]='user'
AND t.Step<=ISNULL((SELECT MIN(x.Step) FROM recCTE AS x WHERE x.tblID=t.tblID AND x.[Type]='user' AND x.NodeName='Task'),10000)
) a
INNER JOIN [dbo].[SplitbyDelimiter]('myFirstRole,mySecondRole',',') r
ON r.TheField = a.Role
group by a.tblID,[Name],[Description],a.NodePath,a.Id
ORDER BY a.tblID
此查询返回太多相同的记录,运行时间为19s
!!这不是好查询。
如果有人可以解释此查询的解决方案,那将非常有用。
答案 0 :(得分:1)
您的查询
我使用了这个查询:
WITH DerivedTable AS ( SELECT prTbl.ID AS tblID ,nd.value('local-name(.)','nvarchar(max)') AS NodeName ,nd.value('@type','nvarchar(max)') AS [Type] ,nd.value('@id','nvarchar(max)') AS Id ,nd.query('.') AS Task ,prTbl.Name AS [Name] ,prTbl.Description AS [Description] ,t.c.value('@RoleName','nvarchar(max)') as [Role] FROM @process AS prTbl CROSS APPLY prTbl.workflowXML.nodes('process') AS A(pr) CROSS APPLY pr.nodes('*') AS B(nd) CROSS APPLY prTbl.workflowXML.nodes('process/Task/TaskUsers/TaskUser') AS t(c) )
使用上一个CROSS APPLY
中的错误路径。您将获得所有TaksUser元素。因此有很多行...你可以将其更改为
[...]
CROSS APPLY pr.nodes('*') AS B(nd)
OUTER APPLY nd.nodes('TaskUsers/TaskUser') AS t(c)
收集当前节点下的所有TaskUser元素......
如果向原始结果集添加行,那么解决WorkFlow的整个方法都会中断!
将信息添加为附加列,其余部分保持不变。在我的查询中,我做了两次(TaskUsers和RoleNames),因为我真的不明白,你想用这个做什么:
WITH DerivedTable AS
(
SELECT prTbl.ID AS tblID
,nd.value('local-name(.)','nvarchar(max)') AS NodeName
,nd.value('@type','nvarchar(max)') AS [Type]
,nd.value('@id','nvarchar(max)') AS Id
,nd.query('.') AS Task
,prTbl.Name AS [Name]
,prTbl.Description AS [Description]
,nd.query('./TaskUsers/TaskUser') AS TaskUsers
,nd.query('./TaskUsers/TaskUser').query('for $rn in /TaskUser return string($rn/@RoleName)').value('.','nvarchar(max)') AS RoleNames
FROM @process AS prTbl
CROSS APPLY prTbl.workflowXML.nodes('process') AS A(pr)
CROSS APPLY pr.nodes('*') AS B(nd)
)
,AllIncoming AS
(
SELECT tblId
,NodeName
,[Type]
,Id
,[Name]
,[Description]
,TaskUsers
,RoleNames
,i.value('.','nvarchar(max)') AS [Target]
FROM DerivedTable
CROSS APPLY Task.nodes('Task/incoming') AS A(i)
WHERE NodeName='Task'
)
,recCTE AS
(
SELECT tblID,NodeName,[Type],Id,[Name],[Description],TaskUsers,RoleNames,Task,1 AS Step,' | ' +CAST(Id AS NVARCHAR(MAX)) AS NodePath
FROM DerivedTable
WHERE [Type]='start'
UNION ALL
SELECT nxt.tblID,nxt.NodeName,nxt.[Type],nxt.Id,nxt.[Name],nxt.Description,nxt.TaskUsers,nxt.RoleNames,nxt.Task,r.Step+1,r.NodePath + ' | ' + nxt.Id
FROM recCTE AS r
INNER JOIN DerivedTable AS nxt ON nxt.Id IN(SELECT x.Id
FROM AllIncoming AS x
WHERE x.[Target] IN (SELECT o.value('.','nvarchar(max)')
FROM r.Task.nodes('*/outgoing') AS A(o)
)
)
WHERE r.[Type]<>'user'
AND r.NodePath NOT LIKE '%| ' + nxt.Id + '%'
AND r.Step<=10
)
select a.tblID as ProcessID,[Name],[Description],TaskUsers,RoleNames,a.NodePath,a.Id as TaskID
from
(
SELECT t.tblID
,t.[Name]
,t.Description
,t.TaskUsers
,t.RoleNames
,t.NodePath
,t.Id
FROM recCTE AS t
WHERE t.[Type]='user'
AND t.Step<=ISNULL((SELECT MIN(x.Step) FROM recCTE AS x WHERE x.tblID=t.tblID AND x.[Type]='user' AND x.NodeName='Task'),10000)
) a
ORDER BY a.tblID
结果如下所示
您想要对这些附加信息做什么,您想要应用的任何过滤器都应该作为最后一步完成......
但是 - 说实话 - 你已经达到了SQL-Server的极限......这不是正确的工具。迟早会有更多的业务逻辑要实现......如果必须在SQL Server中完成,你可能会想到一个CLR方法......