我有一个clr聚合连接函数,类似于https://gist.github.com/FilipDeVos/5b7b4addea1812067b09。当行数很小时,连接字符串的顺序跟在输入数据集之后。当行数较大(几十个或更多)时,序列似乎不确定。执行计划有所不同,但我并不熟悉优化器以及应用的提示(我已尝试过MAXDOP 1,但没有成功)。从与下面的示例不同的测试中得到类似的结果,这似乎是计划中的差异 - 单独的排序,然后是合并连接。它倒在这里的行数是60。
以下是使用上述clr(重命名为TestConcatenate)演示AdventureWorks2014示例数据库中的问题的查询。预期结果是每个订单都有一行的数据集,以及按数量顺序列出该订单的产品的分隔列的列。
;with cte_ordered_steps AS (
SELECT top 100000 sd.SalesOrderID, SalesOrderDetailID, OrderQty
FROM [Sales].[SalesOrderDetail] sd
--WHERE sd.SalesOrderID IN (53598, 53595)
ORDER BY sd.SalesOrderID, OrderQty
)
select
sd.SalesOrderID,
dbo.TestConcatenate(' QTY: ' + CAST(sd.OrderQty AS VARCHAR(9)) + ': ' + IsNull(p.Name, ''))
FROM [Sales].[SalesOrderDetail] sd
JOIN [Production].[Product] p ON p.ProductID = sd.ProductID
JOIN cte_ordered_steps r ON r.SalesOrderID = sd.SalesOrderID AND r.SalesOrderDetailID = sd.SalesOrderDetailID
where sd.SalesOrderID IN (53598, 53595)
GROUP BY sd.SalesOrderID
当SalesOrderID约束在53598,53995的cte中时,序列是正确的(顶部设置),当它在53598,53595的主选择中受约束时,序列不是(按钮设置)。
那么我的问题是什么?如何构建查询,使用提示或其他更改来返回与行数无关的一致(和正确)顺序连接值。
答案 0 :(得分:2)
就像普通查询一样,如果没有order by子句,则无法保证返回顺序。如果我没记错的话,SQL 92规范允许order by子句通过over子句传递给聚合,SQL Server不实现它。因此,无法保证CLR函数的排序(除非您自己通过将Accumulate
和Merge
方法中的所有内容收集到某种集合中然后对{{1}中的列表进行排序来实现它返回它之前的方法。但是你需要支付内存授权的成本,因为现在需要序列化集合。
至于为什么你会根据结果集的大小看到不同的行为,我注意到两者之间正在使用不同的连接运算符。循环连接和合并连接遍历两个以不同方式连接的集合,因此可能会考虑到您所看到的差异。
答案 1 :(得分:1)
为什么不尝试http://groupconcat.codeplex.com处提供的聚合dbo.GROUP_CONCAT_S。 S用于分类输出。它完全符合您的要求。
答案 2 :(得分:0)
虽然这个答案没有解决方案,但Ben和Orlando提供的其他信息(谢谢!)提供了我需要继续前进的内容。我将采用奥兰多指出的方法,这也是我的计划B,即在clr中进行排序。