SQL Server 2000:用于执行连接聚合子查询的想法

Ian*_*oyd 7 sql-server aggregate sql-server-2000 concatenation string-concatenation

我有一个返回我想要的行的查询,例如

QuestionID  QuestionTitle  UpVotes  DownVotes  
==========  =============  =======  =========  
2142075     Win32: Cre...        0          0  
2232727     Win32: How...        2          0  
1870139     Wondows Ae...       12          0  
Run Code Online (Sandbox Code Playgroud)

现在我希望返回一个列,其中包含逗号分隔的" 作者 " 列表(例如原始海报和编辑).例如:

QuestionID  QuestionTitle  UpVotes  DownVotes  Authors
==========  =============  =======  =========  ==========
2142075     Win32: Cre...        0          0  Ian Boyd  
2232727     Win32: How...        2          0  Ian Boyd, roygbiv
1870139     Wondows Ae...       12          0  Ian Boyd, Aaron Klotz, Jason Diller, danbystrom
Run Code Online (Sandbox Code Playgroud)


假装

SQL Server 2000没有CONCAT(AuthorName, ', ')聚合操作,我一直伪造它 - 为TOP 1作者执行简单的子选择,并且作者计数.

QuestionID  QuestionTitle  UpVotes  DownVotes  FirstAuthor  AuthorCount  
==========  =============  =======  =========  ===========  =========== 
2142075     Win32: Cre...        0          0  Ian Boyd               1 
2232727     Win32: How...        2          0  Ian Boyd               2
1870139     Wondows Ae...       12          0  Ian Boyd               3
Run Code Online (Sandbox Code Playgroud)

如果有多个作者,那么我向用户显示一个省略号("..."),表示有多个.例如,用户会看到:

QuestionID  QuestionTitle  UpVotes  DownVotes  Authors
==========  =============  =======  =========  ==========
2142075     Win32: Cre...        0          0  Ian Boyd
2232727     Win32: How...        2          0  Ian Boyd, …
1870139     Wondows Ae...       12          0  Ian Boyd, …
Run Code Online (Sandbox Code Playgroud)

这样做效果很好,因为通常一个问题不会被编辑 - 这意味着我完全支持99%的情况,而1%的情况只有一半-也是.


线程重新查询

作为一个更复杂,容易出错的解决方案,我正在考虑迭代显示的列表,并为列表中的每个" 问题 " 启动线程池工作线程,对数据库执行查询以获取作者列表,然后在内存中聚合列表.这意味着列表首先填充(本机)应用程序.然后我发出几千个单独的查询.

但那将是可怕的,可怕的,非常的,缓慢的.更不用说bug了,因为它将是线程工作.


耶耶耶

亚当机械师说得很明白:

不要将行连接到SQL Server中的分隔字符串.做客户端.

告诉我怎么做,我会做的.


/哭

任何人都可以想到一个更好的解决方案,就像我原来的"TOP 1加省略号"解决方案一样快(比如......在一个数量级内)?

例如,有没有办法返回结果集,其中到达行有一个关联的结果集?因此,对于每个"主"行,我可以获得包含列表的"详细信息"结果集.


代码为最佳答案

Cade与Adam Machanic解决方案的链接我最喜欢.用户定义的函数,似乎通过魔术操作:

CREATE FUNCTION dbo.ConcatAuthors(@QuestionID int)
RETURNS VARCHAR(8000)
AS
BEGIN
    DECLARE @Output VARCHAR(8000)
    SET @Output = ''

    SELECT @Output =    CASE @Output 
                WHEN '' THEN AuthorName 
                ELSE @Output + ', ' + AuthorName 
                END
    FROM  (
        SELECT QuestionID, AuthorName, QuestionDate AS AuthorDate FROM Questions
        UNION
        SELECT QuestionID, EditorName, EditDate FROM QuestionEdits
    ) dt
    WHERE dt.QuestionID = @QuestionID
    ORDER BY AuthorDate

    RETURN @Output
END
Run Code Online (Sandbox Code Playgroud)

使用T-SQL:

SELECT QuestionID, QuestionTitle, UpVotes, DownVotes, dbo.ConcatAuthors(AuthorID)
FROM Questions
Run Code Online (Sandbox Code Playgroud)

Cad*_*oux 3

看看这些文章:

http://dataeducation.com/rowset-string-concatenation-which-method-is-best/

http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/(请参阅响应中 Phil Factor 的交叉联接解决方案 - 这将在 SQL Server 2000 中工作)

显然,在 SQL Server 2005 中,FOR XML 技巧是最简单、最灵活且通常性能最高的。

至于为每行返回一个行集,如果由于某种原因您仍然想这样做,您可以在存储过程中执行此操作,但客户端将需要消耗第一个行集中的所有行,然后转到下一个行集并将其与第一个行集中的第一行关联起来,等等。您的 SP 需要在作为第一个行集返回的同一集上打开一个游标,并按顺序运行多个选择以生成所有子行集。这是我已经完成的一项技术,但仅限于实际需要所有数据的情况(例如,在完全填充的树视图中)。

不管人们怎么说,在客户端执行此操作通常会浪费大量带宽,因为返回所有行并在客户端执行循环和中断意味着在开始时会传输大量相同的列。每行只是为了获取行末尾的变化列。

无论您在何处执行此操作,都应该根据您的用例做出明智的决定。