Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在SQL中的select语句中分配随机值?_Sql_Sql Server - Fatal编程技术网

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

如何在SQL中的select语句中分配随机值?,sql,sql-server,Sql,Sql Server,我想为另一个表的每一行选择一个表的随机值 我有以下代码: 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

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

我有以下代码:

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

添加的子句
其中t1.col1不为null
将强制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
,其中100000行的数字范围为1到100000,还有一个表
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中运行了它们,并比较了它们的执行计划和性能:

从这个屏幕截图中可以看到,行数查询在233毫秒内完成,子查询变量用了289950毫秒。大约是原来的1200倍

当您查看执行计划时,会发现发生了什么:

行数

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
;

在这里,
数字
表被扫描和排序13880次


为了说明这个概念,我保持了RowNumber变量的简单性。如果
T1
的行数大于
T2
,则它将无法正常工作


修复它很容易,不过在计算行号之前,可以根据需要多次将
T2
交叉连接到自身,以生成足够的行。

太好了!我的答案要长得多:(我觉得我的sqlserver技能已经锈坏了)@Ingaz,Gordon的查询为
T1
的每一行运行子查询。它可能相当慢。最好是枚举T2中的行,并将两个表按随机行号连接在一起。因此,表格将只扫描一次。我将在我的系统上进行测试并写出答案。是的。我的变体必须更有效,但:当第一个表大于第二个表时,它会崩溃。Gordon variant永不中断。@Ingaz,效率取决于表格的大小。在我的测试中,差异是1200倍。看看我的答案。如果有人关心大桌子上的效率,他们应该问另一个问题,并提供更详细的信息。弗拉基米尔,这很好,但OP从未问过“如何有效地做”。所以我更喜欢他的变种,而不是我的或你的。@Ingaz,没问题。我只是无法通过它,因此发布了第二个答案。这完全取决于未来阅读本文的人来决定他们更喜欢哪种变体。