【问题标题】:Concat all column values in sql连接sql中的所有列值
【发布时间】:2010-11-01 12:17:41
【问题描述】:

如何将 sql 查询返回的不同行中的所有列值合并为一个值?这是一个例子:

一个查询返回:

食品 ------ RES1 RES2 RES3

现在我想得到如下结果:

福康猫 ----- RES1RES2RES3

有没有办法在sql中做到这一点?

【问题讨论】:

  • 您使用的是哪台服务器?我怀疑是否有通用的 SQL 方法可以做到这一点,但肯定有特定于实现的方法。
  • 我正在使用 Oracle。我很惊讶在 oracle 中没有简单的方法来做到这一点。

标签: sql concatenation


【解决方案1】:

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

【讨论】:

  • 看起来是一个解决方案,但在 oracle 中会是什么样子?
  • 这是 SQL Server 中的一个很酷的技巧,我只需将选择更改为:SELECT REPLACE(REPLACE(col1, '', ''), '', '' )
  • @Quassnoi - 我得到“列名 'Text()' 包含 FOR XML 要求的无效 XML 标识符;'('(0x0028) 是错误的第一个字符。”在 SQL Server 2005 上
  • 哦,[text()] 区分大小写,我在尝试 [Text()]。
  • 这是另一种 SQL Server 方法:DECLARE @c AS VARCHAR(4000); SET @c=''; SELECT @c= @c + col1 FROM Foo 选择 @c;
【解决方案2】:

Quassnoi 的 Oracle 解决方案令人印象深刻,但我 found simpler 使用 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】:

    mysql方式:

    select group_concat(somecolumn separator '') from sometable
    

    【讨论】:

    • 结果不是我所需要的,但我可以说这在某个时候会非常有用
    【解决方案4】:

    假设它是具有多个值的一列,这种方法适用于 MS SQL Server(我不能代表其他系统)。

    declare @result varchar(max)
    set @result = ''
    
    select @result = @result + RES
    from (query goes here)
    

    【讨论】:

      【解决方案5】:

      这是您要寻找的答案;我感觉解决方案在于 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”),您可以将其用作升序且连续的排序字段,则可以省去子查询(它的存在只是为了给树添加一个虚构的深度)并直接使用该表,用 bar 替换 NodeDepth。

      【讨论】:

        【解决方案6】:

        编辑: 从 8.4.0 版开始,CUBRID 为 MySQL 提供了90% compatibility。因此,它支持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 原生支持的 alternative solution

        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 中连接不同行列值的方式与 @devio 提供的 Oracle 方式几乎相同。不过在 CUBRID 中它看起来更容易一些。

        【讨论】:

          【解决方案7】:

          我在How to concatenate all the records in a column returned by a query into one varchar string in T-SQL?找到了答案

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

          这应该可以解决

          【讨论】:

            【解决方案8】:
            select cast(res1 as varchar)+cast(res2 as varchar)+cast(res3 as varchar) as fooconcat from foo
            

            如果列已经是不需要强制转换的字符串,则可以这样做:

            select res1 + res2 + res3  as fooconcat from foo
            

            对于多行数据,使用PIVOT

            【讨论】:

            • 你如何对任意数量的值做同样的事情?
            • res1、res2 和 res3 不是列而是值。该列是“foo”。
            • 抱歉,当我回答这个问题时,您的数据全部格式化在一行上,所以问题似乎是另一个问题。
            【解决方案9】:

            连接字符串取决于您使用的数据库(您没有提到问题中的版本,所以这里是)...

            在 Oracle 和 DB2 中,您可以使用 CONCAT 函数...CONCAT(string, string)

            SQL Server 你可以使用'+'操作符...string1 + string2 + string3

            在 MySQL 中是CONCAT(string, string... n_string)

            最后在 PostgreSQL 中是TEXTCAT(string, string)...

            ...我从 O'Reilly 的 SQL 袖珍指南中的这本很酷的小书中得到了这个...看看!

            :)

            【讨论】:

            • 我知道你的意思,你会做类似...选择@Text = @Text + RES,或选择@Text = CONCAT(@Text, RES) 等来连接列。
            • 不回答问题
            【解决方案10】:

            这可能不是你要找的东西,但我过去运气不错,有这样的结构:

            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;
            

            【讨论】:

              【解决方案11】:

              SQL Server 2008 R2:

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

              【讨论】:

                【解决方案12】:

                Select ([col1] +','+[col2]+','+ [col3]+','+[col4]) as [MyCol] From [Table]

                【讨论】:

                • 目标是连接行,而不是列
                猜你喜欢
                • 2016-04-20
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-02-21
                • 1970-01-01
                • 2013-07-17
                • 1970-01-01
                相关资源
                最近更新 更多