sql server - Random Weighted Choice in T-SQL -


how randomly select table row in t-sql based on applied weight candidate rows?

for example, have set of rows in table weighted @ 50, 25, , 25 (which adds 100 not need to), , want select 1 of them randomly statistical outcome equivalent respective weight.

dane's answer includes self joins in way introduces square law. (n*n/2) rows after join there n rows in table.

what more ideal able parse table once.

declare @id int, @weight_sum int, @weight_point int declare @table table (id int, weight int)  insert @table(id, weight) values(1, 50) insert @table(id, weight) values(2, 25) insert @table(id, weight) values(3, 25)  select @weight_sum = sum(weight) @table  select @weight_point = floor(((@weight_sum - 1) * rand() + 1), 0)  select     @id = case when @weight_point < 0 @id else [table].id end,     @weight_point = @weight_point - [table].weight     @table [table] order     [table].weight desc 

this go through table, setting @id each record's id value while @ same time decrementing @weight point. eventually, @weight_point go negative. means sum of preceding weights greater randomly chosen target value. record want, point onwards set @id (ignoring ids in table).

this runs through table once, have run through entire table if chosen value first record. because average position half way through table (and less if ordered ascending weight) writing loop possibly faster... (especially if weightings in common groups):

declare @id int, @weight_sum int, @weight_point int, @next_weight int, @row_count int declare @table table (id int, weight int)  insert @table(id, weight) values(1, 50) insert @table(id, weight) values(2, 25) insert @table(id, weight) values(3, 25)  select @weight_sum = sum(weight) @table  select @weight_point = round(((@weight_sum - 1) * rand() + 1), 0)  select @next_weight = max(weight) @table select @row_count   = count(*)    @table set @weight_point = @weight_point - (@next_weight * @row_count)  while (@weight_point > 0) begin     select @next_weight = max(weight) @table weight < @next_weight     select @row_count   = count(*)    @table weight = @next_weight     set @weight_point = @weight_point - (@next_weight * @row_count) end  -- # once @weight_point less 0, know randomly chosen record -- # in group of records [table].weight = @next_weight  select @row_count = floor(((@row_count - 1) * rand() + 1), 0)  select     @id = case when @row_count < 0 @id else [table].id end,     @row_count = @row_count - 1     @table [table]     [table].weight = @next_weight order     [table].weight desc 

Comments

Popular posts from this blog

c++ - How do I get a multi line tooltip in MFC -

asp.net - In javascript how to find the height and width -

c# - DataTable to EnumerableRowCollection -