用一道題 來 復習 MySQL 的 復雜 sql 語句


1.前言

  太久沒有在數據庫做一些復雜的sql了,基本上將數據庫的查詢邏輯全放在了Java里做,

一來呢,可以減輕數據庫的負擔,二來呢,在java寫,邏輯感會更強,數據類型更豐富也容易操作。

  然而。。。面試卻喜歡靠復雜的sql ,好吧,即便我不想,但復習一波還是免不了的。

常用的關系型數據庫有 MySQL和Oracle 。Oracle 比較喜歡使用存儲過程做業務 ,當然,MySQL也可以,但是沒怎么用,

自從工程使用mybatis框架,就不再使用存儲過程了,業務基本是增刪改查,查詢數據的邏輯都是從數據庫取相應數據出來后用Java計算,

再從數據庫獲取最終想要的數據,本來是本着減輕數據庫負擔才這樣做的,並發操作會用上積極鎖【樂觀鎖】,因此也就不需要擔心 臟數據問題。

  MySQL和Oracle的語法部分是不同的,有時候用着MySQL,寫着寫着就用上了Oracle的語法,還一臉懵逼的查了半天到底哪里錯,不常使用的東西就是容易忘。

總結:
(1)Oracle 使用nvl() 函數,MySQL使用 ifnull() 函數 來對數據進行判斷是否為空,
如果是空則使用替代的數據 ,參數一樣 ,如if(x.age,0),意思是如果年齡字段為空則
輸出 0 .
(2)sum()函數是運算函數,允許 加減乘除計算 ,如果要使用,則必須使用
group by 分組 ,限定好分組 sum獲取的計算數據才不會錯,否則將會導致全表計算在一起。
(3)avg()函數是計算平均數的,用法根據需要與 group by 分組配合使用,
如果是計算全表某字段的平均分,則不要使用。
(4)having 關鍵字可以篩選分組后的各組數據,也就是說可對分組完成后的數據做邏輯條件判斷 ,與where類似,但是where無法這樣使用,因為where關鍵字無法與聚合函數一起使用

 

2.復習題

數據庫源碼

/*
Navicat MySQL Data Transfer

Source Server         : cen
Source Server Version : 50528
Source Host           : localhost:3306
Source Database       : kktest

Target Server Type    : MYSQL
Target Server Version : 50528
File Encoding         : 65001

Date: 2020-06-17 08:21:15
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for bjb
-- ----------------------------
DROP TABLE IF EXISTS `bjb`;
CREATE TABLE `bjb` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of bjb
-- ----------------------------
INSERT INTO `bjb` VALUES ('1', '一班');
INSERT INTO `bjb` VALUES ('2', '2班');
INSERT INTO `bjb` VALUES ('3', '3班');

-- ----------------------------
-- Table structure for cjb
-- ----------------------------
DROP TABLE IF EXISTS `cjb`;
CREATE TABLE `cjb` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `id_sx` int(11) DEFAULT NULL,
  `yw` int(11) DEFAULT NULL,
  `sx` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of cjb
-- ----------------------------
INSERT INTO `cjb` VALUES ('1', '1', '77', '67');
INSERT INTO `cjb` VALUES ('2', '2', '32', '27');
INSERT INTO `cjb` VALUES ('3', '3', '98', '78');
INSERT INTO `cjb` VALUES ('4', '4', '68', '63');
INSERT INTO `cjb` VALUES ('5', '5', '66', '77');
INSERT INTO `cjb` VALUES ('6', '6', '99', '88');
INSERT INTO `cjb` VALUES ('7', '7', '75', '45');
INSERT INTO `cjb` VALUES ('8', '8', '77', '88');
INSERT INTO `cjb` VALUES ('9', '9', '65', '81');
INSERT INTO `cjb` VALUES ('10', '10', '83', '89');

-- ----------------------------
-- Table structure for xsb
-- ----------------------------
DROP TABLE IF EXISTS `xsb`;
CREATE TABLE `xsb` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `id_banji` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of xsb
-- ----------------------------
INSERT INTO `xsb` VALUES ('1', '岑', '1');
INSERT INTO `xsb` VALUES ('2', 'cen', '1');
INSERT INTO `xsb` VALUES ('3', 'y', '2');
INSERT INTO `xsb` VALUES ('4', 'u', '3');
INSERT INTO `xsb` VALUES ('5', 'yue', '2');
INSERT INTO `xsb` VALUES ('6', 'kk', '2');
INSERT INTO `xsb` VALUES ('7', 'tom', '1');
INSERT INTO `xsb` VALUES ('8', 'lili', '1');
INSERT INTO `xsb` VALUES ('9', 'kile', '3');
INSERT INTO `xsb` VALUES ('10', 'jack', '2');
INSERT INTO `xsb` VALUES ('11', 'hh', '2');

-- ----------------------------
-- Procedure structure for sp_add3
-- ----------------------------
DROP PROCEDURE IF EXISTS `sp_add3`;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_add3`(a int, b int,out c int)
begin 
set c=a+ b;
end
;;
DELIMITER ;
kktest.sql

學生表【字段意思:學生id、姓名、班級id】

 

 班級表【字段意思:班級id、班級名稱】

 

 

 

成績表【字段意思:成績id、學生id、語文成績、數學成績】

 

 

 

【注意:11號同學hh ,他沒有成績,他作弊被取消了考試資格,因此成績表沒有他的信息】

 (1)查詢所有學生的信息

寫法一:

select x.id,x.name,b.name n from xsb x
left join bjb b on b.id = x.id_banji;

查詢結果

 

 

 寫法二:

select x.id,x.name,b.name n2 from xsb x,bjb b
where b.id = x.id_banji;

查詢結果與上圖一樣

(2)查詢所有人的課程分數

寫法一:【查詢11號同學為null】

select x.name,b.name n ,c.yw ,c.sx from xsb x
left join bjb b on b.id = x.id_banji
left join cjb c on c.id_sx = x.id ;

查詢結果

 

 

 寫法二:【查詢11號同學為0】

select x.name,b.name n , ifnull(c.yw,0)  , ifnull(c.sx,0)  from xsb x
left join bjb b on b.id = x.id_banji
left join cjb c on c.id_sx = x.id ;

 

查詢結果

 

 

 

 寫法三:【查詢無11號同學】不使用left join會導致沒有成績的那個同學不顯示,因為直接連表查詢只會保留所有關聯條件成立的數據

select x.name,b.name n , ifnull(c.yw,0)  , ifnull(c.sx,0)  from xsb x,bjb b,cjb c
WHERE b.id = x.id_banji
and c.id_sx = x.id ;

 

查詢結果

 

 (3)查詢語文分數比“yue”的高的學生,【 如果是查詢比“yue”的低, 不使用ifnull那么沒有成績的同學無法查看到】

select x.name,b.name n , ifnull(c.yw,0)  from xsb x
left join bjb b on b.id = x.id_banji
left join cjb c on c.id_sx = x.id 
where ifnull(c.yw,0) > 
(
select c.yw from cjb c 
left join xsb x on c.id_sx = x.id 
where x.name= "yue"
)

 

查詢結果

 

 

(4)查詢各科都合格【分數>=60分】的學生(姓名、語文分數、數學分數)

select x.name , c.yw ,c.sx
from xsb x
left join cjb c on  c.id_sx =x.id
WHERE c.yw>60 and c.sx >60

打印結果

 

 (5)查詢總分數(語文+數學)>=150的學生信息(姓名、班級名稱、總分數)

select x.name,b.name n ,
ifnull(c.yw,0) as "語文",ifnull(c.sx,0) as "數學",
#sum是運算函數 ,在里面可以做加減乘除
sum(ifnull(c.yw,0) + ifnull(c.sx,0)) as "總分"
 from xsb x
left join bjb b on b.id = x.id_banji
left join cjb c on c.id_sx = x.id 
where (ifnull(c.yw,0) +ifnull(c.sx,0)) >=150
#計算總分必須要分組,加上這個GROUP BY x.id,表示以一位學生為一組計算總分,否則會全部加在一起
GROUP BY x.id 

查詢結果

 

 (6)查詢沒有參加考試【沒有成績表】的學生(姓名、班級名稱)

寫法一:

select x.name,b.name n   from xsb x
left join bjb b on b.id = x.id_banji
left join cjb c on c.id_sx = x.id 
where x.id not in (select id_sx from cjb);

查詢結果

 

 寫法二:

select x.name,b.name n  from xsb x ,bjb b ,cjb c
WHERE x.id_banji = b.id and x.id not in (select id_sx from cjb)
GROUP BY x.name,b.name ;

 

查詢結果與上圖一樣

(7)假設分數>=60分合格,分析學生的成績是否合格

select x.name,if(c.yw>=60,"合格","不合格") as "語文成績" ,
 if(c.sx>=60,"合格","不合格") as "數學成績"  
from xsb x
left join cjb c on c.id_sx = x.id 

查詢結果

 

 

(8)查詢有掛科【分數<60分】現象的學生(姓名、語文分數、數學分數)

select x.name ,ifnull( c.yw ,0),ifnull(c.sx,0)
from xsb x
left join cjb c on  c.id_sx =x.id
WHERE ifnull( c.yw ,0) <60 or ifnull(c.sx,0)<60;

查詢結果

 

 (9)查詢所有班級的平均分數(班級編號、班級名稱、語文平均分數、數學平均分數)

 寫法一:

select b.name , AVG(c.yw) as "語文平均分數" ,AVG(c.sx) as "數學平均分數" from xsb x
left join bjb b on b.id = x.id_banji
left join cjb c on c.id_sx = x.id 
GROUP BY b.id ;

查詢結果

 

 寫法二:【主從表換了沒影響】

select b.name , AVG(c.yw) as "語文平均分數" ,AVG(c.sx) as "數學平均分數" from bjb b
left join xsb x on b.id = x.id_banji
left join cjb c on c.id_sx = x.id 
GROUP BY b.id

 

 查詢結果與上圖一樣

(10)查詢班級人數>=3的班級(班級編號、班級名稱、人數)

select b.id ,b.name , count(x.id) as "人數"
from bjb b 
left join xsb x on b.id = x.id_banji
#HAVING 子句可以讓我們篩選分組后的各組數據。
group by b.id having count(x.id) >=3

查詢結果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM