1. 程式人生 > >MySQL筆記(一):基礎知識

MySQL筆記(一):基礎知識

MySQL筆記(一):基礎知識

1、GBK中一個漢字佔2個位元組,一個字母佔一個位元組;UTF-8中一個漢字佔3個位元組,一個字母佔一個位元組

在Mysql中進行驗證:

檢視Mysql客戶端的編碼方式:

select variables like '%char%';

檢視字串的位元組長度,length()方法獲取的是位元組的長度:

select length('張三丰hello');

MySQL中位元組與字元是有區別的,一個字母和一個漢字都算是一個字元,但是二者所佔的位元組數是不一樣的

2、MySQL中和分組函式一同查詢出來的資料要求是group by後的資料

常見的分組函式:sum、avg、count、min、max

例如:查詢各個部門的總人數和平均工資

# SELECT中的department_id必須是GROUP BY的欄位,否則會報錯
SELECT 
	department_id, count(*), AVG(salary)
FROM
	employees
GROUP BY department_id

3、DATEDIFF()函式可以求兩個日期之間相差的天數

SELECT DATEDIFF(now(), '1995-5-20');

4、having可以對分組(group by)後的結果進行篩選

例如:查詢員工數大於2的部門

SELECT
	department_id AS 部門編號,
	count( * ) AS 部門總人數 
FROM
	employees 
GROUP BY
	department_id 
HAVING
	count( * ) > 2

having是對前面的查詢結果再進行篩選,注意:count(*) > 2不能放在where中,where中只能查詢from 表中存在的欄位

分組篩選總結:

①分組篩選分為兩大類:分組前篩選和分組後篩選

資料來源 位置 關鍵字
分組前篩選 原始表(from表) group by子句的前面 where
分組後篩選 分組後得到的結果集 group by子句的後面面 having

②分組函式做條件肯定是放在having子句中,常見的分組函式:sum、max、min、count、avg

③能使用分組前篩選的,優先考慮使用分組前篩選,可以提高查詢效率

④group by中支援多個欄位分組,並且欄位之間的先後順序沒有要求

⑤Mysql中,group by和having子句中都支援別名;Oracle中,group by和having子句中都不支援別名;所以,儘量不要在group by和having子句中使用別名

5、如果為表起了別名,則查詢的欄位就不能再使用原來的表名進行限定

例如:

select student.name from student s where student.id=1(錯誤)
select s.name from student s where s.id=1(正確)

6、ifnull函式,判斷某欄位或表示式是否為null,如果為null 返回指定的值,否則返回原本的值

例如:

select ifnull(commission_pct,0) from employees;

isnull函式,判斷某欄位或表示式是否為null,如果是,則返回1,否則返回0

7、like用於模糊查詢,不僅可以用於字元,也可以用於數字。萬用字元:%任意多個字元,_任意單個字元

# slary是數字型別
select
	salary
from 
	employees
where
	salary like '_2%';

8、連線查詢

①連線分為內連線和外連線,內連線分為等值連線、非等值連線、自連線,外連線分為左連線(left join)、右連線(right join)、全連線(full join)

②inner join的效果與內連線中的等值連線是一樣的,並且inner關鍵字可以省略

一、內連線

特點:

多表等值連線的查詢結果為多表的交集部分

②n表連線至少需要n-1個連線條件

查詢時,多表的順序沒有要求

④儘量為表起別名

⑤可以搭配排序、分組、篩選等子句一起使用

分類:等值連線、非等值連線、自連線

下面的方式一和方式二的查詢效果完全相同

(1)等值連線
# 方式一
SELECT
	last_name,
	department_name 
FROM
	employees e,
	departments d 
WHERE
	e.department_id = d.department_id
	
	
# 方式二	
SELECT
	last_name,
	department_name 
FROM
	employees e
[INNER] JOIN 
	departments d 
ON 
	e.department_id = d.department_id
(2)非等值連線
# 案例:查詢每個員工的工資級別
#方式一:
SELECT
	last_name,
	salary,
	grade_level 
FROM
	employees e,
	grade g 
WHERE
	e.salary BETWEEN g.lowest_sal AND g.highest_sal
	
# 方式二:
SELECT
	last_name,
	salary,
	grade_level 
FROM
	employees e
[INNER] JOIN 
	grade g 
ON 
	e.salary BETWEEN g.lowest_sal AND g.highest_sal
(3)自連線
# 案例:查詢員工和員工領導的資訊
# 方式一:
SELECT
	e.employee_id,
	e.last_name,
	m.employee_id,
	m.last_name 
FROM
	employees e,
	employees m 
WHERE
	e.manager_id = m.employee_id
	
# 方式二:
SELECT
	e.employee_id,
	e.last_name,
	m.employee_id,
	m.last_name 
FROM
	employees e
[INNER] JOIN
	employees m 
ON
	e.manager_id = m.employee_id
二、外連線

特點:

1、外連線的查詢結果為主表中的所有記錄

如果從表中有和它匹配的資料,則查詢匹配的值

如果從表中沒有和它匹配的資料,則顯示null

外連線查詢結果=內連線查詢結果+主表中有而從表中沒有的資料

2、左外連線,left join左邊的是主表;右外連線,right join右邊的是主表

​3、左外連線和右外連線交換兩個表的順序,可以實現同樣的效果

分類:左外連線、右外連線

(1)左外連線
# 查詢員工ID、員工名、員工工資和員工所在部門的部門名
SELECT
	employee_id, last_name, salary, department_name
FROM
	employees e
LEFT JOIN
	departments d
ON 
	e.department_id = d.department_id
(2)右外連線
# 查詢員工ID、員工名、員工工資和員工所在部門的部門名,與上面的左外連線的效果是一樣的
SELECT
	employee_id, last_name, salary, department_name
FROM
	departments d
RIGHT JOIN
	employees e
ON 
	e.department_id = d.department_id

9、子查詢

一、按結果集的行列數分類

①標量子查詢:結果集只有一行一列

②列子查詢:結果集只有一列多行

③行子查詢:結果集一行多列

④表子查詢:結果集多行多列

二、按子查詢出現的位置分類
(1)出現在select後面

僅僅支援標量子查詢

# 查詢每個部門的員工個數, employees是員工資訊表,departments是部門資訊表
SELECT d.*, (
	SELECT
		count(*)
	FROM
		employees e
	WHERE
		e.department_id = d.department_id
) count
FROM
	departments d
ORDER BY
	count 
DESC

# 查詢每個專業的男生總數和女生總數(※)
SELECT
	majorid,
	(
		SELECT 
			count(*)
		FROM
			student t1
		where
			sex = '男'
		AND
			t1.majorid = t.majorid
	) boynum,
	(
		SELECT 
			count(*)
		FROM
			student t1
		where
			sex = '女'
		AND
			t1.majorid = t.majorid
	)
FROM
	student t
GROUP BY
	majorid
(2)出現在from後面

支援表子查詢

# 查詢每個部門的平均工資的工資等級,以及部門id和部門名
SELECT
	department_id, 
	(
		SELECT 
			department_name
		FROM
			departments d
		WHERE
			new_tab.department_id=d.department_id
	) avg_salary,
	CASE 
		WHEN avg_salary>20000 THEN '高等收入'
		WHEN avg_salary>10000 THEN '中等收入'
		ELSE '低等收入'
	END AS '收入等級'
FROM (
	SELECT
		department_id,  avg(salary) avg_salary
	FROM
		employees
	WHERE
		department_id IS NOT NULL
	GROUP BY
		department_id
) new_tab
(3)出現在where或having後面

支援標量子查詢、列子查詢,也支援行子查詢

# 查詢工資最高的員工所在的部門的部門名
SELECT
	department_name
FROM
	departments d
WHERE
	d.department_id in (
		SELECT
			department_id
		FROM
			employees e
		WHERE
			e.salary in (
				SELECT 
					max(salary)
				FROM
					employees
			)
	)
	
# 查詢平均工資高於公司總平均工資的部門資訊
SELECT
	*
FROM
	departments
WHERE
	department_id in (
		SELECT
			department_id
		FROM
			employees
		GROUP BY
			department_id
		HAVING
			AVG(salary) > (
				SELECT
					AVG(salary)
				FROM
					employees
			)
	)
(4)出現在exists後面(相關子查詢)

支援表子查詢

語法:exists(完整的查詢語句);

結果:0或1,0表示括號中的查詢結果中沒有記錄,1表示括號中的查詢結果至少有一條記錄

exists可以用in代替

# 是否有員工的工資等於30000
SELECT EXISTS(SELECT * FROM employees WHERE salary = 30000);

# 查詢有員工的部門的部門名
SELECT
	department_name
FROM
	departments d
WHERE
	EXISTS(
		SELECT 
			*
		FROM
			employees e
		WHERE
			d.department_id = e.department_id
	)
	
# 查詢有員工的部門的部門名,用in代替了exists
SELECT
	department_name
FROM
	departments d
WHERE
	d.department_id in (
		SELECT 
			department_id
		FROM
			employees e
	)
(5) 出現在DML語句(insert、update、delete)中(※)
# 複製資料
INSERT INTO	beauty(name, sex, borndate, phone, photo, boyfriend_id)
SELECT name, sex, borndate, phone, photo, boyfriend_id FROM beauty;

# 修改張三的女朋友的電話號碼為114
UPDATE 
	beauty b1 INNER JOIN boys b2 ON b1.boyfriend_id = b2.id 
SET b1.phone = '114' 
WHERE b2.boyName = '張三'

# 刪除張三女朋友的資訊
DELETE 
	b2
FROM 
	boys b1 INNER JOIN beauty b2 ON b1.id = b2.boyfriend_id
WHERE 
	b1.boyName = '張三'

# 刪除張三的資訊和張三女朋友的資訊
DELETE	
	b1, b2
FROM 
	boys b1 INNER JOIN beauty b2 ON b1.id = b2.boyfriend_id
WHERE 
	b1.boyName = '張三'

10、SQL語句的執行順序

select 查詢列表 ⑦

from 表 ①

連線型別 join 表 ②

on 連線條件 ③

where 篩選條件 ④

group by 分組列表 ⑤

having 分組後的篩選 ⑥

order by 排序列表 ⑧

limit 偏移, 條目數 ⑨

11、聯合查詢

作用:將多條查詢語句的結果合併成一個結果

語法:

查詢語句1
union
查詢語句2
union
...
查詢語句n

特點:

①要求所有的查詢語句的查詢結果列數一致

②要求所有的查詢語句的查詢結果的每一列的型別和順序最好是一致的

③union預設對聯合查詢之後的結果去重,如果不想對聯合查詢結果去重可以使用union all

應用場景:要查詢的結果來自於多個表,並且表之間沒有直接的連線關係,但是查詢語句的查詢結果一致

案例:

# 查詢學生姓名中包含a字元或郵箱中包含b字元的學生資訊
SELECT * FROM student WHERE name LIKE '%a%' 
UNION
SELECT * FROM student WHERE email LIKE '%b%'

12、truncate PK delete

①delete可以加where篩選條件,truncate不能加篩選條件,即truncate只能刪除全部的資料不能篩選

②truncate刪除效率高一些

③如果要刪除的表中有自增長列,用delete刪除後再插入資料,自增長列的值從斷點開始;用truncate刪除後再插入資料,自增長列的值從1開始

④delete刪除有返回值,truncate刪除沒有返回值

⑤delete刪除可以進行事務回滾,truncate刪除不能進行事務回滾

# 刪除admin表的所有資料
TRUNCATE TABLE admin

13、欄位型別

(1)整型
整數型別 位元組 範圍
Tinyint 1 有符號:-27~27-1 無符號:0~2^8-1
Smallint 2 有符號:-215~216-1 無符號:0~2^16-1
Mediumint 3 無符號:-223~223-1 無符號:0~2^24-1
Int/Integer 4 無符號:-231~231-1 無符號:0~2^32-1
Bigint 8 無符號:-263~263-1 無符號:0~2^64-1

特點:

  • 如果不設定無符號還是有符號,預設是有符號,如果想設定無符號,需要新增unsigned關鍵字
  • 如果插入的數值超出了整型的範圍,會報out of range異常,並且插入臨界值
  • 如果不設定長度,會有預設的長度。長度代表了顯示的最大寬度,如果不夠會用0在左邊填充,但必須搭配zerofill使用!
(2)小數
  • 分類:
    • 浮點型:float(M,D)、double(M,D)
    • 定點型:dec(M,D)、decimal(M,D)
  • 特點:
    • M:整數部位+小數部位,D:小數部位,如果超過範圍,則插入臨界值
    • M和D都可以省略,如果是decimal,則M預設為10,D預設為0;如果是float和double,則會根據插入的數值的精度來決定精度
    • 定點型的精確度較高,如果要求插入數值的精度較高如貨幣運算等則考慮使用
(3)字元型
  • 較短的文字:char、varchar

  • 其他:

    • binary和varbinary用於儲存較短的二進位制
    • enum用於儲存列舉
    • set用於儲存集合
  • 較長的文字:text、blob(較大的二進位制)

  • 特點:

    寫法 M的意思 特點 空間的耗費 效率
    char char(M) 最大的字元數,可以省略,預設為1 固定長度的字元 比較耗費 高
    varchar varchar(M) 最大的字元數,不可以省略 可變長度的字元 比較節省 低

    注意:M的意思是存放的最大字元數(一個字母是一個字元,一個漢字也是一個字元)

(4)日期型別
  • 分類:

    型別 資料
    date 只儲存日期
    time 只儲存時間
    year 只儲存年
    datetime 儲存日期+時間
    timestamp 儲存日期+時間的時間戳
  • 特點:

    型別 位元組 範圍 時區等的影響
    datetime 8 1000——9999 不受
    timestamp 4 1970-2038

14、約束

六大約束:主鍵約束(primary key)、外來鍵約束(foreign key)、非空約束(not null)、預設約束(default)、唯一約束(unique)、檢查約束(check)

約束型別:

  • 列級約束:可以加在欄位的欄位型別後面的約束,有主鍵約束、非空約束、預設約束、唯一約束

    DROP TABLE IF EXISTS `user`;
    CREATE TABLE IF NOT EXISTS `user`(
    	`id` INT PRIMARY KEY,
    	`username` VARCHAR(64) NOT NULL,
    	`gender` CHAR(1) DEFAULT '男' CHECK(`gender`='男' OR `gender`='女'), #mysql不支援檢查約束
    	`code_id` VARCHAR(32) UNIQUE
    );
    
  • 表級約束:可以加在表的最後面的約束,有主鍵約束、外來鍵約束、唯一約束

    DROP TABLE IF EXISTS `user`;
    CREATE TABLE IF NOT EXISTS `user`(
    	`id` INT,
    	`username` VARCHAR(64) NOT NULL,
    	`gender` CHAR(1) DEFAULT '男' CHECK(`gender`='男' OR `gender`='女'),
    	`code_id` VARCHAR(32),
    	`major_id` INT,
    	PRIMARY KEY (`id`),
    	UNIQUE (`code_id`),
    	FOREIGN KEY (`major_id`) REFERENCES major(`id`)
    );
    

注意:MySQL不支援檢查約束和列級外來鍵約束

特點:

  • 主鍵 PK 唯一鍵

    保證唯一性 是否允許為空 是否允許有多個 是否允許組合
    主鍵 可以 不允許 不允許 允許
    唯一鍵 可以 允許,但至多有一個為空 允許 允許

    注意:

    ①使用唯一約束的欄位,最多隻能有一條記錄的該欄位為null

    ②unique(欄位名1),unique(欄位名2)與unique(欄位名1, 欄位名2)是不一樣的,前面是定義了兩個唯一鍵,後面是定義了一個組合唯一鍵

15、事務

①事務的ACID屬性

原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、永續性(Durability)

②併發問題

  • 髒讀:(針對未提交的資料)一個事務在更新一條記錄,未提交前,第二個事務讀到了第一個事務更新後的記錄,那麼第二個事務就讀到了髒資料,會產生對第一個未提交資料的依賴。一旦第一個事務回滾,那麼第二個事務讀到的資料,將是錯誤的髒資料
  • 不可重複讀:(讀取資料本身的對比)一個事務在讀取某些資料後的一段時間後,再次讀取這個資料,發現其讀取出來的資料內容已經發生了改變
  • 幻讀:(讀取結果集條數的對比)一個事務按相同的查詢條件查詢之前檢索過的資料,確發現檢索出來的結果集條數變多或者減少(由其他事務插入、刪除的)

③事務的隔離級別

隔離級別 髒讀 不可重複讀 幻讀
READ UNCOMMITTED
READ COMMITTED ×
REPEATABLE READ × ×
SERIALIZABLE × × ×

注意:

  • Mysql預設的隔離級別是REPEATABLE READ,Oracle預設的隔離級別是READ COMMITTED,級別越高效率越低
  • Mysql使用的比較多的儲存引擎有innodb、myisam、memory等,其中innodb支援事務,myisam、memory不支援事務
  • 事務中支援insert、update、delete、select(查詢不需要事務),不支援create、drop、alter

④檢視和設定隔離級別的命令

# 檢視隔離級別
SELECT @@tx_isolation;

# 設定當前會話的隔離級別
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ(隔離級別);

# 設定全域性的隔離級別
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ(隔離級別);

⑤與事務有關的命令

# 關閉自動提交,同時開啟事務
SET autocommit=0;

# 開啟事務(可以省略)
START TRANSACTION;

# 提交事務
COMMIT;

# 事務回滾
ROLLBACK;

# 設定儲存點,只能搭配rollback使用
SAVEPOINT P1;

# 回滾到儲存點p1
ROLLBACK TO p1;