1. 程式人生 > 其它 >資料庫學習4

資料庫學習4

一、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');