我在 SQL Server 2008 R2 数据库中有一个表,它定义了不同状态之间的转换。
相关表格列示例:
TransitionID | SourceStateID | DestinationStateID | WorkflowID
--------------------------------------------------------------
1 | 17 | 18 | 3
2 | 17 | 21 | 3
3 | 17 | 24 | 3
4 | 17 | 172 | 3
5 | 18 | 17 | 3
6 | 18 | 24 | 3
7 | 18 | 31 | 3
8 | 21 | 17 | 3
9 | 21 | 20 | 3
10 | 21 | 141 | 3
11 | 21 | 184 | 3
... ETC。
我的目标是能够定义起始StateID、结束StateID 和 WorkflowID,并希望在该工作流中找到从起始 StateID 到结束 StateID 的逻辑路径。
例如,对于上表,如果我提供的起始 StateID 为 17,结束 StateID 为 184,WorkflowID 为 3,我可以得到一个 17>21>184 的“路径”(或者更理想的是,TransitionID 2>过渡ID 11)
好:
- 定义的开始和结束 StateID 将始终在定义的 WorkflowID中具有可能的路径
坏处:
几乎每个源/目标 StateID 上肯定都有循环引用(即可能有从 SourceStateID 1 到 DestinationStateID 2 的转换,以及从 SourceStateID 2 到 DestinationStateID 1 的转换
从几乎任何定义的起始 StateID 和结束 StateID 肯定有多个可能的路径
我意识到这是我追求的某种 CTE,但我承认我发现 CTE 通常很难掌握,而且当循环引用是一个有保证的问题时更是如此。
完美的解决方案是选择从起始 StateID 到结束 StateID 的最短路径,但老实说,在这一点上,如果我能得到一些能够可靠地为我提供两个状态之间的任何有效路径的工作,我会如此快乐的。
那里的任何 SQL 专家都有一些您可以指出我的方向吗?老实说,我什至不知道从哪里开始防止循环问题,比如沿着 17>18>17>18>17>18...
令人作呕的更新 我想出了这个查询,这在情感层面伤害了我(在这篇文章的一些帮助下:https ://stackoverflow.com/a/11042012/3253311 ),但似乎正在工作。
DECLARE @sourceStatusId INT = 17
DECLARE @destinationStatusId INT = 24
DECLARE @workflowId INT = 3
DECLARE @sourceStatusIdString NVARCHAR(MAX) = CAST(@sourceStatusId AS NVARCHAR(MAX))
DECLARE @destinationStatusIdString NVARCHAR(MAX) = CAST(@destinationStatusId AS NVARCHAR(MAX))
DECLARE @workflowIdString NVARCHAR(MAX) = CAST(@workflowId AS NVARCHAR(MAX))
;WITH CTE ([Source], [Destination], [Sentinel]) AS
(
SELECT
CAST(t.[Source] AS NVARCHAR(MAX)) AS [Source],
CAST(t.[Destination] AS NVARCHAR(MAX)) AS [Destination],
[Sentinel] = CAST([Source] AS NVARCHAR(MAX))
FROM
Transitions t
WHERE
CAST([Source] AS NVARCHAR(MAX)) = @sourceStatusIdString AND
CAST([WorkflowID] AS NVARCHAR(MAX)) = @workflowIdString
UNION ALL
SELECT
CAST(CTE.[Destination] AS NVARCHAR(MAX)),
CAST(t.[Destination] AS NVARCHAR(MAX)),
CAST([Sentinel] AS NVARCHAR(MAX)) + CAST('|' AS NVARCHAR(MAX)) + CAST(CTE.[Destination] AS NVARCHAR(MAX))
FROM
CTE
JOIN Transitions t
ON CAST(t.[Source] AS NVARCHAR(MAX)) = CAST(CTE.[Destination] AS NVARCHAR(MAX))
WHERE
CHARINDEX(CTE.[Destination], Sentinel)=0
)
SELECT TOP 1
[Sentinel]
FROM
CTE
WHERE
LEFT([Sentinel], LEN(@sourceStatusIdString)) = @sourceStatusIdString AND
RIGHT([Sentinel], LEN(@destinationStatusIdString)) = @destinationStatusIdString
ORDER BY
LEN([Sentinel])