2009-11-05 153 views
0

的曲線圖具有以下結構和樣本數據的一個表:TSQL CTE和排序

TableActivity 
------------- 
Type    VARCHAR(8) 
Activity   VARCHAR(8) 
RelatedActivity  VARCHAR(8) 

Type  Activity  RelatedActivity 
------------------------------------------ 
Start  a    - 
Transfer a    b 
Start  b    - 
Transfer b    c 
Start  c    - 
Stop  c    - 
Transfer c    b 
Stop  b    - 
Transfer b    a 
Stop  a    - 

纔有可能寫一個CTE查詢來完成下列工作:

GetActivities('a') 

Order Activities 
------------------- 
0  a 
1  b 
2  c 

我在寫一個停止在遞歸語句中返回行的時候,有一段艱難的時間。

任何想法?

編輯

爲了闡明GetActivities( 'A')。此功能應找到'a'的'開始'活動,並繼續在'a'上找到任何'轉移'活動。在這一點上,函數可以用'b'遞歸,並且隨後用樣本數據遞歸'c'。查詢應通過「轉賬」返回與'a'相關的所有活動。這種嵌套的活動可以儘可能地深入並且是未知的(因此沒有工會)。我遇到的困難是還有另一個「轉移」,例如, 'b' - >'a'。你可以看到這將如何在遞歸查詢中創建一個循環。

再一次澄清:活動表中的傳輸表現爲堆棧。下面是如何在表格中填充數據(使用C#):

using (Activity.Start("a")) 
{ 
    // transfer to 'b' under covers 
    using (Activity.Start("b")) 
    { 
    // transfer to 'c' under covers 
    using (Activity.Start("c")) 
    { 
    } 
    // transfer to 'b' under covers 
    } 
    // transfer to 'a' under covers 
} 

回答

1

基於Erwins輸入:

declare @TableActivity table 
([Type]    VARCHAR(8) 
,Activity   VARCHAR(8) 
,RelatedActivity  VARCHAR(8) 
) 

insert @TableActivity 
     select 'Start','a','-' 
union select 'Transfer','a','b' 
union select 'Start','b','-' 
union select 'Transfer','b','c' 
union select 'Start','c','-' 
union select 'Transfer','c','d' 
union select 'Transfer','c','e' 
union select 'Start','d','-' 
union select 'Stop','d','-' 
union select 'Start','e','-' 
union select 'Stop','e','-' 
union select 'Transfer','d','c' 
union select 'Transfer','e','c' 
union select 'Stop','c','-' 
union select 'Transfer','c','b' 
union select 'Stop','b','-' 
union select 'Transfer','b','a' 
union select 'Stop','a','-' 
union select 'Start','1','-' 
union select 'Transfer','1','2' 
union select 'Start','2','-' 
union select 'Transfer','2','3' 
union select 'Start','3','-' 
union select 'Transfer','3','4' 
union select 'Start','4','-' 
union select 'Stop','4','-' 
union select 'Transfer','4','3' 
union select 'Stop','3','-' 
union select 'Transfer','3','2' 
union select 'Stop','2','-' 
union select 'Transfer','2','1' 
union select 'Stop','1','-' 

declare @activity varchar(8) 
set @activity = 'a' 

;WITH ActivitiesGraph(activity, relatedactivity) AS 
(
     SELECT activity, 
      relatedactivity 
     FROM @TableActivity root 
     WHERE root.activity = @activity 
     AND root.type  = 'Transfer' 

     UNION ALL 

     SELECT next.activity, 
      next.relatedactivity 
     FROM @TableActivity next 
      INNER JOIN ActivitiesGraph prior 
      ON  next.activity = prior.relatedactivity 
     WHERE next.type   = 'Transfer' 
     AND prior.activity != next.relatedactivity 
     AND prior.activity != next.activity 
    ) 
SELECT activity 
FROM @TableActivity 
WHERE activity = @activity 

UNION 

SELECT relatedactivity 
FROM ActivitiesGraph 
+0

不會處理更大的循環。在你的例子中添加「UNION SELECT'Transfer','c','a'」。 – 2009-11-06 22:56:36

+0

幸運的是,這種情況不會發生在我的應用程序中:活動遍歷的行爲像一個堆棧。 – jsw 2009-11-06 23:57:13

+0

啊。這是一個更簡單的情況,然後處理有循環的普通有向圖。 – 2009-11-07 01:16:31

0

是否真的需要遞歸查詢?根據您提供的樣本數據,所有需要的是報告爲使活動停止,相反:

declare @TableActivity table 
([Type]    VARCHAR(8) 
,Activity   VARCHAR(8) 
,RelatedActivity  VARCHAR(8) 
) 


insert @TableActivity 
     select 'Start','a','-' 
union select 'Transfer','a','b' 
union select 'Start','b','-' 
union select 'Transfer','b','c' 
union select 'Start','c','-' 
union select 'Stop','c','-' 
union select 'Transfer','c','b' 
union select 'Stop','b','-' 
union select 'Transfer','b','a' 
union select 'Stop','a','-' 


select activity 
     ,ROW_NUMBER() OVER (ORDER BY activity) - 1 AS rn 
from @TableActivity 
where [Type] = 'Stop' 
order by 2 
+0

是的,我澄清這個問題有點。 – jsw 2009-11-06 20:40:08

0

你沒有給你的預期的語義的任何細節「getactivities()」事情。

這使得問題很難回答。

但無論如何,既然您提到了'遞歸',我會假設您希望結果集包含與給定活動相關的任何間接任何級別的活動。

由於'處於任何間接級別'部分,您無法避免遞歸。它應該粗略地操作如下:

從給定的一組活動('a')開始尋找相關活動('b')。 從找到的新活動中刪除已經找到的活動(無)。 將其餘部分添加到結果集中,並用此集合重複: 通過給定的一組活動('b'),查找相關活動('a''c')。 從找到的新活動中刪除已經找到的活動('a')。 將其餘的('c')添加到結果集中,並用該集合重複: 通過給定的一組活動('c'),查找相關活動('b')。 從找到的新活動中刪除已經找到的活動('b')。 將其餘的(無)添加到結果集中,並且因爲沒有,您就完成了。

對不起,我不能把它變成SQL,爲你脫帽而出。

0

我試過了,但不能告訴你它是否會有好處。如果不是,請忽略。

WITH TMP AS (
SELECT activity, relatedactivity 
FROM tableactivity root 
WHERE root.activity = 'a' and root.type='transfer' 
UNION ALL 
SELECT next.activity, next.relatedactivity 
FROM tableactivity next, TMP prior 
WHERE prior.relatedactivity = next.activity and next.type='transfer' 
    AND not exists (SELECT * FROM TMP ttmp 
        WHERE ttmp.activity = next.relatedactivity 
        AND ttmp.relatedactivity = next.activity) 
       ) 
) 
SELECT relatedactivity FROM TMP 
UNION (ALL ???) 
SELECT 'a' from <nonemptytable> 

PS

爲您orderingnumber,那就是不與圖形及其封閉適應得很好的概念。如果從a到c有不同長度的多條不同路徑,你希望你的號碼是什麼?

+0

是的,訂購號碼不合適。我得到一個公共表表達式的遞歸成員'TMP'具有多個遞歸引用。'在這個查詢中。試圖弄清楚我是否可以解決它。 – jsw 2009-11-06 20:19:28

+0

不存在必須在那裏,但我不知道在CTE的限制下做到這一點。 – jsw 2009-11-06 20:21:26