Как объединить несколько строк в один столбец в SQL Server? - PullRequest
4 голосов
/ 09 августа 2009

Я искал ответ на этот вопрос, но не могу понять. Я относительно новичок в SQL Server, и у меня пока нет синтаксиса. У меня есть эта структура данных (упрощенно):

Table "Users"         | Table "Tags":
UserID    UserName    | TagID    UserID    PhotoID
1         Bob         | 1        1         1
2         Bill        | 2        2         1
3         Jane        | 3        3         1
4         Sam         | 4        2         2
-----------------------------------------------------
Table "Photos":              | Table "Albums":
PhotoID   UserID    AlbumID  | AlbumID     UserID
1         1         1        | 1           1
2         1         1        | 2           3
3         1         1        | 3           2
4         3         2        |
5         3         2        |

Я ищу способ получить всю информацию о фотографии (легко), а также все теги для этой фотографии, объединенные как CONCAT(username, ', ') AS Tags, конечно, с последней удаленной запятой. У меня есть время, пытающееся сделать это. Я попробовал метод в этой статье , но я получаю ошибку, когда пытаюсь выполнить запрос, говоря, что я не могу использовать операторы DECLARE ... У вас, ребята, есть идеи, как это можно быть сделано? Я использую VS08 и любую установленную в ней БД (обычно я использую MySQL, поэтому я не знаю, что это за БД на самом деле ... это файл .mdf?)

Ответы [ 2 ]

13 голосов
/ 09 августа 2009

Хорошо, я чувствую, что мне нужно перейти к комментарию о Как объединить несколько строк в один столбец в SQL Server? и предоставить более предпочтительный ответ.

Мне очень жаль, но использование таких скалярных функций снизит производительность. Просто откройте SQL Profiler и посмотрите, что происходит, когда вы используете скалярную функцию, которая вызывает таблицу.

Кроме того, метод «обновить переменную» для конкатенации не рекомендуется, так как эта функция может не сохраняться в будущих версиях.

Предпочтительный способ объединения строк вместо FOR FOR PATH.

select
 stuff((select ', ' + t.tag from tags t where t.photoid = p.photoid order by tag for xml path('')),1,2,'') as taglist
 ,*
from photos
order by photoid;

В качестве примеров того, как работает FOR XML PATH, рассмотрите следующее, представив, что у вас есть таблица с двумя полями с именами 'id' и 'name'

SELECT id, name
FROM table
order by name
FOR XML PATH('item'),root('itemlist')
;

Дает:

<itemlist><item><id>2</id><name>Aardvark</a></item><item><id>1</id><name>Zebra</name></item></itemlist>

Но если вы пропустите ROOT, вы получите что-то немного другое:

SELECT id, name
FROM table
order by name
FOR XML PATH('item')
;

<item><id>2</id><name>Aardvark</a></item><item><id>1</id><name>Zebra</name></item>

И если вы поместите пустую строку PATH, вы станете еще ближе к обычной конкатенации строк:

SELECT id, name
FROM table
order by name
FOR XML PATH('')
;

<id>2</id><name>Aardvark</a><id>1</id><name>Zebra</name>

Теперь наступает очень сложный момент ... Если вы называете столбец, начинающийся со знака @, он становится атрибутом, а если столбец не имеет имени (или вы называете его [*]), то он пропускает и этот тег:

SELECT ',' + name
FROM table
order by name
FOR XML PATH('')
;

,Aardvark,Zebra

Теперь, наконец, чтобы убрать начальную запятую, приходит команда STUFF. STUFF (s, x, n, s2) извлекает n символов s, начиная с позиции x. На их место ставится s2. Итак:

SELECT STUFF ('abcde', 2,3, '123456');

дает:

a123456e

Итак, взгляните на мой запрос выше для вашего списка тегов.

select
 stuff((select ', ' + t.tag from tags t where t.photoid = p.photoid order by tag for xml path('')),1,2,'') as taglist
 ,*
from photos
order by photoid;

Для каждой фотографии у меня есть подзапрос, который захватывает теги и объединяет их (по порядку) с запятой и пробелом. Затем я окружаю этот подзапрос командой stuff, чтобы убрать начальную запятую и пробел.

Я прошу прощения за любые опечатки - на самом деле я не создал таблицы на своей машине, чтобы проверить это.

Rob

3 голосов
/ 09 августа 2009

Я бы создал UDF:

create function GetTags(PhotoID int) returns @tags varchar(max)
as
begin
    declare @mytags varchar(max)
    set @mytags = ''

    select @mytags = @mytags + ', ' + tag from tags where photoid = @photoid

    return substring(@mytags, 3, 8000)
end

Тогда все, что вам нужно сделать, это:

select GetTags(photoID) as tagList from photos
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...