資料庫學習4
阿新 • • 發佈:2022-03-19
一、DQL查詢資料(重點)
1、DQL
Data Query Language :資料查詢語言
- 所有的查詢操作都用它 Select
- 簡單的查詢,複雜的查詢都能做
- 資料庫中最核心的語言,最重要的語句
- 使用頻率最高的語句
2、SQL語法
SELECT [ALL | DISTINCT] -- distinct去重 {* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]} -- AS取別名 FROM table_name [as table_alias] [left | right | inner join table_name2] -- 聯表查詢 [WHERE ...] -- 指定結果需滿足的條件 [GROUP BY ...] -- 指定結果按照哪幾個欄位來分組 [HAVING] -- 過濾分組的記錄必須滿足的次要條件where不能使用聚合函式,但是having可以 [ORDER BY ...] -- 指定查詢記錄按一個或多個條件排序 [LIMIT {[offset,]row_count | row_countOFFSET offset}]; -- 指定查詢的記錄從哪條至哪條 -- 以上的順序也是不能更換的
- 注意 : [ ] 括號代表可選的 , { }括號代表必選
3、指定查詢欄位
語法:select 欄位,.... from 表;
-- 查詢表中所有的資料列結果 , 採用 **" \* "** 符號; 但是效率低,不推薦 .
-- 查詢所有學生資訊
SELECT * FROM student;
-- 查詢指定列(學號 , 姓名)
SELECT studentno,studentname FROM student;
(1)AS 子句作為別名
作用:
- 可給資料列取一個新別名;
- 可給表取一個新別名;
- 可把經計算或總結的結果用另一個新名稱來代替;
-- 這裡是為列取別名(當然as關鍵詞可以省略) SELECT studentno AS 學號,studentname AS 姓名 FROM student; -- 使用as也可以為表取別名 SELECT studentno AS 學號,studentname AS 姓名 FROM student AS s;
(2)CONCAT()函式拼接字串
-- 使用CONCAT()函式拼接字串
-- 使用as,為查詢結果取一個新名字
-- CONCAT()函式拼接字串
SELECT CONCAT('姓名:',studentname) AS 新姓名 FROM student;
(3)去除重複
去重 distinct
作用:去掉SELECT查詢返回的記錄結果中重複的資料 ( 返回所有列的值都相同 ) , 重複資料只顯示一條。
-- 檢視哪些同學參加了考試(學號) 去除重複項 SELECT * FROM result; -- 檢視考試成績 SELECT studentno FROM result; -- 檢視哪些同學參加了考試 SELECT DISTINCT studentno FROM result; -- 瞭解:DISTINCT 去除重複項 , (預設是ALL)
(4)資料庫的列(表示式)
- 資料庫中的表示式 : 一般由文字值 , 列值 , NULL , 函式和操作符,系統變數等組成。
- 語法:select 表示式 from 表;
應用場景 :
- SELECT語句返回結果列中使用;
- SELECT語句中的ORDER BY , HAVING等子句中使用;
- DML語句中的 where 條件語句中使用表示式。
-- selcet查詢中可以使用表示式
SELECT VERSION(); -- 查詢版本號
SELECT 100*3-1 AS 計算結果; -- 表示式
SELECT @@auto_increment_increment; -- 查詢自增步長
-- 學員考試成績+1分後檢視
SELECT studentno,StudentResult+1 AS '提分後' FROM result;
- 避免SQL返回結果中包含 ’ . ’ , ’ * ’ 和括號等干擾開發語言程式。
4、where條件子句
作用:檢索資料中符合條件的值
- 搜尋條件可由一個或多個邏輯表示式組成 , 結果一般為真或假。
(1)邏輯運算子:
操作符名稱 | 語法 | 描述 |
---|---|---|
AND 或 && | a AND b 或 a && b | 邏輯與,同時為真結果才為真 |
OR 或 || | a OR b 或 a || b | 邏輯或,只要一個為真,則結果為真 |
NOT 或 ! | NOT a 或 !a | 邏輯非,若運算元為假,則結果為真 |
測試:
-- =============where===============
SELECT studentno,studentResult FROM result;
-- 查詢考試成績在95-100之間的
SELECT studentno,studentresult
FROM result
WHERE studentresult>=95 AND studentresult<=100;
-- AND也可以寫成 &&
SELECT studentno,studentresult
FROM result
WHERE studentresult>=95 AND studentresult<=100;
-- 模糊查詢
SELECT studentno,studentresult
FROM result WHERE studentresult BETWEEN 95 AND 100;
-- 除了1000號同學,要其他同學的成績
SELECT studentno,studentresult
FROM result WHERE studentno!=1000;
-- 使用NOT
SELECT studentno,studentresult
FROM result WHERE NOT studentno=1000;
(2)模糊查詢:比較運算子
操作符名稱 | 語法 | 描述 |
---|---|---|
IS NULL | a IS NULL | 若操作符為NULL,則結果為真 |
IS NOT NULL | a IS NOT NULL | 若操作符不為NULL,則結果為真 |
BETWEEN | a BETWEEN b AND c | 若a範圍在b與c之間,則結果為真 |
LIKE | a LIKE b | SQL模式匹配,若a匹配b,則結果為真 |
IN | a IN (a1,a2,a3...) | 若a等於a1,a2…中的某一個,則結果為真 |
- 注意:
- 數值資料型別的記錄之間才能進行算術運算 ;
- 相同資料型別的資料之間才能進行比較 ;
測試:
-- ===================LIKE==========================
-- 查詢姓劉的同學的學號及姓名
-- like結合使用的萬用字元 : % (代表0到任意個字元) _ (一個字元)
SELECT studentno,studentname FROM student
WHERE studentname LIKE '劉%';
-- 查詢姓劉的同學,後面只有一個字的
SELECT studentno,studentname FROM student
WHERE studentname LIKE '劉_';
-- 查詢姓劉的同學,後面只有兩個字的
SELECT studentno,studentname FROM student
WHERE studentname LIKE '劉__';
-- 查詢姓名中含有 嘉 字的
SELECT studentno,studentname FROM student
WHERE studentname LIKE '%嘉%';
-- 查詢姓名中含有特殊字元的需要使用轉義符號 '\'
-- 自定義轉義符關鍵字: ESCAPE ':'
-- =====================IN========================
-- 查詢學號為1000,1001,1002的學生姓名
SELECT studentno,studentname FROM student
WHERE studentno IN (1000,1001,1002);
-- 查詢地址在北京,南京,河南洛陽的學生
SELECT studentno,studentname,address FROM student
WHERE address IN ('北京','南京','河南洛陽');
-- ====================NULL 空=========================
-- 查詢出生日期沒有填寫的同學
-- 不能直接寫=NULL , 這是代表錯誤的 , 用 is null
SELECT studentname FROM student
WHERE BornDate IS NULL;
-- 查詢沒有寫家庭住址的同學(空字串不等於null)
SELECT studentname FROM student
WHERE Address='' OR Address IS NULL;
-- 查詢出生日期填寫的同學
SELECT studentname FROM student
WHERE BornDate IS NOT NULL;
5、聯表查詢
(1)JOIN 對比
操作符名稱 | 描述 |
---|---|
INNER JOIN | 如果表中有至少一個匹配,則返回行(並集) |
LEFT JOIN | 即使右表中沒有匹配,也從左表中返回所有的行 |
RIGHT JOIN | 即使左表中沒有匹配,也從右表中返回所有的行 |
- 七種JOIN
- JOIN(連線的表) ON(判斷條件) 連線查詢
- WHERE 等值查詢
-- 查詢參加了考試的同學資訊(學號,學生姓名,科目編號,分數)
SELECT * FROM student;
SELECT * FROM result;
/*思路:
(1):分析需求,分析查詢的欄位來自哪些表(連線查詢)
(2):確定使用哪種連線查詢?(7種,內連線)
(3):確定交叉點,這兩個表中哪些資料是相同的
判斷的條件:學生表中的studentNo = 成績表中的 studentNo
*/
SELECT s.studentNo,studentName,subjectNo,StudentResult
FROM student AS s
INNER JOIN result AS r
ON r.studentNo = s.studentNo;
-- 右連線(也可實現)
SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s
RIGHT JOIN result r
ON r.studentno = s.studentno;
-- 等值連線
SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s , result r
WHERE r.studentno = s.studentno;
-- 左連線 (查詢了所有同學,不考試的也會查出來)
SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s
LEFT JOIN result r
ON r.studentno = s.studentno;
-- 查詢缺考的同學(左連線應用場景)
SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s
LEFT JOIN result r
ON r.studentno = s.studentno
WHERE StudentResult IS NULL;
-- 思考題:查詢參加了考試的同學資訊(學號,學生姓名,科目名,分數)--三表查詢
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON sub.subjectno = r.subjectno;
-- 查詢學員及所屬的年級(學號,學生姓名,年級名)
SELECT studentno AS 學號,studentname AS 學生姓名,gradename AS 年級名稱
FROM student s
INNER JOIN grade g
ON s.`GradeId` = g.`GradeID`;
-- 查詢科目及所屬的年級(科目名稱,年級名稱)
SELECT subjectname AS 科目名稱,gradename AS 年級名稱
FROM SUBJECT sub
INNER JOIN grade g
ON sub.gradeid = g.gradeid;
-- 查詢 資料庫結構-1 的所有考試結果(學號 學生姓名 科目名稱 成績)
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='資料庫結構-1';
總結1:
- 要查詢不能哪些資料 select
- 從那幾個表中查 from 表 XXX join 連線的表 on 交叉條件
- 假設存在一種多張表查詢,可以先查詢兩張表開始,然後慢慢增加
(2)自連線
- 自己的表和自己的表連線,核心:一張表拆成兩張一樣的表即可
/*
需求:從一個包含欄目ID , 欄目名稱和父欄目ID的表中
查詢父欄目名稱和其他子欄目名稱
*/
-- 建立一個表
CREATE TABLE `category` (
`categoryid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主題id',
`pid` INT(10) NOT NULL COMMENT '父id',
`categoryName` VARCHAR(50) NOT NULL COMMENT '主題名字',
PRIMARY KEY (`categoryid`)
) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
-- 插入資料
INSERT INTO `category` (`categoryid`, `pid`, `categoryName`)
VALUES('2','1','資訊科技'),
('3','1','軟體開發'),
('4','3','資料庫'),
('5','1','美術設計'),
('6','3','web開發'),
('7','5','ps技術'),
('8','2','辦公資訊');
-- 編寫SQL語句,將欄目的父子關係呈現出來 (父欄目名稱,子欄目名稱)
-- 核心思想:把一張表看成兩張一模一樣的表,然後將這兩張表連線查詢(自連線)
SELECT a.`categoryName` AS '父欄目',b.`categoryName` AS '子欄目'
FROM `category` AS a,`category` AS b
WHERE a.`categoryid` = b.`pid`;
查詢前表:
自連線查詢後的結果:
總結2:
- 連線查詢
- 如需要多張資料表的資料進行查詢,則可通過連線運算子實現多個查詢。
- 內連線 inner join
- 查詢兩個表中的結果集中的交集。
- 外連線 outer join
- 左外連線 left join——(以左表作為基準,右邊表來一一匹配,匹配不上的,返回左表的記錄,右表以NULL填充)。
- 右外連線 right join——(以右表作為基準,左邊表來一一匹配,匹配不上的,返回右表的記錄,左表以NULL填充)。
- 等值連線和非等值連線。
- 自連線
6、排序和分頁
- 排序 order by
- 分頁 limit
(1)排序
- 升序 ASC
- 降序 DESC
語法:order by 欄位名 排序;
- ORDER BY 語句用於根據指定的列對結果集進行排序。
- ORDER BY 語句預設按照ASC升序對記錄進行排序。
- 如果希望按照降序對記錄進行排序,可以使用
DESC
關鍵字。
-- 查詢 資料庫結構-1 的所有考試結果(學號 學生姓名 科目名稱 成績)
-- 按成績降序排序
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='資料庫結構-1'
ORDER BY StudentResult DESC;
-- 如果成績一樣,按其他規則排列,比如學號的升序與降序。
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='資料庫結構-1'
ORDER BY StudentResult DESC, studentno DESC;
ORDER BY StudentResult, studentno DESC;
-- 此處的正確理解是:成績升序排列、學號降序排列。因為DESC是修飾studentno的,而StudentResult 是預設的。
(2)分頁
- 為什麼要分頁:緩解資料庫壓力,給人更好的體驗,區別的是瀑布流
- 網頁應用:當前頁面,總的頁數,一頁顯示多少條資料
語法:SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset;
/*
推導:
第一頁 : limit 0,5 (1-1)*5
第二頁 : limit 5,5 (2-1)*5
第三頁 : limit 10,5 (3-1)*5
......
第N頁 : limit (n-1)*pageSzie,pageSzie
n:當前頁碼
limit (n-1)*pageSzie:當前頁
pageSize:單頁面顯示條數
總頁數 = 資料總數/單頁面顯示條數
*/
-- 需求:查詢 資料庫結構-1 的所有考試結果(學號 學生 科目名稱 成績),成績
-- 每頁顯示5條資料
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='資料庫結構-1'
ORDER BY StudentResult DESC , studentno
LIMIT 0,5;
-- 查詢 JAVA第一學年 課程成績前10名並且分數大於80的學生資訊(學號,姓名,課程名,分數)
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE studentresult>80 AND subjectname='JAVA第一學年'
ORDER BY StudentResult DESC
LIMIT 0,10;
7、子查詢
本質:在where語句中巢狀一個子查詢語句
什麼是子查詢?
- 在查詢語句中的WHERE條件子句中,又嵌套了另一個查詢語句;
- 巢狀查詢可由多個子查詢組成,求解的方式是由裡及外;
- 子查詢返回的結果一般都是集合,故而建議使用IN關鍵字;
-- 查詢 資料庫結構-1 的所有考試結果(學號,科目編號,成績),並且成績降序排列
-- 方法一:使用連線查詢
SELECT studentno,r.subjectno,StudentResult
FROM result r
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE subjectname = '資料庫結構-1'
ORDER BY studentresult DESC;
-- 方法二:使用子查詢(執行順序:由裡及外)
SELECT studentno,subjectno,StudentResult
FROM result
WHERE subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname = '資料庫結構-1'
)
ORDER BY studentresult DESC;
-- 查詢課程為 高等數學-2 且分數不小於80分的學生的學號和姓名
-- 方法一:使用連線查詢
SELECT s.studentno,studentname
FROM student s
INNER JOIN result r
ON s.`StudentNo` = r.`StudentNo`
INNER JOIN `subject` sub
ON sub.`SubjectNo` = r.`SubjectNo`
WHERE subjectname = '高等數學-2' AND StudentResult>=80;
-- 方法二:使用連線查詢+子查詢
-- 分數不小於80分的學生的學號和姓名
SELECT r.studentno,studentname FROM student s
INNER JOIN result r ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=80;
-- 在上面SQL基礎上,新增需求:課程為 高等數學-2
SELECT r.studentno,studentname FROM student s
INNER JOIN result r ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=80 AND subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname = '高等數學-2'
);
-- 方法三:使用子查詢
-- 分步寫簡單sql語句,然後將其巢狀起來
SELECT studentno,studentname FROM student WHERE studentno IN(
SELECT studentno FROM result WHERE StudentResult>=80 AND subjectno=(
SELECT subjectno FROM `subject` WHERE subjectname = '高等數學-2'
)
);
8、分組和過濾
- 分組 GROUP BY
- 過濾 HAVING
-- 查詢不同課程的平均分,最高分,最低分
-- 前提:根據不同的課程進行分組
SELECT subjectname,AVG(studentresult) AS 平均分,MAX(StudentResult) AS 最高分,MIN(StudentResult) AS 最低分
FROM result AS r
INNER JOIN `subject` AS s
ON r.subjectno = s.subjectno
GROUP BY r.subjectno
HAVING 平均分>80;
/*
where寫在group by前面.
要是放在分組後面的篩選
要使用HAVING..
因為having是從前面篩選的欄位再篩選,而where是從資料表中的>欄位直接進行的篩選的
*/
二、MySQL函式
官方文件:https://dev.mysql.com/doc/refman/8.0/en/
1、常用函式
- 數值函式
SELECT ABS(-8); -- 絕對值函式
SELECT CEILING(9.4); -- 向上取整/
SELECT FLOOR(9.4); -- 向下取整
SELECT RAND(); -- 隨機數,返回一個0-1之間的隨機數
SELECT SIGN(0); -- 符號函式: 負數返回-1,正數返回1,0返回0
- 字串函式
SELECT CHAR_LENGTH('Java堅持就能成功'); -- 返回字串包含的字元數
SELECT CONCAT('我','改','程式'); -- 合併字串,引數可以有多個
SELECT INSERT('我在程式設計hello world',1,2,'為了鹹魚'); -- 替換字串,從某個位置開始替換某個長度
SELECT LOWER('subeiLY'); -- 小寫
SELECT UPPER('unremittingly'); -- 大寫
SELECT LEFT('hello,world',5); -- 從左邊擷取
SELECT RIGHT('hello,world',5); -- 從右邊擷取
SELECT REPLACE('Java堅持就能成功','鹹魚','努力'); -- 替換字串
SELECT SUBSTR('Java堅持就能成功',4,6); -- 擷取字串,開始和長度
SELECT REVERSE('Java堅持就能成功'); -- 反轉
-- 查詢姓周的同學,改成鄒
SELECT REPLACE(studentname,'周','鄒') AS 新名字
FROM student WHERE studentname LIKE '周%';
- 日期函式
SELECT CURRENT_DATE(); -- 獲取當前日期
SELECT CURDATE(); -- 獲取當前日期
SELECT NOW(); -- 獲取當前日期和時間
SELECT LOCALTIME(); -- 獲取當前日期和時間
SELECT SYSDATE(); -- 獲取當前日期和時間
-- 獲取年月日,時分秒
SELECT YEAR(NOW());
SELECT MONTH(NOW());
SELECT DAY(NOW());
SELECT HOUR(NOW());
SELECT MINUTE(NOW());
SELECT SECOND(NOW());
- 系統資訊函式
SELECT VERSION(); -- 版本
SELECT USER(); -- 使用者
2、聚合函式(常用)
函式名稱 | 描述 |
---|---|
COUNT() | 返回滿足Select條件的記錄總和數,如 select count(*) 【不建議使用 *,效率低】 |
SUM() | 返回數字欄位或表示式列作統計,返回一列的總和。 |
AVG() | 通常為數值欄位或表達列作統計,返回一列的平均值 |
MAX() | 可以為數值欄位,字元欄位或表示式列作統計,返回最大的值。 |
MIN() | 可以為數值欄位,字元欄位或表示式列作統計,返回最小的值。 |
- 從含義上講,count(1) 與 count(*) 都表示對全部資料行的查詢。
- count(欄位) 會統計該欄位在表中出現的次數,忽略欄位為null 的情況。即不統計欄位為null 的記錄。
- count(*) 包括了所有的列,相當於行數,在統計結果的時候,包含欄位為null 的記錄;
- count(1) 用1代表程式碼行,在統計結果的時候,包含欄位為null 的記錄 。
ps:很多人認為count(1)執行的效率會比count(* )高,原因是count( * )會存在全表掃描,而count(1)可以針對一個欄位進行查詢。其實不然,count(1)和count(*)都會對全表進行掃描,統計所有記錄的條數,包括那些為null的記錄,因此,它們的效率可以說是相差無幾。而count(欄位)則與前兩者不同,它會統計該欄位不為null的記錄條數。
- 兩者之間的對比:
- 1)在表沒有主鍵時,count(1)比count(*)快;
- 2)有主鍵時,主鍵作為計算條件,count(主鍵)效率最高;
- 3)若表格只有一個欄位,則count(*)效率較高。
3、資料庫級別的MD5加密
(1)什麼的MD5?
- 主要增強演算法複雜度和不可逆性。
- MD5不可逆,具體的值的md5是一樣的;
- MD5破解網站的原理,背後有一個字典,MD5加密後的值,加密的前值。
(2)實現資料加密
-- 1、新建一個表 testmd5
CREATE TABLE `testmd5` (
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 2、插入資料(明文密碼)
INSERT INTO testmd5 VALUES(1,'zhansan','123456'),(2,'lisi','456789');
-- 3、對pwd這一列資料進行加密,語法是
update testmd5 set pwd = md5(pwd); #全部加密
UPDATE testmd5 SET pwd = MD5(pwd) WHERE NAME='lisi'; #單獨對一個使用者加密
-- 4、插入新的資料自動加密
INSERT INTO testmd5 VALUES(3,'wawu',md5('123586'));
-- 5、如何校驗:將使用者傳遞進來的密碼,進行md5加密,然後比對加密後的值
SELECT * FROM testmd5 WHERE `name`='wawu' AND pwd=MD5('123586');