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

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

 Peter
Paul
Mary
 

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

вопрос задан 11.10.2008
JohnnyM
10236 репутация

44 ответов


  • 1136 рейтинг

    Если вы находитесь на 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
     
    ответ дан gbn, с репутацией 332307, 13.02.2009
  • 906 рейтинг

    Этот ответ может возвращать неожиданные результаты, когда присутствует предложение ORDER BY. Для получения согласованных результатов используйте один из методов 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 s, второй вариант сохраняет их в списке с сообщением маркера [заменить «N /A» на то, что подходит вам]).

    ответ дан Chris Shaffer, с репутацией 27741, 12.10.2008
  • 309 рейтинг

    Один из методов, еще не показанный командой 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
     
    ответ дан jens frandsen, с репутацией 3099, 5.04.2011
  • 221 рейтинг

    В 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 база данных Azure SQL

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

    ответ дан Steven Chong, с репутацией 832, 9.09.2010
  • 188 рейтинг

    SQL Server 2017+ и SQL Azure: STRING_AGG

    Начиная со следующей версии SQL Server, мы можем, наконец, объединиться между строк, не прибегая к какой-либо переменной или XML-witchery.

    STRING_AGG (Transact-SQL)

    Без группировки

     SELECT STRING_AGG(Name, ', ') AS Departments
    FROM HumanResources.Department;
     

    С группировкой:

     SELECT GroupName, STRING_AGG(Name, ', ') AS Departments
    FROM HumanResources.Department
    GROUP BY GroupName;
     

    С группировкой и подсеризацией

     SELECT GroupName, STRING_AGG(Name, ', ') WITHIN GROUP (ORDER BY Name ASC) AS Departments
    FROM HumanResources.Department 
    GROUP BY GroupName;
     
    ответ дан Mathieu Renda, с репутацией 3448, 14.03.2017
  • 102 рейтинг

    В 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
     
    ответ дан Darryl Hein, с репутацией 66521, 12.10.2008
  • 53 рейтинг

    Используйте COALESCE - Узнайте больше отсюда

    Например:

    102

    103

    104

    Затем напишите ниже код на сервере sql,

     Declare @Numbers AS Nvarchar(MAX) -- It must not be MAX if you have few numbers 
    SELECT  @Numbers = COALESCE(@Numbers + ',', '') + Number
    FROM   TableName where Number IS NOT NULL
    
    SELECT @Numbers
     

    Результатом будет:

     102,103,104
     
    ответ дан pedram, с репутацией 4874, 5.04.2016
  • 44 рейтинг

    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 символов.

    ответ дан Alex, с репутацией 7075, 8.03.2012
  • 43 рейтинг

    Массивы 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 это еще проще .

    ответ дан hgmnz, с репутацией 11516, 9.08.2012
  • 28 рейтинг

    В 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
     
    ответ дан Yogesh Bhadauirya, с репутацией 1105, 6.07.2011
  • 24 рейтинг

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

     DECLARE @names VARCHAR(500)
    
    SELECT @names = @names + ' ' + Name
    FROM Names
     
    ответ дан Dana, с репутацией 18860, 12.10.2008
  • 22 рейтинг

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

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

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

    ответ дан a_horse_with_no_name, с репутацией 278415, 16.11.2012
  • 22 рейтинг

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

    Простое решение

     DECLARE @char VARCHAR(MAX);
    
    SELECT @char = COALESCE(@char + ', ' + [column], [column]) 
    FROM [table];
    
    PRINT @char;
     
    ответ дан Tigerjz32, с репутацией 2141, 15.11.2016
  • 22 рейтинг

    Было предложено рекурсивное решение 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
     
    ответ дан jmoreno, с репутацией 10637, 9.08.2012
  • 20 рейтинг

    В SQL Server vNext это будет построено с помощью функции STRING_AGG. Подробнее читайте здесь: https://msdn.microsoft.com/en-us/library/mt790580.aspx

    ответ дан Henrik Fransas, с репутацией 865, 21.11.2016
  • 15 рейтинг

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

     REPLACE(
            (select FName AS 'data()'  from NameList  for xml path(''))
             , ' ', ', ') 
     
    ответ дан Diwakar, с репутацией 159, 7.04.2011
  • 14 рейтинг

    Готовое к использованию решение без дополнительных запятых:

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

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

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

    ответ дан Daniel Reis, с репутацией 9606, 3.02.2012
  • 8 рейтинг

    С другими ответами человек, читающий ответ, должен знать конкретную таблицу домена, такую ​​как автомобиль или ученик. Таблица должна быть создана и заполнена данными для проверки решения.

    Ниже приведен пример использования таблицы SQL Server «Information_Schema.Columns». Используя это решение, таблицы не нужно создавать или добавлять данные. В этом примере создается список имен столбцов, разделенных запятыми, для всех таблиц в базе данных.

     SELECT
        Table_Name
        ,STUFF((
            SELECT ',' + Column_Name
            FROM INFORMATION_SCHEMA.Columns Columns
            WHERE Tables.Table_Name = Columns.Table_Name
            ORDER BY Column_Name
            FOR XML PATH ('')), 1, 1, ''
        )Columns
    FROM INFORMATION_SCHEMA.Columns Tables
    GROUP BY TABLE_NAME 
     
    ответ дан Mike Barlow - BarDev, с репутацией 6985, 4.05.2016
  • 8 рейтинг
     DECLARE @Names VARCHAR(8000)
    SELECT @name = ''
    SELECT @Names = @Names + ',' + Names FROM People
    SELECT SUBSTRING(2, @Names, 7998)
     

    Это ставит блуждающую запятую в начале.

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

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

    ответ дан gbn, с репутацией 332307, 13.10.2008
  • 7 рейтинг
     SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')
     

    Вот пример:

     DECLARE @t TABLE (name VARCHAR(10))
    INSERT INTO @t VALUES ('Peter'), ('Paul'), ('Mary')
    SELECT STUFF((SELECT ', ' + name FROM @t FOR XML PATH('')), 1, 2, '')
    --Peter, Paul, Mary
     
    ответ дан Max Szczurek, с репутацией 2708, 25.01.2018
  • 6 рейтинг

    Для Oracle DB см. Этот вопрос: как несколько строк могут быть объединены в один в 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 содержит руководство о том, как это сделать.

    ответ дан ZeroK, с репутацией 350, 13.05.2013
  • 5 рейтинг

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

     DECLARE @names VARCHAR(500)
    SELECT @names = CONCAT(@names, ' ', name) 
    FROM Names
    select @names
     
    ответ дан Rapunzo, с репутацией 605, 12.02.2015
  • 5 рейтинг

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

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

    Если вы хотите, я уже создал сборку, и можно скачать 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
     

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

    ответ дан Nizam, с репутацией 3187, 8.05.2015
  • 5 рейтинг

    MySQL завершен Пример:

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

    Результат:

     ___________________________
    | 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
     
    ответ дан user1767754, с репутацией 8604, 22.07.2015
  • 5 рейтинг

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

     DECLARE @names VARCHAR(MAX)
    SET @names = ''
    
    SELECT @names = @names + ', ' + Name FROM Names 
    
    -- Deleting last two symbols (', ')
    SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)
     
    ответ дан Oleg Sakharov, с репутацией 959, 21.11.2011
  • 3 рейтинг

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

     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
     
    ответ дан endo64, с репутацией 1513, 25.10.2013
  • 3 рейтинг

    Обычно я использую 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
     
    ответ дан Vladimir Nesterovsky, с репутацией 362, 6.07.2011
  • 2 рейтинг

    Не то, чтобы я сделал какой-либо анализ производительности, так как в моем списке было менее 10 элементов, но я был поражен, посмотрев через 30 нечетных ответов. У меня все еще был поворот в аналогичном ответе, уже приведенном аналогично использованию COALESCE для одного группового списка и didn 't даже нужно установить мою переменную (по умолчанию равно NULL), и она предполагает, что все записи в моей исходной таблице данных не пустые:

     DECLARE @MyList VARCHAR(1000), @Delimiter CHAR(2) = ', '
    SELECT @MyList = CASE WHEN @MyList > '' THEN @MyList + @Delimiter ELSE '' END + FieldToConcatenate FROM MyData
     

    Я уверен, COALESCE внутренне использует ту же идею. Давайте надеяться, что MS не изменит это на мне.

    ответ дан Glen, с репутацией 281, 10.06.2016
  • 2 рейтинг

    --SQL Server 2005+

     CREATE TABLE dbo.Students
    (
        StudentId INT
        , Name VARCHAR(50)
        , CONSTRAINT PK_Students PRIMARY KEY (StudentId)
    );
    
    CREATE TABLE dbo.Subjects
    (
        SubjectId INT
        , Name VARCHAR(50)
        , CONSTRAINT PK_Subjects PRIMARY KEY (SubjectId)
    );
    
    CREATE TABLE dbo.Schedules
    (
        StudentId INT
        , SubjectId INT
        , CONSTRAINT PK__Schedule PRIMARY KEY (StudentId, SubjectId)
        , CONSTRAINT FK_Schedule_Students FOREIGN KEY (StudentId) REFERENCES dbo.Students (StudentId)
        , CONSTRAINT FK_Schedule_Subjects FOREIGN KEY (SubjectId) REFERENCES dbo.Subjects (SubjectId)
    );
    
    INSERT dbo.Students (StudentId, Name) VALUES
        (1, 'Mary')
        , (2, 'John')
        , (3, 'Sam')
        , (4, 'Alaina')
        , (5, 'Edward')
    ;
    
    INSERT dbo.Subjects (SubjectId, Name) VALUES
        (1, 'Physics')
        , (2, 'Geography')
        , (3, 'French')
        , (4, 'Gymnastics')
    ;
    
    INSERT dbo.Schedules (StudentId, SubjectId) VALUES
        (1, 1)      --Mary, Physics
        , (2, 1)    --John, Physics
        , (3, 1)    --Sam, Physics
        , (4, 2)    --Alaina, Geography
        , (5, 2)    --Edward, Geography
    ;
    
    SELECT 
        sub.SubjectId
        , sub.Name AS [SubjectName]
        , ISNULL( x.Students, '') AS Students
    FROM
        dbo.Subjects sub
        OUTER APPLY
        (
            SELECT 
                CASE ROW_NUMBER() OVER (ORDER BY stu.Name) WHEN 1 THEN '' ELSE ', ' END
                + stu.Name
            FROM
                dbo.Students stu
                INNER JOIN dbo.Schedules sch
                    ON stu.StudentId = sch.StudentId
            WHERE
                sch.SubjectId = sub.SubjectId
            ORDER BY
                stu.Name
            FOR XML PATH('')
        ) x (Students)
    ;
     
    ответ дан Graeme, с репутацией 768, 1.06.2016
  • 2 рейтинг

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

    ответ дан user762952, с репутацией 29, 3.06.2011
  • 2 рейтинг

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

     DECLARE @Names VARCHAR(8000) 
    SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People
     
    ответ дан Pramod, с репутацией 29, 27.07.2011
  • 1 рейтинг

    Этот метод применяется к базе данных 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]
     
    ответ дан topchef, с репутацией 12495, 15.11.2013
  • 1 рейтинг
    SELECT PageContent = Stuff(
        (   SELECT PageContent
            FROM dbo.InfoGuide
            WHERE CategoryId = @CategoryId
              AND SubCategoryId = @SubCategoryId
            for xml path(''), type
        ).value('.[1]','nvarchar(max)'),
        1, 1, '')
    FROM dbo.InfoGuide info
    
    ответ дан Muhammad Bilal, с репутацией 119, 26.05.2016
  • 1 рейтинг

    Вот полное решение для этого:

     -- Table Creation
    CREATE TABLE Tbl
    ( CustomerCode    VARCHAR(50)
    , CustomerName    VARCHAR(50)
    , Type VARCHAR(50)
    ,Items    VARCHAR(50)
    )
    
    insert into Tbl
    SELECT 'C0001','Thomas','BREAKFAST','Milk'
    union SELECT 'C0001','Thomas','BREAKFAST','Bread'
    union SELECT 'C0001','Thomas','BREAKFAST','Egg'
    union SELECT 'C0001','Thomas','LUNCH','Rice'
    union SELECT 'C0001','Thomas','LUNCH','Fish Curry'
    union SELECT 'C0001','Thomas','LUNCH','Lessy'
    union SELECT 'C0002','JOSEPH','BREAKFAST','Bread'
    union SELECT 'C0002','JOSEPH','BREAKFAST','Jam'
    union SELECT 'C0002','JOSEPH','BREAKFAST','Tea'
    union SELECT 'C0002','JOSEPH','Supper','Tea'
    union SELECT 'C0002','JOSEPH','Brunch','Roti'
    
    -- function creation
    GO
    CREATE  FUNCTION [dbo].[fn_GetItemsByType]
    (   
        @CustomerCode VARCHAR(50)
        ,@Type VARCHAR(50)
    )
    RETURNS @ItemType TABLE  ( Items VARCHAR(5000) )
    AS
    BEGIN
    
            INSERT INTO @ItemType(Items)
        SELECT  STUFF((SELECT distinct ',' + [Items]
             FROM Tbl 
             WHERE CustomerCode = @CustomerCode
                AND Type=@Type
                FOR XML PATH(''))
            ,1,1,'') as  Items
    
    
    
        RETURN 
    END
    
    GO
    
    -- fianl Query
    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = STUFF((SELECT distinct ',' + QUOTENAME(Type) 
                        from Tbl
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT CustomerCode,CustomerName,' + @cols + '
                 from 
                 (
                    select  
                        distinct CustomerCode
                        ,CustomerName
                        ,Type
                        ,F.Items
                        FROM Tbl T
                        CROSS APPLY [fn_GetItemsByType] (T.CustomerCode,T.Type) F
                ) x
                pivot 
                (
                    max(Items)
                    for Type in (' + @cols + ')
                ) p '
    
    execute(@query) 
     
    ответ дан Ravi Pipaliya, с репутацией 131, 2.04.2018
  • 0 рейтинг

    @ User1460901 Вы можете попробовать что-то вроде этого:

     WITH cte_base AS (
        SELECT CustomerCode, CustomerName,
        CASE WHEN Typez = 'Breakfast' THEN Items ELSE NULL END AS 'BREAKFAST'
        , CASE WHEN Typez = 'Lunch' THEN Items ELSE NULL END AS 'LUNCH'
        FROM #Customer
        )
        SELECT distinct CustomerCode, CustomerName,
        SUBSTRING(
        (   
            SELECT ','+BREAKFAST AS [text()]
            FROM cte_base b1
            WHERE b1.CustomerCode = b2.CustomerCode AND b1.CustomerName = b2.CustomerName
            ORDER BY b1.BREAKFAST
            FOR XML PATH('')
            ), 2, 1000
        ) [BREAKFAST], 
        SUBSTRING(
        (   
            SELECT ','+LUNCH AS [text()]
            FROM cte_base b1
            WHERE b1.CustomerCode = b2.CustomerCode AND b1.CustomerName = b2.CustomerName
            ORDER BY b1.LUNCH
            FOR XML PATH('')
            ), 2, 1000
        ) [LUNCH]
        FROM cte_base b2
     
    ответ дан Aura, с репутацией 827, 2.04.2018
  • 0 рейтинг

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

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

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

    ответ дан Hans Bluh, с репутацией 9, 29.04.2011
  • 0 рейтинг

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

    ответ дан Manu, с репутацией 15660, 11.10.2008
  • 0 рейтинг

    Ниже приведена простая процедура PL /SQL для реализации данного сценария с использованием «basic loop» и «rownum»,

    Определение таблицы

     CREATE TABLE "NAMES" ("NAME" VARCHAR2(10 BYTE))) ;
     

    Вставим значения в эту таблицу

     INSERT INTO NAMES VALUES('PETER');
    INSERT INTO NAMES VALUES('PAUL');
    INSERT INTO NAMES VALUES('MARY');
     

    Процедура начинается здесь

     DECLARE 
    
    MAXNUM INTEGER;
    CNTR INTEGER := 1;
    C_NAME NAMES.NAME%TYPE;
    NSTR VARCHAR2(50);
    
    BEGIN
    
    SELECT MAX(ROWNUM) INTO MAXNUM FROM NAMES;
    
    LOOP
    
    SELECT NAME INTO  C_NAME FROM 
    (SELECT ROWNUM RW, NAME FROM NAMES ) P WHERE P.RW = CNTR;
    
    NSTR := NSTR ||','||C_NAME;
    CNTR := CNTR + 1;
    EXIT WHEN CNTR > MAXNUM;
    
    END LOOP;
    
    dbms_output.put_line(SUBSTR(NSTR,2));
    
    END;
     

    результат

     PETER,PAUL,MARY
     
    ответ дан Pooja Bhat, с репутацией 21, 15.02.2018
  • 0 рейтинг

    С типом 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

    ответ дан Max Tkachenko, с репутацией 474, 2.12.2013
  • 0 рейтинг

    Хотя уже слишком поздно и уже есть много решений. Вот простое решение для MySQL:

     SELECT t1.id,
            GROUP_CONCAT(t1.id) ids
     FROM table t1 JOIN table t2 ON (t1.id = t2.id)
     GROUP BY t1.id
     
    ответ дан Shahbaz, с репутацией 25, 7.12.2017
  • 0 рейтинг

    С помощью рекурсивного запроса вы можете это сделать:

     -- Create example table
    CREATE TABLE tmptable (NAME VARCHAR(30)) ;
    
    -- Insert example data
    INSERT INTO tmptable VALUES('PETER');
    INSERT INTO tmptable VALUES('PAUL');
    INSERT INTO tmptable VALUES('MARY');
    
    -- Recurse query
    with tblwithrank as (
    select * , row_number() over(order by name) rang , count(*) over() NbRow
    from tmptable
    ),
    tmpRecursive as (
    select *, cast(name as varchar(2000)) as AllName from tblwithrank  where rang=1
    union all
    select f0.*,  cast(f0.name + ',' + f1.AllName as varchar(2000)) as AllName 
    from tblwithrank f0 inner join tmpRecursive f1 on f0.rang=f1.rang +1 
    )
    select AllName from tmpRecursive
    where rang=NbRow
     
    ответ дан Esperento57, с репутацией 7740, 31.07.2018
  • 0 рейтинг

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

         create table name
        (first_name varchar2(30));
    
        insert into name values ('Peter');
        insert into name values ('Paul');
        insert into name values ('Mary');
    
        Solution 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
    
        Soution 2:
        select  rtrim(xmlagg (xmlelement (e, first_name || ',')).extract ('//text()'), ',') first_name from name
        o/p=> Peter,Paul,Mary
     
    ответ дан Priti Getkewar Joshi, с репутацией 477, 28.09.2012
  • -1 рейтинг

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

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

    ответ дан Joel Coehoorn, с репутацией 299287, 11.10.2008
  • -6 рейтинг
       declare @phone varchar(max)='' 
       select @phone=@phone + mobileno +',' from  members
       select @phone
    
    ответ дан Hamid Bahmanabady, с репутацией 368, 20.04.2015