【问题标题】:CONCAT(column) OVER(PARTITION BY...)? Group-concatentating rows without grouping the result itselfCONCAT(column) OVER(PARTITION BY ...)?分组连接行而不分组结果本身
【发布时间】:2012-08-19 03:12:00
【问题描述】:

我需要一种方法来在一种窗口函数中连接所有行(每组),例如您可以如何执行COUNT(*) OVER(PARTITION BY...) 并且每组所有行的总计数将在每个特定组中重复。我需要类似的东西,但每组所有值的字符串连接在每组中重复。

这是一些示例数据和我想要的结果,以更好地说明我的问题:

grp  |  val
------------
1    |  a
1    |  b
1    |  c
1    |  d
2    |  x
2    |  y
2    |  z

这就是我需要的(期望的结果):

grp  |   val  |  groupcnct
---------------------------------
1    |   a    |  abcd
1    |   b    |  abcd
1    |   c    |  abcd
1    |   d    |  abcd
2    |   x    |  xyz
2    |   y    |  xyz
2    |   z    |  xyz

这是这个问题真正棘手的部分:

我的特殊情况使我无法两次引用同一个表(我实际上是在递归 CTE 中执行此操作,因此我无法对 CTE 进行自联接,否则会引发错误)。

我完全知道人们可以这样做:

SELECT      a.*, b.groupcnct
FROM        tbl a
CROSS APPLY (
            SELECT STUFF((
                        SELECT '' + aa.val 
                        FROM   tbl aa
                        WHERE  aa.grp = a.grp
                        FOR XML PATH('')
                   ), 1, 0, '') AS groupcnct
            ) b

但如您所见,即在查询中引用了tbl 两次

我只能引用tbl 一次,因此我想知道是否可以将组连接窗口化(我对 TSQL 有点陌生,因为我来自 MySQL 背景,所以不确定是否可以做类似的事情。


创建表:

CREATE TABLE tbl
    (grp int, val varchar(1));

INSERT INTO tbl
    (grp, val)
VALUES
    (1, 'a'),
    (1, 'b'),
    (1, 'c'),
    (1, 'd'),
    (2, 'x'),
    (2, 'y'),
    (2, 'z');

【问题讨论】:

  • @PankajGarg 这实际上是一个结果,而不是一个表格。查询已经在递归 CTE 中完成,因此不能选择使用 CTE。我需要这个的原因是因为我在使用 CTE 遍历表时试图跟踪以前递归层的值。
  • 如果没有递归查询,这个问题没有多大意义。您始终可以将查询结果输出到临时表中,并对其进行分组连接。
  • 引用递归版本指出选择那种方式不好:stackoverflow.com/questions/11137075/…最好用XML PATH

标签: sql sql-server sql-server-2008 tsql string-aggregation


【解决方案1】:

在 sql 2017 中可以使用 STRING_AGG 函数:

SELECT STRING_AGG(T.val, ',') AS val
    , T.grp
FROM @tbl AS T
GROUP BY T.grp

【讨论】:

  • 为了让你的答案更好,你应该解释STRING_AGG函数的用途。
【解决方案2】:

我尝试使用纯 CTE 方法:Which is the best way to form the string value using column from a Table with rows having same ID? Thinking 它更快

但基准测试表明,最好使用来自XML PATH 的子查询(或CROSS APPLY)结果,因为它们更快:Which is the best way to form the string value using column from a Table with rows having same ID?

【讨论】:

    【解决方案3】:
    DECLARE @tbl TABLE
    (
        grp INT
        ,val VARCHAR(1)
    ); 
    
    BEGIN
     INSERT INTO @tbl(grp, val)
    VALUES
        (1, 'a'),
        (1, 'b'),
        (1, 'c'),
        (1, 'd'),
        (2, 'x'),
        (2, 'y'),
        (2, 'z');
    END;
    ----------- Your Required Query
    SELECT  ST2.grp, 
    SUBSTRING(
                (
                    SELECT ','+ST1.val  AS [text()]
                    FROM @tbl ST1
                    WHERE ST1.grp = ST2.grp
                    ORDER BY ST1.grp
                    For XML PATH ('')
                ), 2, 1000
           ) groupcnct
    FROM @tbl ST2
    

    【讨论】:

    • 请始终解释为什么您认为您的代码解决了 OP 的问题。 “为什么”比仅仅修复更有趣。
    【解决方案4】:

    您是否可以只将您的东西放在选择中,或者您是否遇到了同样的问题? (我将 'tbl' 替换为 'TEMP.TEMP123')

    Select 
    A.*
    , [GROUPCNT] = STUFF((
                            SELECT '' + aa.val 
                            FROM  TEMP.TEMP123 AA
                            WHERE  aa.grp = a.grp
                            FOR XML PATH('')
                       ), 1, 0, '') 
    
    
     from TEMP.TEMP123 A
    

    这对我有用——想看看这是否也对你有用。

    【讨论】:

      【解决方案5】:

      我知道这篇文章很旧,但以防万一,有人仍然想知道,您可以创建连接行值的标量函数。

      IF OBJECT_ID('dbo.fnConcatRowsPerGroup','FN') IS NOT NULL
      DROP FUNCTION dbo.fnConcatRowsPerGroup
      GO
      CREATE FUNCTION dbo.fnConcatRowsPerGroup 
          (@grp as int) RETURNS VARCHAR(MAX)
      AS 
      BEGIN
          DECLARE @val AS VARCHAR(MAX)
      
          SELECT @val = COALESCE(@val,'')+val
          FROM tbl
          WHERE grp = @grp
      
          RETURN @val;
      END
      GO
      
      
      select *, dbo.fnConcatRowsPerGroup(grp)
      from tbl
      

      这是我通过查询示例表得到的结果集:

      grp  |   val  |  (No column name)
      ---------------------------------
      1    |   a    |  abcd
      1    |   b    |  abcd
      1    |   c    |  abcd
      1    |   d    |  abcd
      2    |   x    |  xyz
      2    |   y    |  xyz
      2    |   z    |  xyz
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多