繁体   English   中英

如何在SQL中的select语句中分配随机值?

[英]How to assign a random value in a select statement in SQL?

我想为另一个表的每一行选择一个表的随机值。

我有以下代码:

SELECT T1.COL1,(SELECT TOP 1 t2.COL2 FROM T2 ORDER BY NEWID())FROM T1

我理解它不起作用的原因。 它从T2中选择一个随机值,但从T1中选择的每一行都是相同的。

谢谢。

这是SQL Server的棘手部分。 在优化查询方面有点过于激进。 您可以使用关联子句来阻止这种情况:

SELECT T1.COL1,
       (SELECT TOP 1 t2.COL2 FROM T2 where t1.col1 is not null ORDER BY NEWID() )
FROM T1

where t1.col1 is not null的added子句将强制SQL Server计算每行的子查询。 如果没有这个,就像在原始查询中一样,子查询被计算一次,然后被缓存。

Gordon建议的查询是正确的,它会产生预期的结果,但如果你的表有多个行,那么效率很低。

我在这里重复一遍:

SELECT T1.COL1,
       (SELECT TOP 1 t2.COL2 FROM T2 where t1.col1 is not null ORDER BY NEWID() )
FROM T1

本质上,它为T1表的每一行运行子查询。 子查询读取整个T2表,对整个表进行排序,选择一行并丢弃其余的表。 T2表被扫描的次数与T1中的行数一样多。

查询可以为T1不同行返回相同的值t2.COL2

如果这是“随机选择”定义的要求和部分,那么你就无法做很多事情。

但是,如果没有这样的要求并且允许在没有重复的情况下逐行映射两个表,那么通过仅扫描源表一次就可以更快地完成它。

在我的测试SQL Server 2008中我有一个表Numbers与数100,000行从1至100,000和表Calendar从2000-01-01到2037年12月31日(13880行)的日期。

所以,我写了两个问题:

行号

WITH
CTE1
AS
(
    SELECT
        T1.dt
        ,ROW_NUMBER() OVER (ORDER BY dt) AS rn1
    FROM dbo.Calendar AS T1
)
,CTE2
AS
(
    SELECT
        T2.Number
        ,ROW_NUMBER() OVER (ORDER BY NEWID()) AS rn2
    FROM dbo.Numbers AS T2
)
SELECT
    CTE1.dt
    ,CTE2.Number
FROM
    CTE1
    INNER JOIN CTE2 ON CTE1.rn1 = CTE2.rn2
;

子查询

SELECT T1.dt,
    (SELECT TOP 1 t2.Number FROM dbo.Numbers AS T2 where t1.dt is not null ORDER BY NEWID() )
FROM dbo.Calendar AS T1
;

我在SQL Sentry Plan Explorer中运行它们并比较它们的执行计划和性能:

统计

从这个屏幕截图中可以看出,RowNumber查询在233毫秒内完成,而子查询变体在289,950毫秒内完成。 大约1200倍以上。

当您查看执行计划时,会发生什么变得明显:

ROWNUMBER

ROWNUMBER

您可以看到两个表都扫描一次并合并连接在一起。

子查询

子查询

这里, Numbers表被扫描并排序13880次。


我保持RowNumber变体简单来说明这个概念。 如果T1行数多于T2 ,则无法按预期工作。

虽然通过在计算行数之前将T2连接到自身多次以生成足够的行,但很容易修复它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM