【问题标题】:Getting random record from database with group by使用 group by 从数据库中获取随机记录
【发布时间】:2011-01-27 23:13:41
【问题描述】:

您好,我有一个关于从数据库中选择随机条目的问题。我有 4 个表格、产品、出价和自动出价以及用户。

Products
-------  
id 20,21,22,23,24(prime_key)
price...........
etc...........

users  
-------
id(prim_key)  
name user1,user2,user3  
etc  

bids  
-------
product_id  
user_id  
created  

autobids  
--------
user_id   
product_id 

现在,多个用户可以对一个产品进行自动出价。因此,对于下一个投标人,我想从自动投标表中选择一个随机用户

语言查询示例:

对于自动出价表中的每个产品,我想要一个随机用户,这不是最后一个出价者。

在产品 20 上有用户 1、用户 2、用户 3 自动出价。
在产品 21 上有 user1,user2,user3 自动出价

然后我想要一个看起来像这样的结果集

20 – 用户 2
21 - 用户3

只是一个随机用户。我尝试混合 GOUP BY (product_id) 并将其设为 RAND(),但我无法从中获得正确的值。现在我得到一个随机用户,但所有的值都不匹配。

有人可以帮我构建这个查询吗,我正在使用 php 和 mysql

【问题讨论】:

    标签: php mysql random group-by


    【解决方案1】:

    解决方案的第一部分涉及识别每个产品的最新出价:这些最终会出现在临时表“latest_bid”中。

    然后,我们为每个产品的每个自动出价分配随机排名值 - 不包括每个产品的最新出价。然后我们为每个产品选择最高排名值,然后输出具有最高排名值的自动出价的 user_id 和 product_id。

    create temporary table lastbids (product_id int not null, 
                                     created datetime not null, 
                                     primary key( product_id, created ) );
    
    insert into lastbids 
    select product_id, max(created)
    from bids
    group by product_id;
    
    create temporary table latest_bid ( user_id int not null, 
                                        product_id int not null, 
                                        primary key( user_id, product_id) );
    
    insert into latest_bid
    select product_id, user_id 
    from bids b
    join lastbids lb on lb.product_id = b.product_id and lb.created = b.created;
    
    create temporary table rank ( user_id int not null, 
                                  product_id int not null, 
                                  rank float not null, 
                                  primary key( product_id, rank ));
    
    # "ignore" duplicates - it should not matter
    # left join on latest_bid to exclude latest_bid for each product
    
    insert ignore into rank 
    select user_id, product_id, rand() 
    from autobids a
    left join latest_bid lb on a.user_id = lb.user_id and a.product_id = lb.product_id 
    where lb.user_id is null;
    
    create temporary table choice 
    as select product_id,max(rank) choice 
       from rank group by product_id;
    
    select user_id, res.product_id from rank res
    join choice on res.product_id = choice.product_id and res.rank = choice.choice;
    

    【讨论】:

    • 哇,这看起来是一个非常好的解决问题的方法。这肯定会得到我正在寻找的结果。我对性能有疑问。这个查询必须在我的系统中每秒运行一次,因为每秒可能会有一个新的自动竞价被触发。将所有自动出价都输入 php 会不会更快,然后只需使用循环过滤掉不需要的东西。创建一个临时表对我来说似乎有点慢,我认为 rand() 和 max() 函数也是如此。我可能弄错了。我不得不说我正在使用 inooDB 表。
    • 可以通过跟踪“latest_bid”表中每个产品的最新出价的 user_id 和 product_id 来改进数据库方法。维护该表的一个好方法是在 bids 表上添加一个触发器,以便每次添加新的出价时,都会更新 latest_bid 表。您还可以以类似的方式缓存出价状态 - 因此,仅当该产品的新出价到达时,才会重新计算产品的当前出价者。
    【解决方案2】:

    您可以将 LIMIT 语句与服务器端 PREPARE 结合使用。

    这是一个从表 mysql.help_category 中选择随机行的示例:

    select @choice:= (rand() * count(*)) from mysql.help_category;
    prepare rand_msg from 'select * from mysql.help_category limit ?,1';
    execute rand_msg using @choice;
    deallocate prepare rand_msg;
    

    这需要改进以防止@choice 变为零,但总体思路可行。

    或者,您的应用程序可以通过运行第一个选择来构建计数本身,并使用硬编码的限制值构建第二个选择:

    select count(*) from mysql.help_category;
    # application then calculates limit value and constructs the select statement:   
    select * from mysql.help_category limit 5,1;
    

    【讨论】:

    • 哇,我完全不明白这个答案,我还是个初学者。什么是表 mysql.help_category?这是循环使用的吗?
    • mysql.help_category 是我用作示例的大多数安装都会有的表。用你的桌子代替它。我会澄清答案。这是否在循环中使用取决于您的应用程序想要做什么。
    • “取决于我的应用程序想要做什么”?我的应用程序想要执行问题中所要求的操作,即从 autobids 表中为每组获取一个随机项目。有没有一种将整个结果集作为结果集的方法,我不想循环通过数据库。并且像 rand() 和 count() 这样的函数对数据库来说不是一个坏主意。我认为从 mysql 获取整个集合并使用 php 循环它与此选项的性能相同。
    • 对不起 - 我误解了。您确实需要为每种产品重复该过程。我添加了一个新答案,可以一次性为自动出价表中的所有产品提供解决方案。
    猜你喜欢
    • 2018-07-20
    • 1970-01-01
    • 2012-04-09
    • 2012-04-13
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    • 2011-04-07
    • 2014-08-08
    相关资源
    最近更新 更多