How to select one row randomly taking into account a weight?

后端 未结 7 2000
一生所求
一生所求 2020-11-29 11:58

I have a table which looks like that:

id: primary key
content: varchar
weight: int

What I want to do is randomly select one row from this t

7条回答
  •  被撕碎了的回忆
    2020-11-29 12:51

    This one seems to work, but I'm not sure of the math behind it.

    SELECT RAND() / t.weight AS w, t.* 
    FROM table t 
    WHERE t.weight > 0
    ORDER BY 1
    LIMIT 1
    

    My guess at the reason it works is that the ascending order looks for the smallest results and by dividing by the weight for higher weights the random result is clustered more tightly near zero.

    I tested it (actually the same algorithm in postgresql) with 209000 queries over 3000 rows and the weight representation came out correct.

    my input data:

    select count(*),weight from t group by weight
     count | weight 
    -------+--------
      1000 |     99
      1000 |     10
      1000 |    100
    (3 rows)
    

    my results:

    jasen=# with g as ( select generate_series(1,209000) as i )
    ,r as (select (  select t.weight as w 
        FROM  t 
        WHERE t.weight > 0
        ORDER BY ( random() / t.weight ) + (g.i*0)  LIMIT 1 ) from g)
    
    select r.w, count(*), r.w*1000 as expect from r group by r.w;
    
      w  | count | expect 
    -----+-------+--------
      99 | 98978 |  99000
      10 | 10070 |  10000
     100 | 99952 | 100000
    (3 rows)
    

    The +(g.i*0) has no effect on the arithmetic result but an external reference is required to to force the planner to re-evaluate the sub-select for each of the 209K input rows produced in in g

提交回复
热议问题