MYSQL 动态SQL语句
最近在公司遇到一个业务需求,该需求大概是这样子的,查询表中最热门的数据。排序规则是根据转发量,推荐量,点赞量排序,并拿去第一条数据。如果表中的所有数据的转发量都为0的情况下则用推荐量排序,也就是说三个中选一个排序并获取第一条数据。排序的优先级分别为 转发量>推荐量>点赞量。
首先为了模拟需求,我们将来建立一张话题表
-- ----------------------------
-- Table structure for `topic`
-- ----------------------------
DROP TABLE IF EXISTS `topic`;
CREATE TABLE `topic` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(63) DEFAULT NULL COMMENT '标题名称',
`share_count` int(11) DEFAULT '0' COMMENT '转发量',
`recommend_count` int(11) DEFAULT '0' COMMENT '推荐量',
`like_count` int(11) DEFAULT '0' COMMENT '点赞量',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of topic
-- ----------------------------
INSERT INTO `topic` VALUES ('1', '明天吃什么', '0', '0', '999');
INSERT INTO `topic` VALUES ('2', '后天吃什么', '0', '0', '500');
INSERT INTO `topic` VALUES ('3', '今天吃什么', '0', '0', '200');
可以看到上面这张话题表除了有话题标题,转发量,推荐量和点赞量之外还有作者对吃什么这件事情上很执着。
有了表之后我们就可以快乐的写sql语句了。
思路
经过一顿分析,不难发现该SQL主要的难点在排序(如果觉得获取一条数据是难点的话,就关了这篇文章,当没来过 ),排序要求的优先级是转发量>推荐量>点赞量。也就是说当表里的数据都没有转发量的时候则改为推荐量排序,以此类推…那么这很简单,首先我们要知道表里的数据是否没有转发量,我们可以通过MAX()
聚合函数来判断,如果该表中最大的转发量不等于0则代表有转发量可排序,如果最大的转发量等于0的话那就用推荐量排序,以此类推…
那么判断条件已经有了,那么怎么去实现切换排序呢?使用CASE
语句来实现。
最后使用LIMIT
来限制获取条数就好
画外音:我相信到这边我就已经跑偏了,因为我想介绍case语句的用法…
CASE
语句很像JAVA的switch
语句…
CASE WHEN [条件表达式]
THEN
返回的值
WHEN [条件表达式]
THEN
返回的值
ELSE
返回的值
END;
好了,为了今晚我能睡觉,我们还是回到正题吧,CASE语句自己去找博客看,如果看不懂的话就关了这篇文章,当没来过 。
实现方式
SELECT *
FROM topic #一个简单的查询语句
ORDER BY #排序
CASE WHEN (SELECT MAX(share_count) FROM topic) != 0 #如果话题表的最大转发量不等于0则用转发量排序
THEN
share_count
WHEN (SELECT MAX(recommend_count) FROM topic) != 0 #否则如果话题表的最大推荐量不等于0则用推荐量排序
THEN
recommend_count
ELSE #实在不行就点赞量吧。一篇文章要是连点赞量都没有,那就...跟我差不多了。
like_count
END
DESC #降序
LIMIT 1; #限制获取条数
结果
好的,到这里就结束了??? 不好意思并没有。
在我了解到这个需求的时候,我当时的一个思路并不是想着这么写(可能是真的笨,没想到… ) 当时的想法是我能不能够在SQL层面上做到动态拼接SQL???,如果可以的话,那岂不很强。所以我就去网上找了资料,发现还真可以!!!
以上都是废话,这篇文章的正题才正式开始!!!
MYSQL SQL级别动态拼接SQL语句
还是刚刚那需求,但相信我,这次的操作和上面不同,绝对区别于市面上的妖艳贱货。
思路:
SET @lsql = 'SELECT * FROM topic ORDER BY ? DESC LIMIT 1'; #定义一个变量存储要执行的sql语句
SET @sort_field = #定义一个变量 存储要排序的字段。
CASE WHEN (SELECT MAX(share_count) FROM topic) != 0
THEN
CONCAT('share_count')
WHEN (SELECT MAX(recommend_count) FROM topic) != 0 #否则如果话题表的最大推荐量不等于0则用推荐量排序
THEN
CONCAT('recommend_count')
ELSE #实在不行就点赞量吧。一篇文章要是连点赞量都没有,那就...跟我差不多了。
CONCAT('like_count')
END;
PREPARE stms FROM @lsql; #预编译这条字符串sql。
EXECUTE stms USING @sort_field; #执行这条SQL
结果
这种相对于上一种来说更加灵活,他可以动态的拼接语句,不仅可以作用在排序,也可以动态的拼接WHERE
条件等等…更加灵活多变。但这种一般都是封装在存储过程中使用的,而我也是写了一个demo,一个思路。