2013-04-18 44 views
0

我有一个表keywords,列keywordweight。我的目标是随机选择一个keyword,但将其视为weight(概率)。我发现了两种方法来解决这个问题,后者更优雅(并且消耗更少的资源) - 但我没有让它运行。看看你自己。mysql加权随机结果 - 如何在SELECT后获得更改的变量值

表和记录:

CREATE TABLE IF NOT EXISTS `keywords` (
    `keyword` varchar(100) COLLATE utf8_bin NOT NULL, 
    `weight` int(11) NOT NULL, 
    UNIQUE KEY `keywords` (`keyword`), 
    KEY `rate` (`weight`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 

INSERT INTO `keywords` (`keyword`, `weight`) VALUES 
('google', 50), 
('microsoft', 20), 
('apple', 10), 
('yahoo', 5), 
('bing', 5), 
('xing', 5), 
('cool', 5); 

查询1

占用更多的ressources,我在5K +的记录工作。资料来源是Why would this MySQL query using rand() return no results about a third of the time?

SELECT * FROM `keywords` ORDER BY -LOG(1.0 - RAND())/weight LIMIT 1 

查询2

总结了权重@weight_sum。在该范围内设置@weight_pointRAND()数字。循环遍历所有记录,从@weight_pos减去weight,并将@keyword设置为当前的keywords.keyword。直到@weight_pos < 0。然后它保持keyword。来源是Random Weighted Choice in T-SQL

SET @keyword = 0; 
SET @weight_sum = (SELECT SUM(weight) FROM keywords); 
SET @rand = RAND(); 
SET @weight_point = ROUND(((@weight_sum - 1) * @rand + 1), 0); 
SET @weight_pos = @weight_point; 

SELECT 
    keyword, 
    weight, 

    @keyword:=CASE 
     WHEN @weight_pos < 0 THEN @keyword 
     ELSE keyword 
    END AS test, 

    (@weight_pos:=(@weight_pos - weight)) AS curr_weight, 
    @weight_point, 
    @keyword, 
    @weight_pos, 
    @rand, 
    @weight_sum 
FROM 
    keywords; 

见的phpmyadmin此结果http://postimg.org/image/stgpd776f/

phpmyadmin

我的问题

我如何获得在@keyword什么test列包含在最终的价值,或?事后添加SELECT @keyword不会改变任何内容。

回答

0

好的,我想我的问题或多或少是一个基本的mysql问题。通过将上面的SELECT语句封装到另一个SELECT中,我达到了我想要的效果,然后过滤了我搜索的第一个结果。对不起,打扰你。查看查询:

SET @keyword = 0; 
SET @weight_sum = (SELECT SUM(weight) FROM keywords); 
SET @rand = RAND(); 
SET @weight_point = ROUND(((@weight_sum - 1) * @rand + 1), 0); 
SET @weight_pos = @weight_point; 
SELECT t.test FROM (
SELECT 
    keyword, 
    weight, 
    @keyword:=CASE 
     WHEN @weight_pos < 0 THEN @keyword 
     ELSE keyword 
    END AS test, 
    (@weight_pos:=(@weight_pos - weight)) AS curr_weight, 
    @weight_point, 
    #@keyword, 
    @weight_pos, 
    @rand, 
    @weight_sum 
FROM 
    keywords 

) AS t 

WHERE 
    t.curr_weight < 0 
LIMIT 
    1;