在带有group by的查询中使用rand()时如何计算

t8e9dugd  于 2021-06-19  发布在  Mysql
关注(0)|答案(3)|浏览(340)

我有一些sql,我需要在查询中对一些行进行分组,并在分组后为每一行使用一个随机值,这样在分组后,随机值将均匀地分布在每一行,但我不确定mysql是如何处理这个问题的
请看这个非常简单的示例:

CREATE TABLE IF NOT EXISTS soldier (
     unit VARCHAR(255) NOT NULL,
     name VARCHAR(255) NOT NULL,
     personal_number INT
 ) 

select unit, count(name), rand()
   from soldier
   group by unit

所以我试着从一个单位输入3名士兵,从另一个单位输入一名士兵,随机列在结果集中的分布似乎很相似。但我怀疑可能发生的情况是,分组行的值总是从最小值的士兵行或从最大值的士兵行获取,然后分布会发生偏差。如果它是从任何一个分组士兵中随机抽取的,或者是平均值,或者是分组后计算出来的,我是好的(据我所知)。有人知道在这种情况下rand()是如何计算的吗?

nle07wnf

nle07wnf1#

我忘了基本的东西。您的查询按以下顺序计算:

FROM, GROUP BY, COUNT, SELECT

在您的示例中,mysql在选择之前创建两个组:
第一单元有三个士兵
第二单元有一个士兵
这个 RAND() 分组后每行调用一次函数。您当前形式的查询是正确的。
注意比 RAND() 可以在里面安全使用 SELECT 因为它是一个函数,而不是一个列引用。为了确定,我用一个udf替换了它,这个udf记录了它被调用的次数;你的例子打了两次电话。

wz1wpwve

wz1wpwve2#

我没有这方面的文档参考,但根据经验,我能够确定mysql似乎正在进行评估 rand() 之后 GROUP BY 聚合已完成。也就是说,它正在评估 rand() 每个组一次,而不是表中每个记录一次。我设置了以下测试:

WITH yourTable AS (
    SELECT 1 AS id, 3 AS val UNION ALL
    SELECT 1, 5 UNION ALL
    SELECT 2, 10
)

SELECT id, SUM(val) AS val_sum, rand()
FROM yourTable
GROUP BY id;

演示

为了证实 ONLY_FULL_GROUP_BY 模式已启用,我将查询更改为此,但失败:

SELECT id, SUM(val) AS val_sum, rand(), val   -- non aggregate column = failure
FROM yourTable
GROUP BY id;

因此,您当前的方法是为每个组选择随机值。请注意,即使是为每个记录选择随机值,然后选择某个最小记录,那么这些值仍然应该是随机的。

p8h8hvxi

p8h8hvxi3#

您可以使用交叉连接和子查询,例如:

select a.unit, a.num, t.rand
    from (
    select unit, count(name) as num, t.rand
       from soldier
       group by unit
    ) a
    cross join (
        select rand() as rand 
        from dual
    ) t

相关问题