每组获取多个GROUP BY结果,或使用单独的连接表

时间:2010-03-02 14:05:19

标签: php mysql optimization group-by denormalization

我正在拍卖网络应用程序。现在我有一个出价表,从这张表中我想选择每次拍卖的最后10个出价。

现在我知道我可以使用以下内容获得最后一次出价:

SELECT bids.id FROM bids WHERE * GROUP BY bids.id ORDER BY bids.created

现在我已经知道为GROUP BY结果设置一个数量并不是一件容易的事情,实际上我找不到简单的解决方案,如果有我希望听到的话。

但是我已经提出了解决这个问题的一些解决方案,但我不确定我是否做得很好。

替代

首先要创建一个新表,称之为bid_history。在此表中,我存储了最后一项的字符串。

示例:

bids_history
================================================================
auction_id   bid_id     bidders               times
    1        20,25,40   user1,user2,user1     time1,time2,time3

我必须存储名称和时间,因为我发现没有简单的方法来获取bid_id(20,25,40)中使用的字符串,只是在连接中使用它。 这样我就可以加入拍卖ID,我有最新的结果。

现在,当有新的出价时,这些是以下步骤:

  • 将出价插入出价获取lastinserteid
  • 获取bid_history字符串 拍卖产品
    • 爆炸字符串
    • 插入新值
    • 检查是否有超过3个
    • 内爆数组,然后重新插入字符串

在我看来这不是一个很好的解决方案。 我真的不知道要走哪条路。请记住,这是一个有很多竞价的网站,他们可以为每个拍卖项目提供高达15.000的出价。也许是因为这个数量是GROUPING和ORDERING不是一个好方法。如果我错了,请纠正我。

拍卖结束后,我会清理出价表,删除所有出价,并将其存储在单独的表格中。

有人可以帮我解决这个问题!

如果你去过,谢谢你的阅读..

修改

我使用的表是:

bids
======================
id      (prim_key)
aid     (auction id)
uid     (user id)
cbid    (current bid)
created (time created)
======================

auction_products
====================
id        (prim_key)
pid       (product id)
closetime (time the auction closses)

查询结果我想要的是什么:

result
===============================================
auction_products.id   bids.uid   bids.created
2                        6         time1
2                        8         time2
2                        10        time3
5                        3         time1
5                        4         time2
5                        9         time3
7                        3         time1
7                        2         time2
7                        1         time3

这是每次拍卖的最新出价,可按数字3或10进行选择

5 个答案:

答案 0 :(得分:1)

使用用户变量控制流程,我最终得到了(如果您想要的话,只需将<=3替换为<=10拍卖):

SELECT a.*
FROM
 (SELECT aid, uid, created FROM bids ORDER BY aid, created DESC) a,
 (SELECT @prev:=-1, @count:=1) b
WHERE
 CASE WHEN @prev<>a.aid THEN
   CASE WHEN @prev:=a.aid THEN
    @count:=1
   END
 ELSE
   @count:=@count+1
 END <= 3

答案 1 :(得分:0)

要为特定竞价选择上一次10出价,只需创建一个规范化的bids表格(每次出价1条记录)并发出此查询:

SELECT  bids.id
FROM    bids
WHERE   auction = ?
ORDER BY
        bids.created DESC
LIMIT 10

要为每次多次拍卖选择最后10个出价,请使用此选项:

SELECT  bo.*
FROM    (
        SELECT  a.id,
                COALESCE(
                (
                SELECT  bi.created
                FROM    bids bi
                WHERE   bi.auction = a.id
                ORDER BY
                        bi.auction DESC, bi.created DESC, bi.id DESC
                LIMIT 1 OFFSET 9
                ), '01.01.1900'
                ) AS mcreated
                COALESCE(
                (
                SELECT  bi.id
                FROM    bids bi
                WHERE   bi.auction = a.id
                ORDER BY
                        bi.auction DESC, bi.created DESC, bi.id DESC
                LIMIT 1 OFFSET 9
                ), 0)
                AS mid
        FROM    auctions a
        ) q
JOIN    bids bo
ON      bo.auction >= q.auction
        AND bo.auction <= q.auction
        AND (bo.created, bo.id) >= (q.mcreated, q.mid)

bids (auction, created, id)上创建一个复合索引,以便快速工作。

答案 2 :(得分:0)

编辑:这是错的:-)

您需要使用子查询:

SELECT bids1.id
FROM ( SELECT *
       FROM bids AS bids1 LEFT JOIN
            bids AS bids2 ON bids1.created < bids2.created
                          AND bids1.AuctionId = bids2.AuctionId
       WHERE bid2.id IS NULL)
ORDER BY bids.created DESC
LIMIT 10

因此子查询执行从出价到自身的左连接,将每个记录与具有相同auctionId的所有记录配对,并且创建日期在其自己创建的日期之后。对于最近的记录,将没有其他记录具有更大的创建日期,因此该记录不会包含在联接中,但由于我们使用左联接,它将被包括在内,所有bid2字段都为null因此WHERE bid2.id IS NULL声明。

因此,子查询每次竞价有一行,从最近的出价中提取数据。然后只需使用orderby和limit来选择前十名。

如果您的数据库引擎不支持子查询,您也可以使用视图。

答案 3 :(得分:0)

为什么在一个查询中执行此操作?

$sql = "SELECT id FROM auctions ORDER BY created DESC LIMIT 10";
$auctions = array();

while($row = mysql_fetch_assoc(mysql_query($sql)))
  $auctions[] = $row['id'];

$auctions = implode(', ', $auctions);
$sql = "SELECT id FROM bids WHERE auction_id IN ($auctions) ORDER BY created LIMIT 10";
// ...

你应该明显地处理例如$auctions是空的,但我认为这应该有效。

答案 4 :(得分:0)

好的,这个应该有效:

SELECT bids1.id
FROM bids AS bids1 LEFT JOIN
     bids AS bids2 ON bids1.created < bids2.created
                   AND bids1.AuctionId = bids2.AuctionId
GROUP BY bids1.auctionId, bids1.created
HAVING COUNT(bids2.created) < 9

因此,像以前一样,左边加入自己的出价,这样我们就可以将每个出价与其他出价进行比较。然后,首先通过拍卖将其分组(我们希望每次拍卖的最后十个出价),然后创建。由于左联接将每个出价与之前的所有出价配对,我们可以计算每组出价的数量2.这将为我们提供在该出价之前发生的出价数量。如果这个数是&lt; 9(因为第一个将有计数== 0,它是零索引)它是十个最近的出价之一,我们想要选择它。