Write the Code. Change the World.

6月 15

场景

有一个礼物记录表,表名'send_gift_log',送一次礼物,增加一条记录。表里边有下边这些字段:
1. senderid (赠送人uid)
2. sendernickname (赠送人昵称)
3. giftid (礼物id)
4. giftname (礼物昵称)
5. giftcount (礼物个数)
6. accepterid (收礼人uid)
7. accepternickname (收礼人昵称)
8. logdate (赠送时间)
9. roomid (房间id)
10. ……

索引:senderidaccepteridroomidgiftid

赠送人的昵称随时会改变。如果赠送人昵称改变了,他再赠送礼物,表里就会记录他当前的昵称。同样,收礼人的昵称也会改变。

需求

  • 要求,昵称用最新的。

  • 在相同礼物数的情况下,以先达到优先排行。比如:

A,B,C三个送礼人,他们送出的礼物个数都是 1000个(可能分多次赠送),如果A最后一次赠送礼物的时间比B早,而B最后一次赠送礼物的时间比C早,那么ABC三人的排行顺序就是 ABC

  • 统计一段时间内,某个礼物或几个礼物,某些房间里的排行。

按以上要求,统计送礼人排行和收礼人排行。

分析

首先,不通过用户表去获取昵称,用户表非常庞大。

统计的是两类排行,可以做两次处理。以做送礼人排行为例。先SELECT sendernickname, SUM(giftcount) as gc,再FROM, WHERE,再GROUP BY senderid,然后再ORDER BY gc

这时,一个排行已经出来了。可是,送礼人的最最新昵称没有得到。现在的想法是再嵌套一个SELECT,将最新的昵称给取出来。完整的sql语句如下。

SELECT SUM(a.giftcount) as gc , 

(SELECT b.sendernickname FROM send_gift_log b WHERE 

a.senderid = b.senderid ORDER BY b.logdate DESC limit 1) as nickname 

FROM send_gift_log a 

WHERE a.logdate > '2017-06-15 12:30:00' AND

a.logdate < '2017-06-15 23:59:59' AND a.roomid in('3344', '991',

'9696') AND  a.giftid = 2017 

GROUP BY a.senderid ORDER BY gc

当有几个人赠送礼物的个数相同时,这样写,排行也会出问题。并不能保证每次取的的数据顺序都是固定的,还有先赠送的排前边的逻辑。所以,还得进一步处理。既然上边取了赠送人最新昵称,那顺便把logdate取出来不就可以了(他们属于同一行)。因为嵌套的SELECT作为取出的一个字段,所以用CONCAT将昵称和时间组在一起。在排序的时候,再用explode拆出来就可以。完整sql语句如下。

SELECT SUM(a.giftcount) as gc , 

(SELECT CONCAT(b.sendernickname, '#--#', b.logdate) FROM

send_gift_log b WHERE a.senderid = b.senderid ORDER BY b.logdate

DESC limit 1) as nickname 

FROM send_gift_log a 

WHERE a.logdate > '2017-06-15 12:30:00' AND

a.logdate < '2017-06-15 23:59:59' AND a.roomid in('3344', '991',

'9696') AND  a.giftid = 2017

GROUP BY a.senderid ORDER BY gc

功能虽然实现了,可是效率不好。在鱼和熊掌不能兼得间,怎么办呢。考虑是不是还有其他方法呢。

mysql里有个MAX函数,既然时间是个数据标量,用MAX不刚好吗。可是昵称呢,昵称还是没有办法。那就把最新昵称的需求丢掉吧。完整sql语句如下。

SELECT SUM(a.giftcount) as gc , MAX(a.logdate) as date

FROM send_gift_log a 

WHERE a.logdate > '2017-06-15 12:30:00' AND a.logdate < '2017-06-15 

23:59:59' AND a.roomid in('3344', '991', '9696') AND a.giftid = 2017 

GROUP BY a.senderid ORDER BY gc

最后,将查询出来的数据进行排序

排序

$sort1 = array();
$sort2 = array();
$info  = array();
while ($row = $result->fetch_assoc())
{
    $sort1[] = $row['gc'];
    $sort2[] = $row['date'];
    $info[]  = $row;
}

if(count($info) > 0)
{
    array_multisort($sort1, SORT_DESC, $sort2, SORT_ASC, $info);
}
unset($sort1, $sort2);

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注