使用带有CTE的NEWID()来生成行的随机子集会产生奇数结果

时间:2013-06-14 14:27:34

标签: sql-server stored-procedures sql-server-2008-r2 newid

我在存储过程中编写了一些SQL,以将数据集减少为我想要报告的有限随机行数。

报告以Group Users开头,并应用过滤器来指定所需的随机行总数(@SampleLimit)。

为了达到预期的效果,我首先创建一个CTE(临时表):

  • top(@SampleLimit)已应用
  • group by UserId(因为UserID多次出现)
  • order by NEWID()将结果按随机顺序排列

SQL:

; with cte_temp as 
       (select top(@SampleLimit) UserId from QueryResults 
        where (GroupId = @GroupId)
        group by UserId order by NEWID()) 

我有了这个结果集,然后删除UserId在上一步中创建的CTE NOT IN的任何结果。

delete QueryResults 
where (GroupId = @GroupId) and (UserId not in(select UserId from cte_temp))

我遇到的问题是,我不时会得到比@SampleLimit中指定的结果更多的结果,有时候它的效果与预期完全相同。

我已经尝试分解SQL并在应用程序之外执行它,但我无法重现该问题。

我正在做的事情有什么根本性的错误可以解释为什么我偶尔会得到更多我要求的结果?

为了完整性 - 我的重新考虑的解决方案基于以下答案:

select top(@SampleLimit) UserId into #T1
from  QueryResults
where (GroupId = @GroupId)
group by UserId
order by NEWID() 

delete QueryResults 
where (GroupId = @GroupId) and (UserId not in(select UserId from #T1))

1 个答案:

答案 0 :(得分:5)

涉及SELECT的{​​{1}}语句执行的次数是不确定的。

如果在NEWID()QueryResults之间获得嵌套循环反半连接,并且计划中没有假脱机,则可能会重新评估{{1}中的行数次这意味着对于每个外行,与cte_temp进行比较的集合可能完全不同。

您可以将结果具体化为临时表,而不是使用CTE来避免这种情况。

QueryResults

然后在NOT IN

中引用它