2009-06-03 29 views
3

我有一些數據TSQL查詢來連接並刪除常見的前綴

id ref 
== ========== 
1 3536757616 
1 3536757617 
1 3536757618 

,並希望得到的結果

1 3536757616/7/8 

所以本質上是數據彙總的ID,與裁判連接在一起,用斜槓'/'分開,但是除去任何通用前綴,因此如果數據類似於

id ref 
== ========== 
2 3536757628 
2 3536757629 
2 3536757630 

我想要得到的結果

2 3536757629/28/30 

我知道我可以簡單地串聯裁判使用

SELECT distinct 
    id, 
    stuff ((SELECT 
        '/ ' + ref 
       FROM 
        tableA tableA_1 
       where tableA_1.id = tableA_2.id 
    FOR XML PATH ('')) , 1 , 2 , '') 
from TableA tableA_2 

1 3536757616/ 3536757617/ 3536757618 
2 3536757628/ 3536757629/ 3536757630 

,但它是刪除了我的共同元素中的位之後.....


代碼的測試數據:

create table tableA (id int, ref varchar(50)) 

insert into tableA 
select 1, 3536757616 
union select 1, 3536757617 
union select 1, 3536757618 
union select 2, 3536757628 
union select 2, 3536757629 
union select 2, 3536757630 

回答

3
WITH hier(cnt) AS 
     (
     SELECT 1 
     UNION ALL 
     SELECT cnt + 1 
     FROM hier 
     WHERE cnt <= 100 
     ) 
SELECT CASE WHEN ROW_NUMBER() OVER (ORDER BY id) = 1 THEN ref ELSE '/' + SUBSTRING(ref, mc + 1, LEN(ref)) END 
FROM (
     SELECT MIN(common) AS mc 
     FROM (
       SELECT (
         SELECT MAX(cnt) 
         FROM hier 
         WHERE SUBSTRING(initref, 1, cnt) = SUBSTRING(ref, 1, cnt) 
           AND cnt <= LEN(ref) 
         ) AS common 
       FROM (
         SELECT TOP 1 ref AS initref 
         FROM tableA 
         ) i, 
         tableA 
       ) q 
     ) q2, tableA 
FOR XML PATH('') 

--- 

3536757616/17/18/28/29/30 

同樣的事情組:

WITH hier(cnt) AS 
     (
     SELECT 1 
     UNION ALL 
     SELECT cnt + 1 
     FROM hier 
     WHERE cnt <= 100 
     ) 
SELECT (
     SELECT CASE WHEN ROW_NUMBER() OVER (ORDER BY a2.ref) = 1 THEN ref ELSE '/' + SUBSTRING(ref, mc + 1, LEN(ref)) END 
     FROM tableA a2 
     WHERE a2.id = q2.id 
     FOR XML PATH('') 
     ) 
FROM (
     SELECT id, MIN(common) AS mc 
     FROM (
       SELECT a.id, 
         (
         SELECT MAX(cnt) 
         FROM hier 
         WHERE SUBSTRING(i.initref, 1, cnt) = SUBSTRING(a.ref, 1, cnt) 
           AND cnt <= LEN(ref) 
         ) AS common 
       FROM (
         SELECT id, MIN(ref) AS initref 
         FROM tableA 
         GROUP BY 
           id 
         ) i 
       JOIN tableA a 
       ON  i.id = a.id 
       ) q 
     GROUP BY 
       id 
     ) q2 
--- 
3536757616/7/8 
3536757628/29/30 
+0

+1。我的頭痛苦地試圖圍繞這個包裹我的大腦,但它確實是一個「非常好」的做法。遠遠超過(當前)其他兩個答案(包括我自己的答案)。 – 2009-06-03 12:00:04

1

我叫我的表#T,並使用下面的SELECT語句

select id, number, substring(#t.ref, 1, v.number), count(id) 
from master.dbo.spt_values v 
inner join #t on v.number <= len(#t.ref) 
where v.name is null and v.number > 0 
group by id, number, substring(#t.ref, 1, v.number) 
order by id, count(id) desc, number desc 

你得到一個結果集,其中每個ID的第一條記錄包含最大長度每個ID最長的字符串。

這不是一個完整的解決方案,而是一個很好的起點:迭代ID,發出SELECT TOP 1來檢索最長的字符串,並將具有相同ID的每個記錄的字符串差異連接起來。

0
declare @tableA table(id int, ref varchar(50)) 
declare @suffix table(id int, suffix varchar(50)) 
declare @todo table(id int) 

insert into @tableA 
select 1, '3536757616' 
union select 1, '3536757617' 
union select 1, '3536757618' 
union select 2, '3536757628' 
union select 2, '3536757629' 
union select 2, '3536757630' 

insert into @suffix 
select * from @tableA 

insert into @todo 
select s1.id 
from (
    select id, cnt = count(*) 
    from @suffix 
    group by id, substring(suffix, 1, 1) 
) s1 
    inner join (
    select id, cnt = count(*) 
    from @suffix 
    group by id 
) s2 on s2.id = s1.id and s2.cnt = s1.cnt 

while exists (select * from @todo) 
begin 
    update @suffix 
    set suffix = substring(suffix, 2, len(suffix) - 1) 
    from @suffix s 
     inner join @todo t on t.id = s.id 

    delete from @todo 

    insert into @todo 
    select s1.id 
    from (
     select id, cnt = count(*) 
     from @suffix 
     group by id, substring(suffix, 1, 1) 
    ) s1 
    inner join (
     select id, cnt = count(*) 
     from @suffix 
     group by id 
    ) s2 on s2.id = s1.id and s2.cnt = s1.cnt 
end 

select * from @suffix