業務場景下 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. 自連接查詢;

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