MySQL 将 rand() 的顺序修改为其他方法

MySQL modifying order by rand() to other methods

我现在正尝试从每个分组列数组中随机选择,机会后跟每一行的权重。例如,我有一个像这样的 table (DemoTable): http://sqlfiddle.com/#!9/23470/3/0

姓名 年级 体重
约翰 纽约 100 1
利亚姆 纽约 90 2
奥利维亚 纽约 90 3
艾玛 纽约 80 4
詹姆斯 CA 10 1
亨利 CA 20 1
米娅 新泽西州 50 1
艾娃 新泽西州 30 4

对于State = 'NY',有四行成绩数组:[100, 90, 90, 80] 和权重[1, 2, 3, 4]。因此 80 被选中的机会最大,而 100 在其州组中被选中的机会最少。 我查询了一下:

SELECT a.*,
(SELECT b.Grade FROM DemoTable b WHERE a.State = b.State 
ORDER BY RAND() * -b.Weight LIMIT 1) AS 'random_val' FROM DemoTable a;

它的结果是:

姓名 年级 体重 random_val
约翰 纽约 100 1 80
利亚姆 纽约 90 2 80
奥利维亚 纽约 90 3 80
艾玛 纽约 80 4 90
詹姆斯 CA 10 1 20
亨利 CA 20 1 10
米娅 新泽西州 50 1 30
艾娃 新泽西州 30 4 30

虽然,我想知道是否有任何其他方法,如 join 或 union,而不是单独使用 order by rand()。
是否有任何其他方法来修改我的 MySQL 查询以提供相同的结果?
我整天都在寻找解决这个问题的方法,但找不到合适的方法;这就是为什么我在这里请求帮助。
如果能得到一些建议,我将不胜感激。

我第一次尝试使用分析函数,但我怀疑你的函数在更大的数据集上更快...

WITH
  ranged AS
(
  SELECT
    *,
    SUM(weight) OVER (PARTITION BY state ORDER BY id) - weight   AS weight_range_lower,
    SUM(weight) OVER (PARTITION BY state ORDER BY id)            AS weight_range_upper,
    SUM(weight) OVER (PARTITION BY state            ) * rand()   AS rand_threshold
  FROM
    DemoTable
)
SELECT
  ranged.*,
  lookup.grade   AS random_grade
FROM
  ranged
INNER JOIN
  ranged  AS lookup
    ON  lookup.state               = ranged.state
    AND lookup.weight_range_lower <= ranged.rand_threshold
    AND lookup.weight_range_upper >  ranged.rand_threshold
ORDER BY
  ranged.id

或者,如果您希望为同一州的所有成员提供相同的 random_grade...

SELECT
  *,
  FIRST_VALUE(grade) OVER (PARTITION BY state ORDER BY weight * rand() DESC)
FROM
  DemoTable
ORDER BY
  id

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=133f9e86b013a477ac342d0295132dd5