SQL объединить несколько строк таблицы вместе

#sql #sql-server #merge #sql-server-2016

#sql #sql-сервер #объединить #sql-server-2016

Вопрос:

У меня есть таблица со следующим макетом

 Row   ID      Name    Notes
1     100     A       Full Text
2     200     B       Full Text
3     300     C       Text part1
4                     Text part2
5                     Text part3
6     400     D       Full Text
  

Где время от времени содержимое ячейки Notes для строки заполнялось строками под ней (например, строка 3 содержит содержимое notes в строках 4 и 5.) Другими словами, строка 3 была последней «допустимой» строкой. Мне нужно объединить содержимое notes из строк 4 и 5 в строку 3. Как я могу объединить содержимое notes в одну строку (строка 3) и удалить больше не нужные строки (строки 4 и 5)? Таким образом, конечный продукт будет выглядеть следующим образом

 Row   ID      Name    Notes
1     100     A       Full Text
2     200     B       Full Text
3     300     C       Full Text
6     400     D       Full Text
  

Комментарии:

1. какая у вас версия sqlserver?

2. Если бы у вас была какая-то идентификация, которая показывает, что эти строки являются группами, тогда вы могли бы использовать String_Agg() . На данный момент нет ничего, что говорило бы о том, что строки с идентификатором 3,4,5 находятся в одной группе. В чем логика?

3. Зачем повторять text3 3 раза, если каждый раз это будет одно и то же значение?

4. @Fahmi смотрите тег.

5. @CetinBasoz Я обновил информацию о таблице

Ответ №1:

Вы можете использовать накопительный count() для назначения групп, а затем агрегировать:

 select row_number() over (order by min(row)) as row,
       min(id) as id, min(name) as name,
       string_agg(text, ' ') within group (order by row) as text
from (select t.*,
             count(id) over (order by row) as grp
      from t
     ) t
group by grp;
  

Редактировать:

В более старых версиях SQL Server вы можете использовать:

 select min_row, id,
       stuff( (select ' '   t.notes
               from t t2
               where t2.row >= i.min_row and
                     (t2.row < i.max_row or i.max_row is null)
               for xml path ('')
              ), 1, 1, ''
            ) as notes
from (select id, name, min(row) as min_row, lead(min(row)) over (order by id) as max_row
      from t
      group by by id, name
     ) i;
  

Комментарии:

1. У меня другая среда, в которой выполняется SQL Server 2016. Как бы мне обойти отсутствие string_agg для 2016? @Gordon Linoff

2. @user3277752 . . . Есть ли у вас максимальное количество промежуточных строк?

3. Я не уверен, что вы имеете в виду? Исходная таблица состоит из 100 тысяч строк.

4. @user3277752 . . . Каково максимальное количество строк с NULL идентификаторами, которые необходимо объединить в одну строку?

5. На беглый взгляд кажется, что это 60 строк.

Ответ №2:

Если вы используете Sql server 2016, то вы можете попробовать этот запрос:

 --you are getting NumberGroup (using window function )
with cte as
(
  select *, sum(ID)over(order by Row rows unbounded preceding)NumGr from Table
)

-- using FOR XML PATH to get one row within group (Full text in your case)
select min(Row)Row,
max(ID)ID,max(Name)Name,max(Notes_new)Notes
from
(
 select *, stuff((select ' '  Notes from cte cte1 where cte1.NumGr=cte2.NumGr 
 FOR XML PATH('')),1,1,'')Notes_new
 from cte cte2
)X
group by NumGr