2016-09-19 76 views
2

序列我有一個看起來像數據:獲得從列在SQL服務器

ID1 ID2 ID3 ID4 
123 32 43 123 
56 67 56 89 
123 56 123 56 

基本上描述了起始於ID1和ID4結束的序列。我感興趣的只是提取模式,而不是涉及的ID。例如,第一行中的模式將是:

ABCA:由於它從一個ID開始,進入一個新的ID(B),然後是另一個新的ID(C),並返回到原始ID(A )。

第二行這將是:ABAC

和第三這將是:ABAB。

我正在尋找一種有效的方法來做到這一點在sql服務器,而不是使用大量的if語句爲每個潛在的情況。

回答

3

嗯。這是一個蠻力的方法:

select 'A' + 
     (case when id2 = id1 then 'A' else 'B' end) + 
     (case when id3 = id1 then 'A' 
      when id3 = id2 then 'B' 
      when id2 = id1 then 'B' 
      else 'C' 
     end) + 
     (case when id4 = id1 then 'A' 
      when id4 = id2 then 'B' 
      when id4 = id3 and id2 = id1 then 'B' 
      when id3 = id2 then 'C' 
      when id2 = id1 then 'C' 
      else 'D' 
     end) 

這有點複雜,但類似的東西應該工作。

編輯:

下面是應該工作的另一種方法:

select t.*, pattern 
from t outer apply(
    (select (max(case when id = 1 then val end) + 
       max(case when id = 2 then val end) + 
       max(case when id = 3 then val end) + 
       max(case when id = 4 then val end) 
      ) pattern 
     from (select v.*, 
        char(ascii('A' + dense_rank() over (order by minpos) - 1)) as val 
      from (select v.*, min(pos) over (partition by id) as minpos 
        from (values(id1, 1), (id2, 2), (id3, 3), (id4, 4)) as v(id, pos) 
       ) v 
      ) v 
    ) v; 

解釋它是如何工作是相當大的挑戰。的values()命令樞軸數據到行,因此在第一行結束,如:

id pos 
123  1 
32  2 
43  3 
123  4 

下一級把其中的值被找到的最小正:

id pos minpos 
123  1  1 
32  2  2 
43  3  3 
123  4  1 

(注意:它是一個巧合的是,這些數字是連續的)

然後dense_rank()變成字母這樣的:

id pos minpos val 
123  1  1  A 
32  2  2  B 
43  3  3  C 
123  4  1  A 

最後的聚合將它放入ABCA模式中。