【发布时间】:2016-09-10 11:38:22
【问题描述】:
我有这个 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!!。这不是很好的查询。
如果有人能解释这个查询的解决方案,那将非常有帮助。
【问题讨论】:
-
这项工作的语言(工具)错误,我不想成为下一个必须维护该代码的工程师。 SQL 是一种数据持久性工具,而不是 XML 工具。使用具有质量 XML 解析器和查询语言的过程语言,例如C# 与 LINQ 等。
-
@TFD 真实数据量很大并且存储在 SQL Server 数据库中。出于这个原因,我需要这个查询。
-
在同一服务器/网络上运行服务。无论哪种方式,SQL IO 都会发生,只是理解发生的事情有多难
标签: sql sql-server xml