我有一些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()?
答案 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;
要验证是否启用了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在选择之前创建了两个组:
分组后,每行 都会调用一次RAND()
函数。您当前的查询形式是正确的。
请注意,RAND()
可以在SELECT
内部安全使用,因为它是一个函数,而不是列引用。而且可以肯定的是,我用一个UDF代替了它,它记录了它被调用了多少次。在您的示例中,它两次被调用。