11

我需要一种方法来在一种窗口函数中连接所有行(每组),就像你可以做的那样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');
4

5 回答 5

2

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

SELECT STRING_AGG(T.val, ',') AS val
    , T.grp
FROM @tbl AS T
GROUP BY T.grp
于 2018-06-04T13:28:25.563 回答
1

我尝试使用纯 CTE 方法:使用具有相同 ID 的行的表中的列来形成字符串值的最佳方法是什么?认为它更快

但是基准测试表明,最好使用子查询(或CROSS APPLY)结果,XML PATH因为它们更快:使用具有相同 ID 的行的表中的列形成字符串值的最佳方法是哪个?

于 2012-08-19T07:37:13.657 回答
0
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
于 2015-05-07T13:13:54.353 回答
0

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

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
于 2018-07-12T04:14:17.883 回答
0

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

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

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

于 2018-06-01T22:38:28.233 回答