业务场景下 MySQL 原生语句编写

1. SELECT 取数行号;

使用到的表

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `products`
-- ----------------------------
DROP TABLE IF EXISTS `products`;
CREATE TABLE `products` (
  `p_id` int(11) NOT NULL AUTO_INCREMENT,
  `p_name` varchar(30) DEFAULT NULL,
  `p_type` varchar(20) DEFAULT NULL,
  `p_view` int(11) DEFAULT NULL comment '点击量',
  PRIMARY KEY (`p_id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of products
-- ----------------------------
INSERT INTO `products` VALUES ('1', '西瓜', '水果类', '21');
INSERT INTO `products` VALUES ('2', '瓜子', '干果类', '32');
INSERT INTO `products` VALUES ('22', '苹果', '水果类', '32');
INSERT INTO `products` VALUES ('28', '桔子', '水果类', '33');
INSERT INTO `products` VALUES ('32', '香蕉', '水果类', '21');
INSERT INTO `products` VALUES ('35', '花生', '干果类', '3');
INSERT INTO `products` VALUES ('37', '猪肉', '生鲜类', '5');
INSERT INTO `products` VALUES ('48', '牛肉', '生鲜类', '23');
INSERT INTO `products` VALUES ('60', '开心果', '干果类', '56');
INSERT INTO `products` VALUES ('61', '鸡翅', '生鲜类', '23');
INSERT INTO `products` VALUES ('77', '樱桃', '水果类', '41');
INSERT INTO `products` VALUES ('87', '杜蕾斯', '其他类', '123');
INSERT INTO `products` VALUES ('102', '开瓶器', '其他类', '88');
INSERT INTO `products` VALUES ('114', '五花肉', '生鲜类', '4');

实操

# 需求:取出数据并显示行号(假设按 p_view 倒排序)
# 首先是排序的 sql
select p_name,p_type,p_view from products ORDER BY p_view desc
# MySQL 并没有 oracle、sqlserver 那样直接的方法
# 会话变量,基本设置方法:
set @name='hua';
select @name;
# 只要会话不结束,这个变量就一直存在

# 对变量进行赋值
# “:=” 这才是 MySQL 对变量真正赋值的方式,“=” 只是比较
set @age:=10;
select @age:=10 as name;
# 只不过使用 set 语句时 可以写成“=”
# select 赋值必须是“:=”,如果不加“as name”,会给变量赋值+打印

# 结合 sql 语句
select p_name,p_type,p_view,@rownum:=@rownum+1 from products ORDER BY p_view desc 
# 此时的问题是,如果变量一上来没有定义,就一直是 null

# MySQL 的 ifnull 函数
# IFNULL(expr1, expr2) 
# expr1 不为 NULL,则 IFNULL() 的返回值为 expr1; 否则其返回值为 expr2
select p_name,p_type,p_view, IFNULL(@rownum:=@rownum+1,@rownum:=1) from products a
ORDER BY p_view desc

# 问题又来了,第二次运行 @rownum 不是从 1 开始的
# 最终解决方案,用 select 对 @rownum 进行初始化
select p_name,p_type,p_view,@rownum:=@rownum+1 as row_num
from products a,(select @rownum:=0) b ORDER BY p_view desc

在这里插入图片描述

2. 分组后在分组内排序、每个分组取前 N 条;

实操

# 实操前:关闭 only_full_group_by
SELECT @@sql_mode;
# 如果有 ONLY_FULL_GROUP_BY 则
SET sql_mode
='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

# 需求:分组后按照 p_view 进行倒排序
# 首先是分组的 SQL
# 中文字段的排序是安装 ascii 码排序的
select a.p_type,a.p_name,a.p_view from products a GROUP BY p_type,p_name

# 为了满足 p_view 的倒排序,分组 p_type 无效了
select a.p_type,a.p_name,a.p_view from products a GROUP BY p_type,p_name 
order by p_view desc

# 按照 p_type,p_view 排序
# 这里不考虑优化,优化可以在 SQL 前加 explain
# type 为 ALL,需要加索引
select a.p_type,a.p_name,a.p_view from products a 
order by a.p_type desc, a.p_view desc

# 每个分类取出前 n 条,有些网站的首页就有这样的需求
# 思路就是再加一列行号,p_type 相同行号就一直排下去
# p_type 和上一个不同就重新开一个行号
# 取出行号 <= n 就行
# @pre 保存上一条的 p_type 值
select p_type,p_name,p_view from 
(select p_type,p_name,p_view from products
order by p_type desc, p_view desc) a,
(select @rownum:=0,@pre:=0) b

# MySQL 中 “=” 是用来进行判断的
# 第一次执行,@pre 没有值,@rownum 就 = 1
# 第二次运行 @pre:=p_type,@rownum 就 @rownum+1
# @pre:=p_type 没用,就只是一个表达式
select p_type,p_name,p_view, IF(@pre=p_type,@rownum:=@rownum+1,@rownum:=1) as row_num,
@pre:=p_type from 
(select p_type,p_name,p_view from products
order by p_type desc, p_view desc) a,
(select @rownum:=0,@pre:='') b

# 取前 n 条
select p_type,p_name,p_view,row_num from(
select p_type,p_name,p_view, IF(@pre=p_type,@rownum:=@rownum+1,@rownum:=1) as row_num,
@pre:=p_type from 
(select p_type,p_name,p_view from products
order by p_type desc, p_view desc) a,
(select @rownum:=0,@pre:='') b
) c
where c.row_num <=2

在这里插入图片描述

3. 纯 SQL 实现小算法、计算商品重要度;

追加表 - 商品销售汇总表

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `products_sales`
-- ----------------------------
DROP TABLE IF EXISTS `products_sales`;
CREATE TABLE `products_sales` (
  `p_id` int(11) NOT NULL AUTO_INCREMENT,
  `p_name` varchar(30) DEFAULT NULL,
  `p_sales` int(11) DEFAULT NULL comment '销量',
  PRIMARY KEY (`p_id`)
) ENGINE=InnoDB AUTO_INCREMENT=115 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of products_sales
-- ----------------------------
INSERT INTO `products_sales` VALUES ('1', '西瓜', '101');
INSERT INTO `products_sales` VALUES ('2', '瓜子', '200');
INSERT INTO `products_sales` VALUES ('22', '苹果', '90');
INSERT INTO `products_sales` VALUES ('28', '桔子', '80');
INSERT INTO `products_sales` VALUES ('35', '花生', '55');
INSERT INTO `products_sales` VALUES ('87', '杜蕾斯', '500');
INSERT INTO `products_sales` VALUES ('102', '开瓶器', '231');
INSERT INTO `products_sales` VALUES ('114', '五花肉', '77');

实操:根据商品的点击量和销量,对商品进行一个评分

  • 需求 1:根据分类显示出商品的名称、点击量和销售量情况。没有销售量的置为 0
select a.p_type,a.p_name,a.p_view from products a
order by a.p_type,a.p_view desc

select a.p_type,a.p_name,a.p_view,IFNULL(b.p_sales,0) from products a
left join products_sales b on a.p_id=b.p_id
order by a.p_type,a.p_view desc

在这里插入图片描述

  • 每一个分类的平均销量
# 0 销量不计算在内
select p_type,round(sum(sales)/count(*),0) as sales_avg from
(select a.p_type,a.p_name,a.p_view,IFNULL(b.p_sales,0) as sales from products a
left join products_sales b on a.p_id=b.p_id
order by a.p_type,a.p_view desc) a
where a.sales>0
GROUP BY p_type
  • 对商品表做平均值计算
# 每一个分类的点击量平均值
select p_type,round(sum(p_view)/count(*),0) as view_avg
from products group by p_type
  • 合并
# 之前写的商品点击量和销售量 a
select a.p_type,a.p_name,a.p_view,IFNULL(b.p_sales,0) as sales from products a  
left join products_sales b on a.p_id=b.p_id
group by a.p_type,a.p_name order by a.p_type desc,a.p_view desc

# 每一个分类的点击量平均值 b
select p_type,round(sum(p_view)/count(*),0) as view_avg
from products group by p_type

# 销量平均值 c
select p_type,round(sum(sales)/count(*),0) as sales_avg from
(select a.p_type,a.p_name,a.p_view,IFNULL(b.p_sales,0) as sales from products a
left join products_sales b on a.p_id=b.p_id
order by a.p_type,a.p_view desc) a
where a.sales>0
GROUP BY p_type

# 合并
select a.p_type,p_name,p_view,view_avg,sales,sales_avg from 
(
	select a.p_type,a.p_name,a.p_view,IFNULL(b.p_sales,0) as sales from products a  
	left join products_sales b on a.p_id=b.p_id
	group by a.p_type,a.p_name order by a.p_type desc,a.p_view desc
) a,
(
	select p_type,round(sum(p_view)/count(*),0) as view_avg
	from products group by p_type
) b,
(
	select p_type,round(sum(sales)/count(*),0) as sales_avg from
	(select a.p_type,a.p_name,a.p_view,IFNULL(b.p_sales,0) as sales from products a
	left join products_sales b on a.p_id=b.p_id
	order by a.p_type,a.p_view desc) a
	where a.sales>0
	GROUP BY p_type
) c
where a.p_type = b.p_type and a.p_type=c.p_type

在这里插入图片描述

  • 评分机制:可以加入权重
select a.p_type,p_name,(p_view/view_avg)*0.3+(sales/sales_avg)*0.7 from 
(
	select a.p_type,a.p_name,a.p_view,IFNULL(b.p_sales,0) as sales from products a  
	left join products_sales b on a.p_id=b.p_id
	group by a.p_type,a.p_name order by a.p_type desc,a.p_view desc
) a,
(
	select p_type,round(sum(p_view)/count(*),0) as view_avg
	from products group by p_type
) b,
(
	select p_type,round(sum(sales)/count(*),0) as sales_avg from
	(select a.p_type,a.p_name,a.p_view,IFNULL(b.p_sales,0) as sales from products a
	left join products_sales b on a.p_id=b.p_id
	order by a.p_type,a.p_view desc) a
	where a.sales>0
	GROUP BY p_type
) c
where a.p_type = b.p_type and a.p_type=c.p_type

在这里插入图片描述

4. 自连接查询;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章