TSQL-запрос для объединения и удаления общего префикса - PullRequest
3 голосов
/ 03 июня 2009

У меня есть данные

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 ]

3 голосов
/ 03 июня 2009
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
1 голос
/ 03 июня 2009

Я назвал свою таблицу #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

вы получите набор результатов, в котором первая запись каждого идентификатора содержит максимальную длину и самую длинную начальную строку для каждого идентификатора.

Это не полное решение, но хорошая отправная точка: переберите идентификаторы, выполните команду SELECT TOP 1, чтобы получить самую длинную строку, и объедините различия строк для каждой записи с одинаковым идентификатором.

0 голосов
/ 03 июня 2009
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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...