在GROUP BY查询中使用rand()时如何计算

时间:2018-10-22 09:38:06

标签: mysql sql

我有一些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名士兵,从另一单位输入1名士兵, 并且随机列在结果集中的分布似乎非常相似。但我怀疑 可能发生的情况是,可能总是从最小值的士兵行或最大值的士兵行获取分组行的值,然后分配会偏斜。如果是OTOH,则从任何 分组士兵,或平均,或分组后计算,我很好(据我所知)。 有谁知道在这种情况下如何计算rand()?

3 个答案:

答案 0 :(得分:2)

我没有文档参考,但是凭经验我可以确定在rand()聚合完成之后,MySQL似乎正在评估GROUP BY 。也就是说,它对每个 group 评估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;

Demo

要验证是否启用了ONLY_FULL_GROUP_BY模式,我将查询更改为此,但失败:

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

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

答案 1 :(得分:1)

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

    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 

答案 2 :(得分:1)

我忘记了基础知识。您的查询将按以下顺序进行评估

FROM, GROUP BY, COUNT, SELECT

在您的示例中,MySQL在选择之前创建了两个组:

  • 第1单元,有3名士兵
  • 第2单元,一名士兵

分组后,每行 都会调用一次RAND()函数。您当前的查询形式是正确的。

请注意,RAND()可以在SELECT内部安全使用,因为它是一个函数,而不是列引用。而且可以肯定的是,我用一个UDF代替了它,它记录了它被调用了多少次。在您的示例中,它两次被调用。