SQL连接多行

时间:2013-10-25 16:37:21

标签: teradata concat partition

我正在使用Teradata,我有一个这样的表

ID       String
123      Jim
123      John
123      Jane
321      Jill
321      Janine
321      Johan

我想查询表格,所以我得到

ID       String
123      Jim, John, Jane
321      Jill, Janine, Johan

我尝试过分区,但可以有很多名字。 我如何得到这个结果。甚至,指出我正确的方向将是伟大的。

3 个答案:

答案 0 :(得分:8)

不幸的是Teradata没有PIVOT(14.10只有TD_UNPIVOT)。

如果你运气好,你的网站上会有一个聚合UDF进行群组连接(可能性很小)。

否则有两种选择:递归或聚合。

如果已知每个id的最大行数,则聚合通常更快。这是很多代码,但大部分是基于剪切和粘贴。

SELECT
  id,
     MAX(CASE WHEN rn = 1 THEN string END)
  || MAX(CASE WHEN rn = 2 THEN ',' || string ELSE '' END)
  || MAX(CASE WHEN rn = 3 THEN ',' || string ELSE '' END)
  || MAX(CASE WHEN rn = 4 THEN ',' || string ELSE '' END)
  || ... -- repeat up to the known maximum
FROM
 (
   SELECT
      id, string, 
      ROW_NUMBER() 
      OVER (PARTITION BY id
            ORDER BY string) AS rn
   FROM t
 ) AS dt
GROUP BY 1;

对于大型表,当您首先使用GROUP BY列作为PI实现Volatile Table中的派生表的结果时,效率会更高。

对于递归,您也应该使用易失性表,因为递归部分中不允许OLAP函数。相反,使用视图会重复计算OLAP功能,从而导致性能下降。

CREATE VOLATILE TABLE vt AS
 (
   SELECT
      id
      ,string
      ,ROW_NUMBER()
       OVER (PARTITION BY id
             ORDER BY string DESC) AS rn -- reverse order!
      ,COUNT(*)
       OVER (PARTITION BY id) AS cnt
   FROM t
 ) WITH DATA 
UNIQUE PRIMARY INDEX(id, rn)
ON COMMIT PRESERVE ROWS;

WITH RECURSIVE cte
(id, list, rn) AS
 (
   SELECT
      id
      ,CAST(string AS VARCHAR(1000)) -- define maximum size based on maximum number of rows 
      ,rn
   FROM vt
   WHERE rn = cnt

   UNION ALL

   SELECT
      vt.id
      ,cte.list || ',' || vt.string
      ,vt.rn
   FROM vt
   JOIN cte
   ON vt.id = cte.id
   AND vt.rn = cte.rn - 1
)
SELECT id, list
FROM cte
WHERE rn = 1;

这种方法存在一个问题,它可能需要大量的假脱机,当您省略WHERE rn = 1时很容易看到。

答案 1 :(得分:2)

SELECT ID,  
TRIM(TRAILING ',' FROM (XMLAGG(TRIM(String)|| ',' ORDER BY String) (VARCHAR(10000)))) as Strings
FROM db.table
GROUP BY 1  

答案 2 :(得分:0)

SQL Server 2017+ 和 SQL Azure:STRING_AGG

从下一版本的 SQL Server 开始,我们最终可以跨行串联,而无需求助于任何变量或 XML 巫术。

STRING_AGG (Transact-SQL)

SELECT ID, STRING_AGG(String, ', ') AS Strings
FROM TableName
GROUP BY ID