有趣的题目:两张表合并取出前十名

11 篇文章 0 订阅

昨晚在某个群上看到一个人抛出一个问题:
在这里插入图片描述
我想出两种解法,一种是sql加代码。一种是一句sql搞定。

方法一

首先模拟两张表:

CREATE TABLE `read_log_a`
 ( `id` int(11) NOT NULL AUTO_INCREMENT,
  `article` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '文章',
   `read_num` int(11) DEFAULT '0' COMMENT '阅读数',
    PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
 
 CREATE TABLE `read_log_b`
 ( `id` int(11) NOT NULL AUTO_INCREMENT,
  `article` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '文章',
   `read_num` int(11) DEFAULT '0' COMMENT '阅读数',
    PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

执行脚本生成测试数据(需要分别执行两次)两张表分别生成100条数据,阅读数在0到10000之间,便于对比。

  /**
     * 生成测试数据
     */
    public function buildData()
    {
        $book_name = ['星华字典','收敛之道','羽毛球从菜鸟到省队','酒席文化剖析','面试指南','大话NBA'];
        for ($i=0;$i<100;$i++) {
            //从一维数组获取随机值。array_rand()返回的是数组随机下标
            $name = $book_name[array_rand($book_name)];
            $rand_num = rand(0,10000);
            $data = [
                'read_num' => $rand_num,
//                'article' => $name . '_a_' . $i
                'article' => $name . '_b_' . $i
            ];
//            $res = Db::name("read_log_a")->insert($data);
            $res = Db::name("read_log_b")->insert($data);

        }
        dump("插入结束");
    }

获取前n名的排行榜方法:

/**
 * 获取前n名的排行榜
 * @param $rank_limit 指定第n名
 */
public function getReadRank()
{
    //获取排行榜的显示长度。默认取10个
    $rank_limit = input("rank_limit",10);
    //查找两张表阅读数最大的n条记录
    $a_sql = "SELECT * FROM `read_log_a` ORDER BY read_num DESC limit {$rank_limit}";
    $b_sql = "SELECT * FROM `read_log_b` ORDER BY read_num DESC limit {$rank_limit}";
    $a_top_rank = Db::query($a_sql);
    $b_top_rank = Db::query($b_sql);

    $len = count($a_top_rank) + count($b_top_rank);
    //分别取a队列和队列b的尾部不断对比,把小的丢弃。
    //循环终止的条件是两个队列的数量和为指定前n个排行版.代表已经取到二者的前n个
    while ($len > $rank_limit) {
        $a_last_num = end($a_top_rank);
        $b_last_num = end($b_top_rank);
        if ($a_last_num['read_num'] >= $b_last_num['read_num']) {
            array_pop($b_top_rank);
        } else {
            array_pop($a_top_rank);
        }
        $len = count($a_top_rank) + count($b_top_rank);
    }
    $result = array_merge($a_top_rank,$b_top_rank);
    //二维数组以字段read_num排序
    array_multisort(array_column($result,'read_num'),SORT_DESC,$result);
    dump($result);
}

执行代码得到的结果如下:

在这里插入图片描述
分别查看各自表阅读数前10的数据:
在这里插入图片描述

方法二

后面想了一下,直接用一句sql也能得出结果:

SELECT * FROM 
(
SELECT * FROM read_log_a 
UNION ALL 
SELECT * FROM read_log_b
) 
AS combine_table
ORDER BY read_num DESC LIMIT 10

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值