SQL Server 2000:执行串联聚合子查询的想法

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

QuestionID  QuestionTitle  UpVotes  DownVotes  
==========  =============  =======  =========  
2142075     Win32: Cre...        0          0  
2232727     Win32: How...        2          0  
1870139     Wondows Ae...       12          0  

现在我想要返回一个 ,其中包含逗号分隔的“作者”列表(例如原始海报和编辑)。 例如:

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


作假

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

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

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, …

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


线程重新查询

作为一个更复杂,更容易出错的解决方案,我正在考虑迭代显示的列表,并为列表中的每个“问题”旋转一个线程池工作线程,对数据库执行查询以获取作者列表,然后在内存中汇总列表。 这意味着该列表首先在(本地)应用程序中填充。 然后我发布了几千个人查询。

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


耶耶耶

Adam Mechanic很明显地说:

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

告诉我如何,我会做。


/哭

任何人都可以想到一个更好的解决方案,就像我最初的“TOP 1 plus椭圆”解决方案一样快(例如......在一个数量级内)?

例如,有没有办法返回一个结果集,其中reach行具有关联的结果集? 因此,对于每个“主”行,我都可以得到包含列表的“详细”结果集。


代码为最佳答案

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

使用以下T-SQL用法:

SELECT QuestionID, QuestionTitle, UpVotes, DownVotes, dbo.ConcatAuthors(AuthorID)
FROM Questions

看看这些文章:

http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/rowset-string-concatenation-which-method-is-best.aspx

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需要在与第一个行集相同的集上打开一个游标,然后按顺序运行多个选择来生成所有子行集。 这是我所做的一项技术,但只有在实际需要所有数据的情况下(例如,在完全填充的树视图中)。

不管人们怎么说,做客户端往往是带宽的一个非常大的浪费,因为返回所有行并在客户端进行循环和断开意味着大量相同的列在开始时被传输每行只是为了在行的末尾获得变化的列。

无论您在哪里做,都应该根据您的使用情况作出明智的决定


我尝试了3种解决方案,一种是在这里发布的,activex脚本和UDF函数。

对我来说,最有效的脚本(速度方面)是令人惊叹的Axtive-X脚本,它运行多个查询来获取additioanl数据。

UDF平均需要22分钟才能完成转换,Subquery方法(在此处张贴)花费了大约5分钟,而activeX脚本花费了4分30秒,这让我很烦恼,因为这是我希望挖掉的脚本。 我必须看看我能否在其他地方提高效率。

我认为额外的30s被tempdb用于存储数据,因为我的脚本需要按顺序。

应该指出,我正在连接大量的文本数据。


你也可以看看这个脚本。 这基本上是Cade Roux在他的文章中提到的交叉连接方法。

上面的方法看起来非常干净:您必须首先执行视图,然后根据视图中的值创建语句。 您可以在代码中动态构建第二个sql语句,因此应该直接使用。

链接地址: http://www.djcxy.com/p/45131.html

上一篇: SQL Server 2000: Ideas for performing concatenation aggregation subquery

下一篇: ASP.MVC routes without Details action