Как объединить текст из нескольких строк в одну текстовую строку на сервере SQL?

Рассмотрим таблицу базы данных с именами из трех строк:

Peter
Paul
Mary

Есть ли простой способ превратить это в одну строку Peter, Paul, Mary?

11.10.2008 23:49:59
Для ответов, специфичных для SQL Server, попробуйте этот вопрос .
Matt Hamilton 12.10.2008 00:03:42
Для MySQL, проверьте Group_Concat из этого ответа
Pykler 6.05.2011 19:48:02
Хотелось бы, чтобы в следующей версии SQL Server была предложена новая функция для элегантного решения многострочной конкатенации строк без глупости FOR XML PATH.
Pete Alvin 2.10.2014 11:47:17
Не SQL, но если это единственная вещь, вы можете вставить этот список в этот инструмент браузера: convert.town/column-to-comma-separated-list
Stack Man 27.05.2015 07:56:14
В Oracle вы можете использовать LISTAGG (COLUMN_NAME) из 11g r2 до того, как есть неподдерживаемая функция WM_CONCAT (COLUMN_NAME), которая делает то же самое.
Richard 6.07.2017 06:32:06
30 ОТВЕТОВ
РЕШЕНИЕ

Если вы используете SQL Server 2017 или Azure, см. Ответ Матье Ренда .

У меня была похожая проблема, когда я пытался соединить две таблицы с отношениями один-ко-многим. В SQL 2005 я обнаружил, что XML PATHметод может очень легко обрабатывать конкатенацию строк.

Если есть таблица с именем STUDENTS

SubjectID       StudentName
----------      -------------
1               Mary
1               John
1               Sam
2               Alaina
2               Edward

Результат, который я ожидал, был:

SubjectID       StudentName
----------      -------------
1               Mary, John, Sam
2               Alaina, Edward

Я использовал следующее T-SQL:

SELECT Main.SubjectID,
       LEFT(Main.Students,Len(Main.Students)-1) As "Students"
FROM
    (
        SELECT DISTINCT ST2.SubjectID, 
            (
                SELECT ST1.StudentName + ',' AS [text()]
                FROM dbo.Students ST1
                WHERE ST1.SubjectID = ST2.SubjectID
                ORDER BY ST1.SubjectID
                FOR XML PATH ('')
            ) [Students]
        FROM dbo.Students ST2
    ) [Main]

Вы можете сделать то же самое более компактным способом, если вы можете объединить запятые в начале и использовать substringдля пропуска первого, чтобы вам не нужно было выполнять подзапрос:

SELECT DISTINCT ST2.SubjectID, 
    SUBSTRING(
        (
            SELECT ','+ST1.StudentName  AS [text()]
            FROM dbo.Students ST1
            WHERE ST1.SubjectID = ST2.SubjectID
            ORDER BY ST1.SubjectID
            FOR XML PATH ('')
        ), 2, 1000) [Students]
FROM dbo.Students ST2
1417
2.08.2018 11:20:52
Отличное решение. Следующее может быть полезно, если вам нужно обрабатывать специальные символы, такие как в HTML: Роб Фарли: Обработка специальных символов с помощью FOR XML PATH ('') .
user140628 17.04.2013 12:35:18
Очевидно, это не работает, если имена содержат символы XML, такие как <или &. Смотрите @ BenHinman комментарий.
Sam 13.08.2013 01:26:59
NB. Этот метод зависит от недокументированного поведения FOR XML PATH (''). Это означает, что он не должен считаться надежным, поскольку любое исправление или обновление может изменить его функционирование. Это в основном полагаться на устаревшую функцию.
Bacon Bits 13.11.2014 18:54:02
@Whelkaholism Суть в том, что FOR XMLон предназначен для генерации XML, а не для конкатенации произвольных строк. Вот почему она ускользает &, <и >кодов XML сущностей ( &amp;, &lt;, &gt;). Я предполагаю, что это также сбежит "и 'в &quot;и &apos;в атрибутах также. Это не GROUP_CONCAT() , string_agg(), array_agg(), listagg()и т.д. , даже если вы можете отчасти сделать его сделать это. Мы должны тратить наше время, требуя, чтобы Microsoft реализовала правильную функцию.
Bacon Bits 23.03.2015 14:15:21
Хорошая новость: MS SQL Server будет добавлен string_aggв v.Next. и все это может уйти.
Jason C 6.04.2017 00:32:48

Зависит от поставщика вашей базы данных. MySQL имеет concat_ws. MS SQL Server ожидает, что вы сделаете это в своем клиентском приложении.

Обновление: вы также можете сделать это во внешней процедуре или в UDF, возможно, используя курсор или вызывая код CLR.

-5
12.10.2008 00:16:32
@Joel, функция в MySQL - CONCAT_WS (), но она полезна только для 1 строки в результате.
Darryl Hein 12.10.2008 00:11:35

Один из способов сделать это в SQL Server - вернуть содержимое таблицы в формате XML (для необработанного XML), преобразовать результат в строку и затем заменить теги на «,».

2
26.02.2012 18:37:25

В MySQL есть функция GROUP_CONCAT () , которая позволяет объединять значения из нескольких строк. Пример:

SELECT 1 AS a, GROUP_CONCAT(name ORDER BY name ASC SEPARATOR ', ') AS people 
FROM users 
WHERE id IN (1,2,3) 
GROUP BY a
120
26.02.2012 18:37:58
работает хорошо. Но когда я использую, SEPARATOR '", "'я пропущу некоторые символы в конце последней записи. почему это может случиться?
gooleem 27.11.2016 13:05:59
@gooleem Я не совсем понимаю, что вы имеете в виду, но эта функция только устанавливает разделитель между элементами, а не после. Если это не ответ, я бы рекомендовал опубликовать новый вопрос.
Darryl Hein 4.12.2016 23:41:35
@DarrylHein для своих нужд, я использовал разделитель, как указано выше. Но это подрезает мне некоторые символы в самом конце вывода. Это очень странно и кажется ошибкой. У меня нет решения, я просто обошел стороной.
gooleem 6.12.2016 09:28:00
Работает в принципе. Две вещи, на которые следует обратить внимание: 1) если ваш столбец не a CHAR, вам нужно привести его, например, через GROUP_CONCAT( CAST(id AS CHAR(8)) ORDER BY id ASC SEPARATOR ',')2) если у вас есть много значений, вы должны увеличить group_concat_max_lenкак написано в stackoverflow.com/a/1278210/1498405
hardmooth 14.02.2018 09:25:23

У меня нет доступа к SQL Server дома, поэтому я предполагаю синтаксис здесь, но он более или менее:

DECLARE @names VARCHAR(500)

SELECT @names = @names + ' ' + Name
FROM Names
28
12.10.2008 00:16:20
Вам нужно будет инициализировать @names чем-то ненулевым, иначе вы получите NULL повсюду; вам также нужно обработать разделитель (включая ненужный)
Marc Gravell♦ 12.10.2008 09:10:53
единственная проблема с этим подходом (который я использую все время) состоит в том, что вы не можете его встроить
ekkis 23.11.2012 22:22:29
Чтобы избавиться от лидирующего пробела, измените запрос наSELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ' ' END + Name FROM Names
Tian van Heerden 4.03.2016 09:15:45
Кроме того, вы должны проверить, что имя не является нулевым, вы можете сделать это, выполнив:SELECT @names = @names + ISNULL(' ' + Name, '')
Vita1ij 18.03.2016 10:49:30

Этот ответ может возвращать неожиданные результаты. Для получения согласованных результатов используйте один из методов FOR XML PATH, подробно описанных в других ответах.

Используйте COALESCE:

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name 
FROM People

Просто некоторое объяснение (так как этот ответ, кажется, получает относительно регулярные взгляды):

  • Coalesce действительно полезный чит, который выполняет две вещи:

1) Нет необходимости инициализировать @Namesпустым строковым значением.

2) Нет необходимости снимать дополнительный разделитель в конце.

  • Приведенное выше решение даст неверные результаты, если строка имеет значение NULL Name (если есть NULL , NULL будет иметь @Names значение NULL после этой строки, а следующая строка будет начинаться снова как пустая строка. Легко исправляется одним из двух решения:
DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
WHERE Name IS NOT NULL

или:

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + 
    ISNULL(Name, 'N/A')
FROM People

В зависимости от того, какое поведение вы хотите (первая опция просто отфильтровывает значения NULL , вторая опция сохраняет их в списке с сообщением-маркером [замените 'N / A' тем, что вам подходит]).

1003
30.04.2019 12:02:01
Чтобы было ясно, coalesce не имеет ничего общего с созданием списка, он просто гарантирует, что значения NULL не включены.
Graeme Perrow 13.02.2009 12:02:46
@Graeme Perrow Не исключает значения NULL (для этого требуется WHERE - это приведет к потере результатов, если одно из входных значений равно NULL), и это требуется в этом подходе, потому что: NULL + non-NULL -> NULL и не NULL + NULL -> NULL; Кроме того, @Name по умолчанию равно NULL, и, фактически, это свойство используется здесь как неявный сторож, чтобы определить, следует ли добавить ',' или нет.
user166390 15.08.2010 18:57:57
Обратите внимание, что этот метод объединения основан на SQL Server, выполняющем запрос с определенным планом. Я был пойман с помощью этого метода (с добавлением ORDER BY). Когда он имел дело с небольшим количеством строк, он работал нормально, но с большим количеством данных SQL Server выбирал другой план, в результате чего выбирался первый элемент без объединения. Смотрите эту статью Анит Сен
fbarber 26.04.2012 02:18:01
Этот метод нельзя использовать в качестве подзапроса в списке выбора или предложении where, поскольку он использует переменную tSQL. В таких случаях вы можете использовать методы, предложенные @Ritesh
R. Schreurs 2.08.2013 08:10:54
Это не надежный метод конкатенации. Он не поддерживается и не должен использоваться (для Microsoft, например, support.microsoft.com/en-us/kb/287515 , connect.microsoft.com/SQLServer/Feedback/Details/704389 ). Это может измениться без предупреждения. Используйте технику XML PATH, обсуждаемую в stackoverflow.com/questions/5031204/… Я написал больше здесь: marc.durdin.net/2015/07/…
Marc Durdin 15.07.2015 00:23:20
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

Это ставит случайную запятую в начале.

Однако, если вам нужны другие столбцы или для CSV дочерней таблицы, вам нужно обернуть это в скалярное пользовательское поле (UDF).

Вы можете использовать путь XML в качестве коррелированного подзапроса в предложении SELECT (но мне придется подождать, пока я не вернусь к работе, потому что Google не выполняет работу дома :-)

10
26.02.2012 18:39:58

В SQL Server 2005

SELECT Stuff(
  (SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'')

В SQL Server 2016

Вы можете использовать синтаксис FOR JSON

т.е.

SELECT per.ID,
Emails = JSON_VALUE(
   REPLACE(
     (SELECT _ = em.Email FROM Email em WHERE em.Person = per.ID FOR JSON PATH)
    ,'"},{"_":"',', '),'$[0]._'
) 
FROM Person per

И результат станет

Id  Emails
1   abc@gmail.com
2   NULL
3   def@gmail.com, xyz@gmail.com

Это будет работать, даже если ваши данные содержат недопустимые символы XML

'"},{"_":"'безопасно , потому что, если ваши данные содержат '"},{"_":"',будет убежал в"},{\"_\":\"

Вы можете заменить ', 'любой разделитель строк


А в SQL Server 2017 база данных SQL Azure

Вы можете использовать новую функцию STRING_AGG

303
23.07.2018 16:55:05
Хорошее использование функции STUFF, чтобы убрать два первых символа.
David 11.08.2011 23:12:59
Мне больше всего нравится это решение, потому что я могу легко использовать его в списке выбора, добавив «как <label>». Я не уверен, как это сделать с помощью решения @Ritesh.
R. Schreurs 2.08.2013 08:27:52
Это лучше , чем общепринятом ответ , потому что эта опция также обрабатывает не-спасаясь символы reserverd XML , такие как <, >, &и т.д. , которые FOR XML PATH('')будут автоматически избежать.
BateTech 7.04.2014 21:35:21
Это потрясающий ответ, так как он решил проблему и предоставляет лучшие способы работы в различных версиях SQL, теперь я хотел бы использовать 2017 / Azure
Chris Ward 21.05.2018 14:27:54

Один метод, еще не показанный с помощью XML data()команды в MS SQL Server:

Предположим, таблица с именем NameList с одним столбцом с именем FName,

SELECT FName + ', ' AS 'data()' 
FROM NameList 
FOR XML PATH('')

возвращает:

"Peter, Paul, Mary, "

Только лишняя запятая должна быть обработана.

Редактировать: как принято из комментария @ NReilingh, вы можете использовать следующий метод для удаления запятой. Предполагая одинаковые имена таблиц и столбцов:

STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands
361
25.04.2016 15:28:47
святой с ** т это удивительно! Когда выполняется сам по себе, как в вашем примере, результат форматируется как гиперссылка, при нажатии (в SSMS) открывается новое окно, содержащее данные, но при использовании в качестве части более крупного запроса оно просто отображается в виде строки. Это строка? или это XML, который мне нужно обрабатывать по-разному в приложении, которое будет использовать эти данные?
Ben 7.09.2012 15:56:00
Этот подход также XML-экранирует символы, такие как <и>. Итак, ВЫБОР '<b>' + FName + '</ b>' приводит к появлению "& lt; b & gt; John & lt; b & gt; b & gt; b ...>
Lukáš Lánský 26.02.2014 18:34:07
Опрятное решение. Я заметил, что даже если я не добавляю, + ', 'он добавляет один пробел между каждым объединенным элементом.
Baodad 3.10.2014 22:40:38
@Baodad Похоже, это часть сделки. Вы можете обойти это путем замены на добавленный токен. Например, это делает идеальный список, разделенный запятыми, любой длины:SELECT STUFF(REPLACE((SELECT '#!'+city AS 'data()' FROM #cityzip FOR XML PATH ('')),' #!',', '),1,2,'')
NReilingh 29.02.2016 18:12:13
Вау, на самом деле в моем тестировании с использованием data () и замены это ПУТЬ более производительным, чем нет. Супер странно.
NReilingh 29.02.2016 18:33:08

Использование XML помогло мне получить строки, разделенные запятыми. Для дополнительной запятой мы можем использовать функцию замены SQL Server. Вместо добавления запятой использование AS data () объединит строки с пробелами, которые впоследствии можно будет заменить на запятые в качестве синтаксиса, приведенного ниже.

REPLACE(
        (select FName AS 'data()'  from NameList  for xml path(''))
         , ' ', ', ') 
18
26.02.2012 18:42:55
Это лучший ответ здесь, на мой взгляд. Использование объявления переменная не годится, когда вам нужно объединить в другую таблицу, и это хорошо и кратко. Хорошая работа.
David Roussel 2.06.2011 16:22:53
это не работает хорошо, если в данных FName уже есть пробелы, например «Мое имя»
binball 8.06.2011 15:16:32
На самом деле это работает для меня на MS-SQL 2016 Выберите REPLACE ((выберите Имя AS 'data ()' из Бренда, где Id IN (1,2,3,4) для пути XML ('')), '', ' , ') as allBrands
Rejwanul Reja 28.04.2017 10:13:38

Как насчет этого:

   ISNULL(SUBSTRING(REPLACE((select ',' FName as 'data()' from NameList for xml path('')), ' ,',', '), 2, 300), '') 'MyList'

Где «300» может быть любой ширины, принимая во внимание максимальное количество элементов, которые, по вашему мнению, будут отображаться.

1
29.04.2011 15:28:29
Если вам когда-нибудь придется заранее угадывать, сколько строк будет в ваших результатах, вы делаете это неправильно.
Geoff Griswald 10.01.2020 10:57:29

В Oracle это так wm_concat. Я считаю, что эта функция доступна в версии 10g и выше.

4
26.02.2012 18:44:21

Я обычно использую select следующим образом, чтобы объединить строки в SQL Server:

with lines as 
( 
  select 
    row_number() over(order by id) id, -- id is a line id
    line -- line of text.
  from
    source -- line source
), 
result_lines as 
( 
  select 
    id, 
    cast(line as nvarchar(max)) line 
  from 
    lines 
  where 
    id = 1 
  union all 
  select 
    l.id, 
    cast(r.line + N', ' + l.line as nvarchar(max))
  from 
    lines l 
    inner join 
    result_lines r 
    on 
      l.id = r.id + 1 
) 
select top 1 
  line
from
  result_lines
order by
  id desc
5
6.07.2011 07:06:01

В SQL Server 2005 и более поздних версиях используйте приведенный ниже запрос для объединения строк.

DECLARE @t table
(
    Id int,
    Name varchar(10)
)
INSERT INTO @t
SELECT 1,'a' UNION ALL
SELECT 1,'b' UNION ALL
SELECT 2,'c' UNION ALL
SELECT 2,'d' 

SELECT ID,
stuff(
(
    SELECT ','+ [Name] FROM @t WHERE Id = t.Id FOR XML PATH('')
),1,1,'') 
FROM (SELECT DISTINCT ID FROM @t ) t
34
20.10.2014 08:49:30
Я считаю, что это не удается, когда значения содержат символы XML, такие как <или &.
Sam 13.08.2013 01:36:56

Если вы хотите иметь дело с пустыми значениями, вы можете сделать это, добавив предложение where или добавив еще один COALESCE вокруг первого.

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People
5
27.07.2011 20:05:13

Мне очень понравилась элегантность ответа Даны . Просто хотел сделать это завершенным.

DECLARE @names VARCHAR(MAX)
SET @names = ''

SELECT @names = @names + ', ' + Name FROM Names 

-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)
7
23.05.2017 11:55:19
Если вы удаляете последние два символа «,», то вам необходимо добавить «,» после имени («SELECT \ @names = \ @names + Name +», «FROM Names»). Таким образом, последние два символа всегда будут «,».
JT_ 18.12.2015 11:04:11
В моем случае мне нужно было избавиться от ведущей запятой, поэтому измените запрос, чтобы SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ', ' END + Name FROM Namesпотом не нужно было его усекать.
Tian van Heerden 4.03.2016 09:13:29

Готовое решение без лишних запятых:

select substring(
        (select ', '+Name AS 'data()' from Names for xml path(''))
       ,3, 255) as "MyList"

Пустой список приведет к значению NULL. Обычно вы вставляете список в столбец таблицы или переменную программы: установите максимальную длину 255 в соответствии с вашими потребностями.

(Дивакар и Йенс Франдсен дали хорошие ответы, но нуждаются в улучшении.)

17
26.02.2012 20:03:20
Пробел перед запятой при использовании этого :(
slayernoah 18.11.2015 18:23:52
Просто замените ', 'на, ','если вам не нужно дополнительное место.
Daniel Reis 18.11.2015 23:17:45

Oracle 11g Release 2 поддерживает функцию LISTAGG. Документация здесь .

COLUMN employees FORMAT A50

SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS employees
FROM   emp
GROUP BY deptno;

    DEPTNO EMPLOYEES
---------- --------------------------------------------------
        10 CLARK,KING,MILLER
        20 ADAMS,FORD,JONES,SCOTT,SMITH
        30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD

3 rows selected.

Предупреждение

Будьте осторожны при реализации этой функции, если есть вероятность, что результирующая строка превысит 4000 символов. Это бросит исключение. Если это так, то вам нужно либо обработать исключение, либо выполнить собственную функцию, которая не позволяет объединенной строке превышать 4000 символов.

46
14.03.2013 14:30:15
Для более старых версий Oracle идеально подходит wm_concat. Его использование объясняется в ссылке подарок от Алекса. Спасибо Алекс!
toscanelli 20.07.2015 13:04:25
LISTAGGработает отлично! Просто прочитайте документ, связанный здесь. wm_concatудалено с версии 12с и далее.
asgs 22.06.2016 18:56:44

Было предложено рекурсивное решение CTE, но код не был предоставлен. Код ниже является примером рекурсивного CTE. Обратите внимание, что хотя результаты совпадают с вопросом, данные не совсем соответствуют данному описанию, так как я предполагаю, что вы действительно хотите делать это для групп строк, а не для всех строк в таблице. Изменение его для соответствия всем строкам таблицы оставлено читателю в качестве упражнения.

;WITH basetable AS (
    SELECT
        id,
        CAST(name AS VARCHAR(MAX)) name, 
        ROW_NUMBER() OVER (Partition BY id ORDER BY seq) rw, 
        COUNT(*) OVER (Partition BY id) recs 
    FROM (VALUES
        (1, 'Johnny', 1),
        (1, 'M', 2), 
        (2, 'Bill', 1),
        (2, 'S.', 4),
        (2, 'Preston', 5),
        (2, 'Esq.', 6),
        (3, 'Ted', 1),
        (3, 'Theodore', 2),
        (3, 'Logan', 3),
        (4, 'Peter', 1),
        (4, 'Paul', 2),
        (4, 'Mary', 3)
    ) g (id, name, seq)
),
rCTE AS (
    SELECT recs, id, name, rw
    FROM basetable
    WHERE rw = 1

    UNION ALL

    SELECT b.recs, r.ID, r.name +', '+ b.name name, r.rw + 1
    FROM basetable b
    INNER JOIN rCTE r ON b.id = r.id AND b.rw = r.rw + 1
)
SELECT name
FROM rCTE
WHERE recs = rw AND ID=4
28
26.08.2019 18:22:43
Для ошарашил: этот запрос вставки 12 строк (в 3 колонки) во временную basetable, а затем создает рекурсивную общий стол Выражение (РКТО) , а затем сглаживает name столбец в разделенных запятыми строку на 4 группы в idс. На первый взгляд, я думаю, что это больше работы, чем большинство других решений для SQL Server.
knb 24.07.2017 13:34:43
@knb: не уверен, что это похвала, осуждение или просто сюрприз. Базовая таблица такова, что мне нравятся мои примеры, и они не имеют ничего общего с вопросом.
jmoreno 25.07.2017 02:20:15

Массивы Postgres потрясающие. Пример:

Создайте некоторые тестовые данные:

postgres=# \c test
You are now connected to database "test" as user "hgimenez".
test=# create table names (name text);
CREATE TABLE                                      
test=# insert into names (name) values ('Peter'), ('Paul'), ('Mary');                                                          
INSERT 0 3
test=# select * from names;
 name  
-------
 Peter
 Paul
 Mary
(3 rows)

Объедините их в массив:

test=# select array_agg(name) from names;
 array_agg     
------------------- 
 {Peter,Paul,Mary}
(1 row)

Преобразовать массив в строку с разделителями-запятыми:

test=# select array_to_string(array_agg(name), ', ') from names;
 array_to_string
-------------------
 Peter, Paul, Mary
(1 row)

СДЕЛАННЫЙ

Начиная с PostgreSQL 9.0 это еще проще .

48
23.05.2017 12:18:33
Если вам нужно более одного столбца, например, идентификатор сотрудника в скобках, используйте оператор concat: select array_to_string(array_agg(name||'('||id||')'
Richard Fox 27.02.2015 11:50:37
Не применимо к sql-серверу , только к mysql
GoldBishop 4.05.2017 15:03:24

В оракуле есть несколько способов,

    create table name
    (first_name varchar2(30));

    insert into name values ('Peter');
    insert into name values ('Paul');
    insert into name values ('Mary');

Решение 1:

    select substr(max(sys_connect_by_path (first_name, ',')),2) from (select rownum r, first_name from name ) n start with r=1 connect by prior r+1=r
    o/p=> Peter,Paul,Mary

Соус 2:

    select  rtrim(xmlagg (xmlelement (e, first_name || ',')).extract ('//text()'), ',') first_name from name
    o/p=> Peter,Paul,Mary
2
20.09.2019 16:03:04

Начиная с PostgreSQL 9.0 это довольно просто:

select string_agg(name, ',') 
from names;

В версиях до 9.0 array_agg()можно использовать как показано hgmnz

24
20.10.2014 10:42:42
Чтобы сделать это со столбцами, которые не имеют тип текста, вам нужно добавить приведение типа:SELECT string_agg(non_text_type::text, ',') FROM table
Torben Kohlmeier 17.05.2013 12:05:28
@TorbenKohlmeier: это нужно только для не символьных столбцов (например, целое, десятичное). Это прекрасно работает для varcharилиchar
a_horse_with_no_name 17.05.2013 12:11:38

Для БД Oracle посмотрите этот вопрос: Как можно объединить несколько строк в одну в Oracle без создания хранимой процедуры?

Наилучшим ответом, по-видимому, является @Emmanuel, использующий встроенную функцию LISTAGG (), доступную в Oracle 11g Release 2 и более поздних версиях.

SELECT question_id,
   LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE;
GROUP BY question_id

как указал @ user762952, и согласно документации Oracle http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php , функция WM_CONCAT () также является опцией. Это кажется стабильным, но Oracle явно рекомендует не использовать его для любого SQL-приложения, поэтому используйте его на свой страх и риск.

Помимо этого, вам придется написать свою собственную функцию; В приведенном выше документе Oracle есть руководство, как это сделать.

7
23.05.2017 11:47:36

Это тоже может быть полезно

create table #test (id int,name varchar(10))
--use separate inserts on older versions of SQL Server
insert into #test values (1,'Peter'), (1,'Paul'), (1,'Mary'), (2,'Alex'), (3,'Jack')

DECLARE @t VARCHAR(255)
SELECT @t = ISNULL(@t + ',' + name, name) FROM #test WHERE id = 1
select @t
drop table #test

возвращается

Peter,Paul,Mary
4
25.10.2013 08:14:23
К сожалению, это поведение официально не поддерживается. MSDN говорит: «Если на переменную ссылаются в списке выбора, ей должно быть присвоено скалярное значение, или инструкция SELECT должна возвращать только одну строку». И есть люди, которые наблюдали проблемы: sqlmag.com/sql-server/multi-row-variable-assignment-and-order
blueling 5.12.2013 09:11:08

Этот метод применяется только к базе данных Teradata Aster, поскольку он использует функцию NPATH.

Опять же у нас есть стол студентов

SubjectID       StudentName
----------      -------------
1               Mary
1               John
1               Sam
2               Alaina
2               Edward

Тогда с NPATH это просто один SELECT:

SELECT * FROM npath(
  ON Students
  PARTITION BY SubjectID
  ORDER BY StudentName
  MODE(nonoverlapping)
  PATTERN('A*')
  SYMBOLS(
    'true' as A
  )
  RESULT(
    FIRST(SubjectID of A) as SubjectID,
    ACCUMULATE(StudentName of A) as StudentName
  )
);

Результат:

SubjectID       StudentName
----------      -------------
1               [John, Mary, Sam]
2               [Alaina, Edward]
3
15.11.2013 20:26:03

С типом TABLE это очень просто. Давайте представим, что ваша таблица называется Studentsи у нее есть столбец name.

declare @rowsCount INT
declare @i INT = 1
declare @names varchar(max) = ''

DECLARE @MyTable TABLE
(
  Id int identity,
  Name varchar(500)
)
insert into @MyTable select name from Students
set @rowsCount = (select COUNT(Id) from @MyTable)

while @i < @rowsCount
begin
 set @names = @names + ', ' + (select name from @MyTable where Id = @i)
 set @i = @i + 1
end
select @names

Этот пример протестирован в MS SQL Server 2008 R2

1
2.12.2013 09:25:52

Чтобы избежать нулевых значений, вы можете использовать CONCAT ()

DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name) 
FROM Names
select @names
7
12.02.2015 12:01:27
Было бы неплохо узнать, почему работает CONCAT. Ссылка на MSDN была бы хороша.
Reversed Engineer 20.09.2016 08:15:03
   declare @phone varchar(max)='' 
   select @phone=@phone + mobileno +',' from  members
   select @phone
-5
21.04.2015 07:47:06
Почему не так, +', 'как хотел OP, а также вы не удаляете последний ';'. Я думаю, что этот ответ такой же, а также этот ответ ;).
shA.t 20.04.2015 07:05:44
У меня была эта проблема, и я нашел ответ, но я хочу объединить с ';' вот и
Hamid Bahmanabady 20.04.2015 13:24:41
Когда вы публикуете здесь свой ответ, это должно быть связано с вопросом, и результатом вашего кода должно быть Null, потому что вы начинаете с @phone IS Nullдобавления и Nullбудете Nullв SQL Server, я думаю, вы забыли что-то вроде добавления = ''после первой строки;).
shA.t 20.04.2015 13:43:13
Нет, я выкладываю ответ после проверки, и результат не был нулевым
Hamid Bahmanabady 20.04.2015 17:36:29

Этот ответ потребует некоторых привилегий на сервере для работы.

Сборки - это хороший вариант для вас. Есть много сайтов, которые объясняют, как его создать. Один я думаю , что очень хорошо объяснил это один

Если вы хотите, я уже создал сборку, и можно скачать DLL здесь .

Как только вы загрузите его, вам нужно будет запустить следующий скрипт на вашем SQL Server:

CREATE Assembly concat_assembly 
   AUTHORIZATION dbo 
   FROM '<PATH TO Concat.dll IN SERVER>' 
   WITH PERMISSION_SET = SAFE; 
GO 

CREATE AGGREGATE dbo.concat ( 

    @Value NVARCHAR(MAX) 
  , @Delimiter NVARCHAR(4000) 

) RETURNS NVARCHAR(MAX) 
EXTERNAL Name concat_assembly.[Concat.Concat]; 
GO  

sp_configure 'clr enabled', 1;
RECONFIGURE

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

SELECT dbo.Concat(field1, ',')
FROM Table1

Надеюсь, поможет!!!

6
8.05.2015 01:39:06
Ссылка DLL - ошибка 404. Использование сборки для этого является излишним. Смотрите лучший ответ для SQL Server.
Protiguous 19.02.2020 13:37:45

MySQL complete Пример:

У нас есть Пользователи, у которых может быть много Данных, и мы хотим иметь вывод, где мы можем видеть все пользовательские Данные в списке:

Результат:

___________________________
| id   |  rowList         |
|-------------------------|
| 0    | 6, 9             |
| 1    | 1,2,3,4,5,7,8,1  |
|_________________________|

Настройка таблицы:

CREATE TABLE `Data` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;


INSERT INTO `Data` (`id`, `user_id`) VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 0),
(7, 1),
(8, 1),
(9, 0),
(10, 1);


CREATE TABLE `User` (
  `id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


INSERT INTO `User` (`id`) VALUES
(0),
(1);

Запрос:

SELECT User.id, GROUP_CONCAT(Data.id ORDER BY Data.id) AS rowList FROM User LEFT JOIN Data ON User.id = Data.user_id GROUP BY User.id
6
22.07.2015 07:51:12