【发布时间】:2016-08-07 22:43:14
【问题描述】:
我在 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
...等等
我的目标是能够定义 starting StateID、ending StateID 和 WorkflowID,并希望找到从起始 StateID 到结束的逻辑路径该工作流程中的 StateID。
例如对于上表,如果我提供的起始 StateID 为 17,结束 StateID 为 184,WorkflowID 为 3,我可以得到一个 17>21>184 的“路径”(或者更理想的是,TransitionID 2 > TransitionID 11)
善:
- 定义的开始和结束 StateID总是在定义的 WorkflowID 中有一个可能路径
坏人:
在几乎每个源/目标 StateID 上肯定都有循环引用(即,可能存在从 SourceStateID 1 到 DestinationStateID 2 以及从 SourceStateID 2 到 DestinationStateID 1 的转换
从几乎任何定义的起始 StateID 和结束 StateID 肯定有多个可能的路径
我意识到这是我所追求的某种 CTE,但我承认我发现 CTE 通常很难掌握,而且当循环引用是一个有保证的问题时更是如此。
完美的解决方案是选择从起始 StateID 到结束 StateID 的最短路径,但老实说,在这一点上,如果我能得到可靠地给我 any 有效的东西两种状态之间的路径我会很高兴。
那里的任何 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])
【问题讨论】:
-
没有多少 sql 甚至逻辑可以解决这个问题。您有一行具有 parentID 17 和一个 18 的孩子,在同一个组中,您有一个 18 的 parentID 和一个 17 的孩子。您甚至没有任何数据表明基点或起点是什么。你这里有个无解之谜。像这样想。鸡 17 岁,鸡蛋 18 岁。哪个先来?
-
@SeanLange 虽然我同意这是一个泡菜,但我尊重地不同意它“无法解决”。我刚刚提出了一个可行的解决方案,但是它的实施在情感层面上伤害了我。我现在要查看 Quassnoi 的答案,希望我不需要使用我想出的答案:)
标签: sql sql-server common-table-expression hierarchical hierarchical-query