2

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

...など

私の目標は、開始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は一般的に把握するのが難しいことを認めており、循環参照が保証された問題である場合は2倍になります。

完璧な解決策は、StateID の開始から StateID の終了までの最短パスを選択することですが、この時点で正直に言うと、2 つの状態の間の有効なパスを確実に提供する何かが機能する場合は、そうします。ハッピー。

そこにいる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])
4

3 に答える 3

3

Quassnoi の回答に似ていますが、最初の要素の後に開始する循環参照を防ぎます。

DECLARE @src int = 18, @dst int = 184;
WITH cte  AS 
(Select TransitionId, SourceStateId, DestinationStateID, SourceStateID as StartingState, 0 as Depth
  , cast(TransitionId as varchar(max)) + ','  as IDPath  
  , cast(SourceStateID as varchar(max)) + ',' as States
 FROM Transitions
 WHERE SourceStateId = @src
 UNION ALL
 Select t.TransitionId, t.SourceStateId, t.DestinationStateID, StartingState, cte.Depth + 1
  , cte.IDPath + cast(t.TransitionId as varchar(max)) + ',' 
  , cte.States + cast(t.SourceStateID as varchar(max)) + ','
 FROM cte JOIN Transitions t on cte.DestinationStateID = t.SourceStateId 
 and CHARINDEX(',' + cast(t.SourceStateID as varchar(max)) + ',', States) = 0 --prevent loop starting after first element
 and t.DestinationStateID <> StartingState --prevent loop starting with first element
 where cte.Depth < 10 -- prevent going too deep
 )
 select TransitionId, SourceStateId, DestinationStateID, Depth, left(IDPath, len(IDPath) - 1) IDPath, left(States, len(States) - 1) States
 from cte
 where DestinationStateID = @dst
 order by Depth
于 2016-04-15T21:07:41.917 に答える