Concat все значения столбцов в sql - PullRequest
26 голосов
/ 09 июня 2009

Как объединить все значения столбцов из разных строк, возвращаемых из запроса SQL, в одно значение? Это пример:

запрос возвращает:

FOO
------
RES1

RES2

RES3

Теперь я хочу получить результат, подобный следующему:

FOOCONCAT
-----
RES1RES2RES3

Есть ли способы сделать это в SQL?

Ответы [ 12 ]

46 голосов
/ 09 июня 2009

В SQL Server:

SELECT  col1 AS [text()]
FROM    foo
FOR XML PATH ('')

В MySQL:

SELECT  GROUP_CONCAT(col1 SEPARATOR '')
FROM    foo

В PostgreSQL:

SELECT  array_to_string
        (
        ARRAY
        (
        SELECT  col1
        FROM    foo
        ), ''
        )

В Oracle:

SELECT  *
FROM    (
        SELECT  col1, ROW_NUMBER() OVER(ORDER BY 1) AS rn
        FROM    foo
        MODEL
        DIMENSION BY
                (rn)
        MEASURES
                (col1, col1 AS group_concat, 0 AS mark)
        RULES UPDATE (
                group_concat[rn > 1] =  group_concat[CV() - 1] || col1[CV()],
                mark[ANY] = PRESENTV(mark[CV() + 1], 0, 1)
                )
        )
WHERE   mark = 1
9 голосов
/ 19 июня 2009

Решение Oracle от Quassnoi впечатляет, но я нашел простых решений, использующих SYS_CONNECT_BY_PATH (), а не магию MODEL.

SELECT REPLACE(MAX(SYS_CONNECT_BY_PATH(foo, '/')), '/', '') conc
FROM (
    SELECT T_FOO.*, ROW_NUMBER() OVER (ORDER BY FOO) R FROM T_FOO
)
START WITH r=1
CONNECT BY PRIOR r = r-1;
3 голосов
/ 09 июня 2009

Мысленный путь:

select group_concat(somecolumn separator '') from sometable
3 голосов
/ 09 июня 2009

Предполагая, что это один столбец с несколькими значениями, этот подход работает для MS SQL Server (я не могу говорить для других систем).

declare @result varchar(max)
set @result = ''

select @result = @result + RES
from (query goes here)
1 голос
/ 18 марта 2011

Редактировать: Начиная с версии 8.4.0, CUBRID обеспечивает 90% совместимость с MySQL. Таким образом, он поддерживает GROUP_CONCAT , синтаксис которого аналогичен MySQL:

CREATE TABLE t(i int);
INSERT INTO t VALUES (4),(2),(3),(6),(1),(5);

SELECT GROUP_CONCAT(i*2+1 ORDER BY 1 SEPARATOR '') FROM t;

group_concat(i*2+1 order by 1 separator '')
======================
  '35791113'

Довольно мощный, не так ли? И ниже альтернативное решение изначально поддерживается в CUBRID.

SELECT MAX(SYS_CONNECT_BY_PATH(s_name, '')) AS conc_s_name
FROM (
     SELECT ROWNUM AS r, s_name FROM code
) AS res
START WITH r = 1
CONNECT BY PRIOR r = r - 1;

Интересно, что этот способ объединения различных значений столбцов строк в CUBRID практически идентичен способу Oracle, предоставляемому @devio. В CUBRID это выглядит немного проще, хотя.

1 голос
/ 12 июня 2009

Вот ответ, который вы ищете; У меня было ощущение, что решение лежит в операции CONNECT BY, я просто раньше не использовал псевдостолбец SYS_CONNECT_BY_PATH (который отображает полный путь к узлу в дереве, разделяя имена узлов знаком "/"). Предполагая, что ваш набор значений "foo" перед этим состоит из нескольких строк в таблице, сгруппированных по столбцу "myKey", например ::

myKey    foo
-------- ----------
group 1  apple
group 1  orange
group 1  pear
group 2  ape
group 2  bear
group 2  kitten

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

  SELECT myKey
       , SUBSTR(MAX(REPLACE(SYS_CONNECT_BY_PATH(foo, '/')
                           ,'/'
                           ,' '
                           )
                   )
               ,2
               ) FooConcat
    FROM ( SELECT MyKey
                , Foo
                , row_number() OVER (Partition by myKey order by myKey) NodeDepth
             FROM MyTable
         )
   START WITH NodeDepth = 1
 CONNECT BY PRIOR myKey = myKey
     AND PRIOR NodeDepth = NodeDepth -1
GROUP BY myKey
;

Конечно, порядок сцепленных значений будет случайным; если в вашей таблице есть еще один столбец ("bar"), который вы можете использовать в качестве поля упорядочения, которое является восходящим и непрерывным, вы можете обойтись без подзапроса (который существует только для добавления мнимой глубины к дереву) и использовать таблицу напрямую, замена NodeDepth на полосу.

0 голосов
/ 12 апреля 2018

Я нашел ответ на Как объединить все записи в столбце, возвращенном запросом, в одну строку varchar в T-SQL?

declare @s varchar(8000)
select @s = coalesce(@s + col, col) from tbl

Это должно решить

0 голосов
/ 10 января 2015

SQL Server 2008 R2:

declare @ColumnNameList VARCHAR(MAX)


 SELECT @ColumnNameList  = COALESCE(@ColumnNameList +',' ,'') + ColumnName 
                     FROM 
                       <<table name>>

select @ColumnNameList 
0 голосов
/ 23 июня 2010

Выберите ([col1] + ',' + [col2] + ',' + [col3] + ',' + [col4]) как [MyCol] Из [Table]

0 голосов
/ 09 июня 2009

Возможно, это не то, что вы ищете, но в прошлом мне повезло с такими конструкциями:

SELECT      MAX(DECODE(fookey, 1, foo, NULL))
         || MAX(DECODE(fookey, 2, foo, NULL))
         || MAX(DECODE(fookey, 3, foo, NULL))
         || MAX(DECODE(fookey, 4, foo, NULL))
       , groupingvalue
    FROM mytable
GROUP BY groupingvalue;

Он не зависит от платформы и работает хорошо, когда у вас есть произвольное, но ограниченное количество значений для foo, и они основаны на каком-то другом значении ключа. Например, если у вас есть таблица счетов-фактур, и вы хотите увидеть все времена строк из счета-фактуры в одной строке, объединенные, и у вас есть верхний предел 5 позиций, это будет выглядеть так:

SELECT      MAX(DECODE(lineno, 1, foo, NULL))
         || ', '
         || MAX(DECODE(lineno, 2, foo, NULL))
         || ', '
         || MAX(DECODE(lineno, 3, foo, NULL))
         || ', '
         || MAX(DECODE(lineno, 4, foo, NULL))
         || ', '
         || MAX(DECODE(lineno, 5, foo, NULL))
       , invoiceid
    FROM lineitem
GROUP BY invoiceid;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...