dongtiao2066 2013-10-28 12:12 采纳率: 0%
浏览 60

分组和排序问题

I have a notifications system (PHP, MySQL- based) and I am trying to do the following: Query notifications results grouped by posts without any limit but then ordered by time_sent limited to 5 (per iteration). Then I used an ajax to show the next iteration set of 5 notifications.

Basically I need 5 notifications at a time (per set) but for each of them, if a group concerns one post: there can be as many notifications as wanted:

This is how there will be displayed:

  1. Notification concerning post F – sent 1 day ago
  2. First notification concerning post C – sent 2 days ago
    • Second notification concerning post C – sent 3 days ago
    • Third notification concerning post C – sent 4 days ago
    • Fourth notification concerning post C – sent 5 days ago
  3. Notification concerning post Y – sent 3 days ago
  4. First notification concerning post D – sent 4 days ago
    • Second notification concerning post D – sent 5 days ago
    • Third notification concerning post D – sent 6 days ago
  5. Notification concerning post Y – sent 5 days ago

If a new notification were sent concerning post Y, this would be upped to the top of the list naturally.

This is how I had started, before I decided to implement this group system:

$notifications_req = mysql_query('SELECT * FROM notifications WHERE user_id = "'.$user_id.'" ORDER BY time_sent DESC LIMIT 5');

And now I got lost, and struggle with this group by and order by logic.

The database contains of course a post_id column.

EDIT:

I ended up changing quite drastically the way I wanted to sor the notifications. This is how I eventually did it. It might not be the most efficient, but it works the way I want:

<?php  $notifications_all_req = mysql_query('SELECT * FROM notifications WHERE user_id = "'.$user_id.'" ORDER BY time_sent DESC');  if(mysql_num_rows($notifications_all_req) > 0){
while($row =  mysql_fetch_assoc($notifications_all_req))
{
    $post_req_ids[] = $row['post_id'];
}
$unique_post_ids = array_unique($post_req_ids);
foreach ($unique_post_ids as $i => $unique_post_id)
{
    ?>      
    <ul id="notifications_ul_<?php echo $i; ?>">
    <?php
    $notifications_req = mysql_query('SELECT * FROM notifications WHERE (user_id = "'.$user_id.'" AND post_id = "'.$unique_post_id.'") ORDER BY time_sent DESC ');
        while($notification =  mysql_fetch_assoc($notifications_req))
        {

        }
        ?>
    </ul>
    <?php
}  }  ?>

This way, I can control the limits of both the notifications group (using $i) and the ones within each group, also with an Ajax load more code for the latter.

  • 写回答

1条回答 默认 最新

  • dow72046 2013-10-28 13:14
    关注

    You don't want to use GROUP BY here, because that's for summary queries.

    Pro tip: Don't use SELECT *. Instead, select the columns you want by name.

    Pro tip: People are advising you to use PDO or mysqli_ for a really good reason. The mysql_ interface is notoriously insecure. If you put a web app based on mysql_ on the public network, some badguy will pwn you. If you don't mind being pwned, for example if your're building a prototype or proof-of-concept web site, don't worry about it.

    Let's get the result set ordering right before we start to segment it into five-post chunks. You need two items in your ORDER BY clause. It seems you want your result set ordered like this.

    SELECT * 
      FROM notifications 
     WHERE user_id = ? 
     ORDER BY post_id, time_sent DESC
    

    Give that a try, without the LIMIT 5, and debug your php code so you get a good display, even if it's too long for your purposes.

    Next, if I understand you correctly, you're trying to show five posts at a time. This gets trickier, because you want five posts, and each of them can have a variable number of notifications.

    So we have to come up with a way to get five posts at a time. This subquery will do that, giving a list of five post_id values.

     SELECT DISTINCT post_id
       FROM notifications
      WHERE user_id = ?
      ORDER BY post_id
      LIMIT 5 OFFSET ?   
    

    The parameter to OFFSET ? should be 0, 5, 10 and so forth to get the first, second, third, etc, bunch of five posts. If you only want the first five posts just leave out the OFFSET clause.

    Now we have to embed that subquery that gets just five posts in another query to get all the data. That works like this.

    SELECT * 
      FROM notifications 
     WHERE post_id IN (
                          SELECT DISTINCT post_id
                            FROM notifications
                           WHERE user_id = ?
                           ORDER BY post_id
                           LIMIT 5 OFFSET ?   
                      ) 
     ORDER BY post_id, time_sent DESC
    

    This last, more complex, SQL query will give a resultset that looks like the one from the first statement. You should be able to plug it in to your debugged php code and get the display you're looking for.

    评论

报告相同问题?

悬赏问题

  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来
  • ¥15 求帮我调试一下freefem代码
  • ¥15 matlab代码解决,怎么运行
  • ¥15 R语言Rstudio突然无法启动
  • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法