日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

SQL基本语句及用法

發布時間:2025/3/21 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SQL基本语句及用法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

一.基本SQL語句用法及概述

1.常用MySQL命令

2.語法規范

3.SQL語句分類

二.數據查詢語言

1.基礎查詢

1)查詢的字段列表可以是字段、常量、表達式、函數等

2)使用別名,字段名和別名之間可以用空格或關鍵字AS與as指定別名

3)去重??? distinct

4)使用concat函數進行字符串拼接

2.條件查詢

1)件運算符

2)邏輯運算符

3.模糊查詢

4.排序??? order by

三.數據查詢語言之函數應用

1.常用函數分類

1)按使用方式分為:

2)按用途分為

2.函數應用

1)字符函數實例:

2)日期和時間函數實例

3)分組函數

四.數據查詢語言之分組查詢

1.分組查詢的概述

五.數據查詢語言之連接查詢

1.連接查詢的概述

2.連接分類

3.SQL99標準多表查詢

1)內連接

2)等值連接

3)非等值連接 between

4)自連接

5)外連接的概述

6)左外連接

7)右外連接

8)交叉連接 cross join

六.數據查詢語言之子查詢

1.子查詢的概述

2.子查詢實例

1)單行單列

2)多行單列

3)單行多列

4)多行多列

5)分頁查詢

6)聯合查詢UNION

七.插入語句DDL

1.不指定列名的插入

2.指定列名的插入

3.使用set語句

4.修改語句

5.刪除記錄

6.刪除多表記錄

7.清空表

八.數據庫管理

1.創建數據庫

2.修改數據庫

3.刪除數據庫

九.表管理

1.關系數據庫的規范化

2.表管理語句

3.常用數據類型

4.示例:

1)修改表

2)修改列的類型或約束

3)添加新列

4)刪除列

5)修改表名

6)刪除表

7)表復制

8)復制表結構及數據

十.約束

1.約束分類

2.約束應用

1)列級應用

2)表級約束

3)刪除約束

十一.事務控制語言DCL

1.事務

2.事務必須滿足的4個條件

3.事務控制語句

4.MySQL事物處理的方法

5.事務的創建

1)隱式事務

7.事務示例

十二.事務隔離

1.事務隔離要解決的問題

2.事務隔離級別

3.設置事務隔離級別

1)查看當前事務隔離級別

2)設置隔離事務級別

3)測試

4.SAVEPOINT應用

1)基本用法

2)SAVEPOINT示例


一.基本SQL語句用法及概述

1.常用MySQL命令

# 查看所有數據庫 SHOW DATABASES; # 切換指定數據庫 USE nsd2021; # 查看當前庫中所有的表 SHOW TABLES; # 查看表結構 DESC departments; # 查看當前所處的數據庫 SELECT DATABASE(); # 查看當前登陸用戶 SELECT USER(); # 查看版本 SELECT VERSION(); [root@mysql1 ~]# mysql --version #不進庫查看 [root@mysql1 ~]# mysql -V

2.語法規范

關鍵字不區分大小寫,但建議關鍵字大寫

表名、列名建議小寫

每條命令最好用分號結尾,當然,你用`\G結尾也可以

每條命令根據需要,可以進行縮進或換行(最好是關鍵字單獨占一行),如:

mysql> SELECT-> name, email-> FROM-> employees;

注釋

????????單行注釋

mysql> # select * from departments mysql> -- select * from departments

????????多行注釋

mysql> /*/*> SELECT/*> */*> FROM/*> departments;/*> */

3.SQL語句分類

數據查詢語言(Data Query Language, )DQL

負責進行數據查詢而不會對數據本身進行修改的語句,這是最基本的SQL語句。

數據定義語言 (Data Definition Language,)DDL

負責數據結構定義與數據庫對象定義的語言,由CREATE、ALTER與DROP三個語法所組成

數據操縱語言(Data Manipulation Language,)DML

負責對數據庫對象運行數據訪問工作的指令集,以INSERT、UPDATE、DELETE三種指令為核心,分別代表插入、更新與刪除。

數據控制語言 (Data Control Language)

它可以控制特定用戶賬戶對數據表、查看表、預存程序、用戶自定義函數等數據庫對象的控制權。由 GRANT 和 REVOKE 兩個指令組成。

二.數據查詢語言

1.基礎查詢

SELECT 查詢的字段列表 FROM 表;

1)查詢的字段列表可以是字段、常量、表達式、函數等

# 查單個字段 select dept_name from departments; # 查多個字段 select name, email from employees; # 查所有字段 select * from departments; # 使用表達式 select date, employee_id, basic+bonus from salary; # 查詢常量 select 100; # 查詢表達式 select 10+5; # 查詢函數 select version(); # 查詢函數,統計salary共有多少行記錄 select count(*) from salary;

2)使用別名,字段名和別名之間可以用空格或關鍵字AS與as指定別名

mysql> select dept_id 部門編號, dept_name AS 部門名 from departments;

3)去重??? distinct

select dept_id from employees; select distinct dept_id from employees;

4)使用concat函數進行字符串拼接

select concat(name, '-', phone_number) from employees;

2.條件查詢

SELECT 查詢的字段列表 FROM 表 WHERE 條件;

1)件運算符

>: 大于

<: 小于

=: 等于

>=: 大于等于

<=: 小于等于

!=: 不等于

select * from departments where dept_id>3; select * from departments where dept_id<3; select * from departments where dept_id=3; select * from departments where dept_id!=3; select * from departments where dept_id>=3; select * from departments where dept_id<=3;

2)邏輯運算符

and(&&)、or(||)、not(!)

select * from departments where dept_id>1 and dept_id<5;
select * from departments where dept_id<3 or dept_id>6;
select * from departments where not dept_id<=6;

3.模糊查詢

- like: 包含
- between xxx and yyy :??????? 在xxx和yyy之間的
- in:在列表中的
- is null:為空,相當于python的None
- is not null:非空

%匹配0到多個任意字符

?_匹配一個字符

# %匹配0到多個任意字符 select name, email from employees where name like '張%'; # _匹配一個字符 select name, email from employees where name like '張_'; select * from departments where dept_id between 3 and 5; select * from departments where dept_id in (1, 3, 5, 8); # 匹配部門名為空的記錄 select * from departments where dept_name is null; # 查詢部門名不為空的記錄 select * from departments where dept_name is not null;

4.排序??? order by

SELECT 查詢的字段列表 FROM 表 ORDER BY 排序列表 [asc|desc];

排序:默認升序

select name, birth_date from employees where birth_date>'19980101'; # 默認升序排列 select name, birth_date from employees where birth_date>'19980101' order by birth_date; # 降序排列 select name, birth_date from employees where birth_date>'19980101' order by birth_date desc;

三.數據查詢語言之函數應用

1.常用函數分類

1)按使用方式分為:

  • 單行函數

  • 分組函數

2)按用途分為

  • 字符函數

  • 數學函數

  • 日期函數

  • 流程控制函數

SELECT 函數(參數) FROM 表;

2.函數應用

1)字符函數實例:

  • LENGTH(str):返字符串長度,以(字節)為單位

select length('abc'); select length('你好'); select name, email, length(email) from employees where name='李平';
  • CHAR_LENGTH(str): 返回字符串長度,以(字符)為單位

select char_length('abc'); select char_length('你好');
  • CONCAT(s1,s2,...): 返回連接參數產生的字符串,一個或多個待拼接的內容,任意一個為NULL則返回值為NULL

# 拼接字符串 mysql> select concat(dept_id, '-', dept_name) from departments;
  • UPPER(str)和UCASE(str): 將字符串中的字母全部轉換成大寫

select name, upper(email) from employees where name like '李%';
  • LOWER(str)和LCASE(str):將str中的字母全部轉換成小寫

# 轉小寫 select lower('HelloWorld');
  • SUBSTR(s, start, length): 從子符串s的start位置開始,取出length長度的子串,位置(從1)開始計算

select substr('hello world', 7); # 取子串,下標從7開始取出3個 select substr('hello world', 7, 3);
  • INSTR(str,str1):返回str1參數,在str參數內的位置

# 子串在字符串中的位置 select instr('hello world', 'or'); select instr('hello world', 'ol');
  • TRIM(s): 返回字符串(s刪除了兩邊空格之后的字符串)

select trim(' hello world. ');

數學函數實例

  • ABS(x):返回x的絕對值

select abs(-10);(負—>正)
  • PI(): 返回圓周率π,默認顯示6位小數

select pi();
  • MOD(x,y): 返回x被y除后的余數

select mod(10, 3);
  • CEIL(x)、CEILING(x): 返回不小于x的最小整數

select ceil(10.1);
  • FLOOR(x): 返回不大于x的最大整數

select floor(10.9);
  • ROUND(x)、ROUND(x,y): 前者返回最接近于x的整數,即對x進行四舍五入;后者返回最接近x的數,其值保留到小數點后面y位,若y為負值,則將保留到x到小數點左邊y位

select round(10.6666);返回最接近于x的整數,即對x進行四舍五入 select round(10.6666, 2);返回最接近x的數,其值保留到小數點后面y位

2)日期和時間函數實例

  • CURDATE()、CURRENT_DATE(): 將當前日期按照"YYYY-MM-DD"或者"YYYYMMDD"格式的值返回,具體格式根據函數用在字符串或是數字語境中而定

select curdate();當前日期按照"YYYY-MM-DD" select curdate() + 0;格式根據函數用在字符串或是數字語境中而定
  • NOW(): 返回當前日期和時間值,格式為"YYYY_MM-DD HH:MM:SS"或"YYYYMMDDHHMMSS",具體格式根據函數用在字符串或數字語境中而定

select now();式為"YYYY_MM-DD HH:MM:SS" select now() + 0;具體格式根據函數用在字符串或數字語境中而定
  • UNIX_TIMESTAMP()、UNIX_TIMESTAMP(date): 前者返回一個格林尼治標準時間1970-01-01 00:00:00到現在的秒數,后者返回一個格林尼治標準時間1970-01-01 00:00:00到指定時間的秒數

select unix_timestamp();
  • FROM_UNIXTIME(date): 和UNIX_TIMESTAMP互為反函數,把UNIX時間戳轉換為普通格式的時間

select from_unixtime(0);
  • MONTH(date)和MONTHNAME(date):前者返回指定日期中的月份,后者返回指定日期中的月份的名稱

select month('20211001120000');返回指定日期中的月份 select monthname('20211001120000');返回指定日期中的月份的名稱
  • DAYNAME(d)、DAYOFWEEK(d)、WEEKDAY(d): DAYNAME(d)返回d對應的工作日的英文名稱,如Sunday、Monday等;DAYOFWEEK(d)返回的對應一周中的索引,1表示周日、2表示周一;WEEKDAY(d)表示d對應的工作日索引,0表示周一,1表示周二

select dayname('20211001120000');返回星期* select dayname('20211001');
  • WEEK(d): 計算日期d是一年中的第幾周

select week('20211001');
  • DAYOFYEAR(d)、DAYOFMONTH(d): 前者返回d是一年中的第幾天,后者返回d是一月中的第幾天

select dayofyear('20211001');
  • YEAR(date)、QUARTER(date)、MINUTE(time)、SECOND(time): YEAR(date)返回指定日期對應的年份,范圍是1970到2069;QUARTER(date)返回date對應一年中的季度,范圍是1到4;MINUTE(time)返回time對應的分鐘數,范圍是0~59;SECOND(time)返回制定時間的秒值

select year('20211001');返回指定日期對應的年份 select quarter('20211001');回date對應一年中的季度

流程控制函數實例

  • IF(expr,v1,v2): 如果expr是TRUE則返回v1,否則返回v2

select if(3>0, 'yes', 'no'); select name, dept_id, if(dept_id=1, '人事部', '非人事部') from employees where name='張亮';
  • IFNULL(v1,v2): 如果v1不為NULL,則返回v1,否則返回v2

select dept_id, dept_name, ifnull(dept_name, '未設置') from departments; insert into departments(dept_id) values(9); select dept_id, dept_name, ifnull(dept_name, '未設置') from departments;
  • CASE expr (WHEN v1)( THEN r1) [WHEN v2 THEN v2] [ELSE rn] END: 如果expr等于某個vn,則返回對應位置THEN后面的結果,如果與所有值都不想等,則返回ELSE后面的rn

mysql> select dept_id, dept_name,-> case dept_nam-> when '運維部' then '技術部門'-> when '開發部' then '技術部門'-> when '測試部' then '技術部門'-> when null then '未設置'-> else '非技術部門'-> end as '部門類型'-> from departments; # 查看字段,名字。匹配 名字是 當是v1就是r1 ,是v2 就是v2,否則就返回對應位置THEN后面的結果,如果與所有值都不想等,則返回ELSE后面的值 select dept_id, dept_name,-> case -> when dept_name='運維部' then '技術部門'-> when dept_name='開發部' then '技術部門'-> when dept_name='測試部' then '技術部門'-> when dept_name is null then '未設置'-> else '非技術部門'-> end as '部門類型'-> from departments;

3)分組函數

用于統計,又稱為聚合函數或統計函數

  • sum() :求和

select employee_id, sum(basic+bonus) from salary where employee_id=10 and year(date)=2018;
  • avg() :求平均值

select employee_id, avg(basic+bonus) from salary where employee_id=10 and year(date)=2018;
  • max() :求最大值

select employee_id, max(basic+bonus) from salary where employee_id=10 and year(date)=2018;
  • min() :求最小值

select employee_id, min(basic+bonus) from salary where employee_id=10 and year(date)=2018;
  • count() :計算個數

select count(*) from departments;

四.數據查詢語言之分組查詢

1.分組查詢的概述

  • 在對數據表中數據進行統計時,可能需要按照一定的類別分別進行統計。比如查詢每個部門的員工數。

  • 使用GROUP BY按某個字段,或者多個字段中的值,進行分組,字段中值相同的為一組

語法格式

  • 查詢列表必須是分組函數和出現在(GROUP BY)后面的字段

  • 通常而言,分組前的數據篩選放在where子句中,分組后的數據篩選放在having子句中

SELECT 字段名1(要求出現在group by后面),分組函數(),…… FROM 表名 WHERE 條件 GROUP BY 字段名1,字段名2 HAVING 過濾條件 ORDER BY 字段;

應用實例

  • 查詢每個部門的人數

select dept_id, count(*) from employees group by dept_id;
  • 查詢每個部門中年齡最大的員工

select dept_id, min(birth_date) from employees group by dept_id;
  • 查詢每個部門入職最晚員工的入職時間

select dept_id, max(hire_date) from employees group by dept_id;
  • 統計各部門使用tedu.cn郵箱的員工人數

mysql> select dept_id, count(*) from employees where email like '%@tedu.cn' group by dept_id; +---------+----------+ | dept_id | count(*) | +---------+----------+ | 1 | 5 | | 2 | 2 | | 3 | 4 | | 4 | 32 | | 5 | 7 | | 6 | 5 | | 7 | 15 | | 8 | 1 | +---------+----------+ 8 rows in set (0.00 sec)
  • 查看員工2018年工資總收入,按總收入進行降序排列

mysql> select employee_id, sum(basic+bonus) as total from salary where year(date)=2018 group by employee_id order by total desc;
  • 查詢部門人數少于10人

mysql> select dept_id, count(*) from employees where count(*)<10 group by dept_id; ERROR 1111 (HY000): Invalid use of group functionmysql> select dept_id, count(*) from employees group by dept_id having count(*)<10; +---------+----------+ | dept_id | count(*) | +---------+----------+ | 1 | 8 | | 2 | 5 | | 3 | 6 | | 6 | 9 | | 8 | 3 | +---------+----------+ 5 rows in set (0.00 sec)

五.數據查詢語言之連接查詢

1.連接查詢的概述

  • 也叫多表查詢。常用于查詢字段來自于多張表

  • 如果直接查詢兩張表,將會得到笛卡爾積

select name, dept_name from employees, departments;
  • 通過添加有效的條件可以進行查詢結果的限定

select name, dept_name from employees, departments where employees.dept_id=departments.dept_id;

2.連接分類

按功能分類

  • 內連接(重要)

    • 等值連接

    • 非等值連接

    • 自連接

  • 外連接

    • 左外連接(重要)

    • 右外連接(重要)

    • 全外連接(mysql不支持,可以使用UNION實現相同的效果)

  • 交叉連接

按年代分類

  • SQL92標準:僅支持內連接

  • SQL99標準:支持所有功能的連接

3.SQL99標準多表查詢

  • 語法格式

SELECT 字段... FROM 表1 [AS] 別名 [連接類型] JOIN 表2 [AS] 別名 ON 連接條件 WHERE 分組前篩選條件 GROUP BY 分組 HAVING 分組后篩選條件 ORDER BY 排序字段

1)內連接

  • 語法格式

select 查詢列表 from 表1 別名 inner join 表2 別名 on 連接條件 inner join 表3 別名 on 連接條件 [where 篩選條件] [group by 分組] [having 分組后篩選] [order by 排序列表]

2)等值連接

  • 查詢每個員工所在的部門名

select name, dept_name-> from employees-> inner join departments-> on employees.dept_id=departments.dept_id;
  • 查詢每個員工所在的部門名,使用別名

select name, dept_name-> from employees as e-> inner join departments as d-> on e.dept_id=d.dept_id;
  • 查詢每個員工所在的部門名,使用別名。兩個表中的同名字段,必須指定表名

select name, d.dept_id, dept_name-> from employees as e-> inner join departments as d-> on e.dept_id=d.dept_id;
  • 查詢11號員工的名字及2018年每個月工資

select name, date, basic+bonus as total-> from employees as e-> inner join salary as s-> on e.employee_id=s.employee_id-> where year(s.date)=2018 and e.employee_id=11;
  • 查詢2018年每個員工的總工資

select name, sum(basic+bonus) from employees-> inner join salary-> on employees.employee_id=salary.employee_id-> where year(salary.date)=2018-> group by name;
  • 查詢2018年每個員工的總工資,按工資升序排列

select name, sum(basic+bonus) as total from employees as e-> inner join salary as s-> on e.employee_id=s.employee_id-> where year(s.date)=2018-> group by name-> order by total;
  • 查詢2018年總工資大于30萬的員工,按工資降序排列

select name, sum(basic+bonus) as total from employees as e-> inner join salary as s-> on e.employee_id=s.employee_id-> where year(s.date)=2018-> group by name-> having total>300000-> order by total desc;

3)非等值連接 between

附:創建工資級別表

創建表語法:

CREATE TABLE 表名稱 ( 列名稱1 數據類型, 列名稱2 數據類型, 列名稱3 數據類型, .... )

創建工資級別表:

  • id:主鍵。僅作為表的行號

  • grade:工資級別,共ABCDE五類

  • low:該級別最低工資

  • high:該級別最高工資

mysql> use nsd2021; mysql> create table wage_grade-> (-> id int,-> grade char(1),-> low int,-> high int,-> primary key (id));

向表中插入數據:

  • 語法:

INSERT INTO 表名稱 VALUES (值1, 值2,....);
  • 向wage_grade表中插入五行數據:

mysql> insert into wage_grade values-> (1, 'A', 5000, 8000),-> (2, 'B', 8001, 10000),-> (3, 'C', 10001, 15000),-> (4, 'D', 15001, 20000),-> (5, 'E', 20001, 1000000);
  • 查詢2018年12月員工基本工資級別

select employee_id, date, basic, grade-> from salary as s-> inner join wage_grade as g-> on s.basic between g.low and g.high-> where year(date)=2018 and month(date)=12;
  • 查詢2018年12月員工各基本工資級別的人數

select grade, count(*)-> from salary as s-> inner join wage_grade as g-> on s.basic between g.low and g.high-> where year(date)=2018 and month(date)=12-> group by grade;
  • 查詢2018年12月員工基本工資級別,員工需要顯示姓名

select name, date, basic, grade-> from salary as s-> inner join employees as e-> on s.employee_id=e.employee_id-> inner join wage_grade-> on basic between low and high-> where date='20181210'-> order by grade, basic;

4)自連接

  • 要點:

    • 將一張表作為兩張使用

    • 每張表起一個別名

  • 查看哪些員的生日月份與入職月份相同

select e.name, e.hire_date, em.birth_date-> from employees as e-> inner join employees as em-> on month(e.hire_date)=month(em.birth_date)-> and e.employee_id=em.employee_id;

5)外連接的概述

  • 常用于查詢一個表中有,另一個表中沒有的記錄

  • 如果從表中有和它匹配的,則顯示匹配的值

  • 如要從表中沒有和它匹配的,則顯示NULL

  • 外連接查詢結果=內連接查詢結果+主表中有而從表中沒有的記錄

  • 左外連接中,left join左邊的是主表left outer join

  • 右外連接中,right join右邊的是主表right outer join

  • 左外連接和右外連接可互換,實現相同的目標

6)左外連接

  • 語法

SELECT tb1.字段..., tb2.字段 FROM table1 AS tb1 LEFT OUTER JOIN table2 AS tb2 ON tb1.字段=tb2.字段
  • 查詢所有部門的人員以及沒有員工的部門

select d.*, e.name-> from departments as d-> left outer join employees as e-> on d.dept_id=e.dept_id;

7)右外連接

  • 語法

SELECT tb1.字段..., tb2.字段 FROM table1 AS tb1 RIGHT OUTER JOIN table2 AS tb2 ON tb1.字段=tb2.字段
  • 查詢所有部門的人員以及沒有員工的部門

select d.*, e.name-> from employees as e-> right outer join departments as d-> on d.dept_id=e.dept_id;

8)交叉連接 cross join

  • 返回笛卡爾積

  • 語法:

SELECT <字段名> FROM <表1> CROSS JOIN <表2> [WHERE子句]
  • 查詢員工表和部門表的笛卡爾積

select name, dept_name-> from employees-> cross join departments;

附:授予管理員root可以通過任意地址訪問數據庫,密碼是NSD2021@tedu.cn。默認情況下,root只允許在本機訪問

grant all on *.* to root@'%' identified by 'NSD2021@tedu.cn';

向部門表中插入數據:

insert into departments(dept_name) values('采購部');


六.數據查詢語言之子查詢

1.子查詢的概述

子查詢就是指的在一個完整的查詢語句之中,嵌套若干個不同功能的小查詢,從而一起完成復雜查詢的一種編寫形式

子查詢返回的數據分類
????????單行單列:返回的是一個具體列的內容,可以理解為一個單值數據

????????單行多列:返回一行數據中多個列的內容

????????多行單列:返回多行記錄之中同一列的內容,相當于給出了一個操作范圍

????????多行多列:查詢返回的結果是一張臨時表

子查詢常出現的位置
????????select之后:僅支持單行單列????????

????????from之后:支持多行多列

????????where或having之后:支持單行單列、單行多列、多行單列

2.子查詢實例

1)單行單列

查詢運維部所有員工信息

分析:
????????首先從departments表中查出運維部的編號

mysql> select dept_id from departments where dept_name='運維部'; +---------+ | dept_id | +---------+ | 3 | +---------+ 1 row in set (0.00 sec) 再從employees表中查找該部門編號和運維部編號相同的員工 mysql> select *-> from employees-> where dept_id=(-> select dept_id from departments where dept_name='運維部'-> );

查詢2018年12月所有比100號員工基本工資高的工資信息

分析:

首先查到2018年12月100號員工的基本工資

mysql> select basic from salary-> where year(date)=2018 and month(date)=12 and employee_id=100; +-------+ | basic | +-------+ | 14585 | +-------+ 1 row in set (0.00 sec) 再查詢2018年12月所有比100號員工基本工資高的工資信息mysql> select * from salary-> where year(date)=2018 and month(date)=12 and basic>(-> select basic from salary-> where year(date)=2018 and month(date)=12 and employee_id=100-> );

查詢部門員工人數比開發部人數少的部門

分析:

查詢開發部部門編號

mysql> select dept_id from departments where dept_name='開發部'; +---------+ | dept_id | +---------+ | 4 | +---------+ 1 row in set (0.00 sec) 查詢開發部人數mysql> select count(*) from employees-> where dept_id=(-> select dept_id from departments where dept_name='開發部'-> ); +----------+ | count(*) | +----------+ | 55 | +----------+ 1 row in set (0.00 sec)

分組查詢各部門人數

mysql> select count(*), dept_id from employees group by dept_id; +----------+---------+ | count(*) | dept_id | +----------+---------+ | 8 | 1 | | 5 | 2 | | 6 | 3 | | 55 | 4 | | 12 | 5 | | 9 | 6 | | 35 | 7 | | 3 | 8 | +----------+---------+ 8 rows in set (0.01 sec)

?查詢部門員工人數比開發部人數少的部門

mysql> select count(*), dept_id from employees group by dept_id-> having count(*)<(-> select count(*) from employees-> where dept_id=(-> select dept_id from departments where dept_name='開發部'-> )-> ); +----------+---------+ | count(*) | dept_id | +----------+---------+ | 8 | 1 | | 5 | 2 | | 6 | 3 | | 12 | 5 | | 9 | 6 | | 35 | 7 | | 3 | 8 | +----------+---------+ 7 rows in set (0.00 sec)

查詢每個部門的人數

分析:

查詢所有部門的信息

mysql> select d.* from departments as d; +---------+-----------+ | dept_id | dept_name | +---------+-----------+ | 1 | 人事部 | | 2 | 財務部 | | 3 | 運維部 | | 4 | 開發部 | | 5 | 測試部 | | 6 | 市場部 | | 7 | 銷售部 | | 8 | 法務部 | | 9 | NULL | +---------+-----------+ 9 rows in set (0.00 sec)

查詢每個部門的人數

mysql> select d.*, (-> select count(*) from employees as e-> where d.dept_id=e.dept_id-> ) as amount-> from departments as d; +---------+-----------+--------+ | dept_id | dept_name | amount | +---------+-----------+--------+ | 1 | 人事部 | 8 | | 2 | 財務部 | 5 | | 3 | 運維部 | 6 | | 4 | 開發部 | 55 | | 5 | 測試部 | 12 | | 6 | 市場部 | 9 | | 7 | 銷售部 | 35 | | 8 | 法務部 | 3 | | 9 | NULL | 0 | +---------+-----------+--------+ 9 rows in set (0.00 sec)

2)多行單列


查詢人事部和財務部員工信息

分析:

查詢人事部和財務部編號

mysql> select dept_id from departments-> where dept_name in ('人事部', '財務部'); +---------+ | dept_id | +---------+ | 1 | | 2 | +---------+ 2 rows in set (0.00 sec) 查詢部門編號是兩個部門編號的員工信息mysql> select * from employees-> where dept_id in (-> select dept_id from departments-> where dept_name in ('人事部', '財務部')-> );

查詢人事部2018年12月所有員工工資

分析:

查詢人事部部門編號

mysql> select dept_id from departments where dept_name='人事部'; +---------+ | dept_id | +---------+ | 1 | +---------+ 1 row in set (0.00 sec) 查詢人事部員的編號mysql> select employee_id from employees-> where dept_id=(-> select dept_id from departments where dept_name='人事部'-> ); +-------------+ | employee_id | +-------------+ | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 | +-------------+ 8 rows in set (0.00 sec)

查詢2018年12月人事部所有員工工資

mysql> select * from salary-> where year(date)=2018 and month(date)=12 and employee_id in (-> select employee_id from employees-> where dept_id=(-> select dept_id from departments where dept_name='人事部'-> )-> ); +------+------------+-------------+-------+-------+ | id | date | employee_id | basic | bonus | +------+------------+-------------+-------+-------+ | 6252 | 2018-12-10 | 1 | 17016 | 7000 | | 6253 | 2018-12-10 | 2 | 20662 | 9000 | | 6254 | 2018-12-10 | 3 | 9724 | 8000 | | 6255 | 2018-12-10 | 4 | 17016 | 2000 | | 6256 | 2018-12-10 | 5 | 17016 | 3000 | | 6257 | 2018-12-10 | 6 | 17016 | 1000 | | 6258 | 2018-12-10 | 7 | 23093 | 4000 | | 6259 | 2018-12-10 | 8 | 23093 | 2000 | +------+------------+-------------+-------+-------+ 8 rows in set (0.00 sec)

3)單行多列

查找2018年12月基本工資和獎金都是最高的工資信息

分析:

查詢2018年12月最高的基本工資

mysql> select max(basic) from salary-> where year(date)=2018 and month(date)=12; +------------+ | max(basic) | +------------+ | 25524 | +------------+ 1 row in set (0.00 sec) 查詢2018年12月最高的獎金mysql> select max(bonus) from salary-> where year(date)=2018 and month(date)=12; +------------+ | max(bonus) | +------------+ | 11000 | +------------+ 1 row in set (0.00 sec) 查詢mysql> select * from salary-> where year(date)=2018 and month(date)=12 and basic=(-> select max(basic) from salary-> where year(date)=2018 and month(date)=12-> ) and bonus=(-> select max(bonus) from salary-> where year(date)=2018 and month(date)=12-> ); +------+------------+-------------+-------+-------+ | id | date | employee_id | basic | bonus | +------+------------+-------------+-------+-------+ | 6368 | 2018-12-10 | 117 | 25524 | 11000 | +------+------------+-------------+-------+-------+ 1 row in set (0.01 sec)

4)多行多列

查詢3號部門及其部門內員工的編號、名字和email

分析

查詢3號部門和員工的所有信息

mysql> select d.dept_name, e.*-> from departments as d-> inner join employees as e-> on d.dept_id=e.dept_id; 將上述結果當成一張臨時表,必須為其起別名。再從該臨時表中查詢mysql> select dept_id, dept_name, employee_id, name, email-> from (-> select d.dept_name, e.*-> from departments as d-> inner join employees as e-> on d.dept_id=e.dept_id-> ) as tmp_table-> where dept_id=3; +---------+-----------+-------------+-----------+--------------------+ | dept_id | dept_name | employee_id | name | email | +---------+-----------+-------------+-----------+--------------------+ | 3 | 運維部 | 14 | 廖娜 | liaona@tarena.com | | 3 | 運維部 | 15 | 竇紅梅 | douhongmei@tedu.cn | | 3 | 運維部 | 16 | 聶想 | niexiang@tedu.cn | | 3 | 運維部 | 17 | 陳陽 | chenyang@tedu.cn | | 3 | 運維部 | 18 | 戴璐 | dailu@tedu.cn | | 3 | 運維部 | 19 | 陳斌 | chenbin@tarena.com | +---------+-----------+-------------+-----------+--------------------+ 6 rows in set (0.00 sec)

5)分頁查詢

使用SELECT查詢時,如果結果集數據量很大,比如幾萬行數據,放在一個頁面顯示的話數據量太大,不如分頁顯示,每次顯示100條

要實現分頁功能,實際上就是從結果集中顯示第1至100條記錄作為第1頁,顯示第101至200條記錄作為第2頁,以此類推

分頁實際上就是從結果集中“截取”出從M開始,偏移到N的記錄。這個查詢可以通過LIMIT <M>, <N>子句實現

起始索引從0開始

每頁顯示內容速算:LIMIT (PAGE-1)*SIZE, SIZE

示例:

# 按employee_id排序,取出前5位員姓名
?

mysql> select employee_id, name from employees-> order by employee_id-> limit 0, 5; +-------------+-----------+ | employee_id | name | +-------------+-----------+ | 1 | 梁偉 | | 2 | 郭巖 | | 3 | 李玉英 | | 4 | 張健 | | 5 | 鄭靜 | +-------------+-----------+ 5 rows in set (0.00 sec)


# 按employee_id排序,取出前15至20號員姓名

mysql> select employee_id, name from employees-> order by employee_id-> limit 15, 5; +-------------+--------+ | employee_id | name | +-------------+--------+ | 16 | 聶想 | | 17 | 陳陽 | | 18 | 戴璐 | | 19 | 陳斌 | | 20 | 蔣紅 | +-------------+--------+ 5 rows in set (0.00 sec)

6)聯合查詢UNION

作用:將多條select語句的結果,合并到一起,稱之為聯合操作。

語法:( ) UNION ( )

要求查詢時,多個select語句的檢索到的字段數量必須一致

每一條記錄的各字段類型和順序最好是一致的

UNION關鍵字默認去重,可以使用UNION ALL包含重復項

mysql> (select 'yes') union (select 'yes'); +-----+ | yes | +-----+ | yes | +-----+ 1 row in set (0.00 sec)mysql> (select 'yes') union all (select 'yes'); +-----+ | yes | +-----+ | yes | | yes | +-----+ 2 rows in set (0.00 sec)


例,某生產商有一張原材料表和一張商品表,需要把原材料價格和商品價格一起輸出

查詢1972年前或2000年后出生的員工

# 普通方法
?

mysql> select name, birth_date from employees-> where year(birth_date)<1972 or year(birth_date)>2000; +-----------+------------+ | name | birth_date | +-----------+------------+ | 梁偉 | 1971-08-19 | | 張建平 | 1971-11-02 | | 竇紅梅 | 1971-09-09 | | 溫蘭英 | 1971-08-14 | | 朱文 | 1971-08-15 | | 和林 | 1971-12-10 | +-----------+------------+ 6 rows in set (0.01 sec)

# 聯合查詢的方法
?

mysql> (-> select name, birth_date from employees-> where year(birth_date)<1972-> )-> union-> (-> select name, birth_date from employees-> where year(birth_date)>=2000-> ); +-----------+------------+ | name | birth_date | +-----------+------------+ | 梁偉 | 1971-08-19 | | 張建平 | 1971-11-02 | | 竇紅梅 | 1971-09-09 | | 溫蘭英 | 1971-08-14 | | 朱文 | 1971-08-15 | | 和林 | 1971-12-10 | +-----------+------------+ 6 rows in set (0.00 sec)

七.插入語句DDL

1.不指定列名的插入

語法格式:

????????INSERT INTO 表名稱 VALUES (值1, 值2,....)
需要為所有列指定值

值的順序必須與表中列的順序一致

示例:# 如果表中已有1號部門,則出錯。因為dept_id是主鍵,不允許重復

mysql> insert into departments values(1, '行政部'); ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'# mysql> insert into departments values(10, '行政部'); Query OK, 1 row affected (0.01 sec)

?支持多行插入

mysql> insert into employees values-> (134, '張三', '2019-5-10', '2000-10-12', 'zhangsan@tedu.cn', '15088772354', 9),-> (135, '李四', '2020-8-20', '1999-6-23', 'lisi@tedu.cn', '13323458734', 9); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0

2.指定列名的插入

語法格式:

INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
列和值的順序要一致

列名先后順序不重要

示例 :

mysql> insert into departments (dept_name, dept_id) values ('售后部', 11); Query OK, 1 row affected (0.00 sec) 主鍵由于是自動增長的,也可以不指定主鍵的值mysql> insert into departments (dept_name) values ('咨詢部'); Query OK, 1 row affected (0.00 sec)


支持子查詢

mysql> insert into employees-> (name, hire_date, birth_date, email, phone_number, dept_id)-> (-> select name, hire_date, birth_date, email, phone_number, dept_id-> from employees-> where name='張三'-> ); Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0

3.使用set語句

語法格式:

INSERT INTO 表名 SET 列名1=列值1, 列名2=列值2, ...
示例:

mysql> insert into departments set dept_name='采購部'; Query OK, 1 row affected (0.00 sec)

4.修改語句

修改單表記錄
語法:

UPDATE 表名稱 SET 列名稱=新值, 列名稱=新值, ... WHERE 篩選條件
示例:

# 修改人事部的名稱為人力資源部

mysql> update departments set dept_name='人力資源部'-> where dept_name='人事部'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0

修改多表記錄
語法:

UPDATE 表1 AS 表1別名 INNER | LEFT | RIGHT JOIN 表2 AS 表2別名 ON 連接條件 SET 列=值, 列=值, ... WHERE 連接條件


示例:

# 修改李四所在部門為企劃部

mysql> update departments as d-> inner join employees as e-> on d.dept_id=e.dept_id-> set d.dept_name='企劃部'-> where e.name='李四';

5.刪除記錄

刪除單表記錄
語法:

DELETE FROM 表名 WHERE 篩選條件;

刪除的是滿足條件的整行記錄,而不是某個字段

示例:

# 刪除重復的員工張三,只保留一個張三的信息
# 查詢張三信息

mysql> select * from employees where name='張三';

# 根據員工編號刪除重復的張三

mysql> delete from employees where employee_id=136; Query OK, 1 row affected (0.00 sec)

6.刪除多表記錄

語法:

DELETE 表1別名, 表2別名 FROM 表1 AS 表1別名 INNER | LEFT | RIGHT JOIN 表2 AS 表2別名 ON 連接條件 WHERE 篩選條件

示例:

# 刪除9號部門中所有的員工

mysql> delete e-> from employees as e-> inner join departments as d-> on e.dept_id=d.dept_id-> where d.dept_id=9; Query OK, 2 rows affected (0.00 sec)

7.清空表

語法:

TRUNCATE TABLE 表名 TRUNCATE不支持WHERE條件

自增長列,TRUNCATE后從1開始;DELETE繼續編號

TRUNCATE不能回滾,DELETE可以

效率略高于DELETE

示例:

# 清空wage_grade表 mysql> truncate table wage_grade; Query OK, 0 rows affected (0.01 sec)

八.數據庫管理

1.創建數據庫

  • 語法:

CREATE DATABASE [IF NOT EXISTS] <數據庫名> [[DEFAULT] CHARACTER SET <字符集名>] [[DEFAULT] COLLATE <校對規則名>];
  • [ ]中的內容是可選的

  • <數據庫名>:創建數據庫的名稱。MySQL 的數據存儲區將以目錄方式表示 MySQL 數據庫,因此數據庫名稱必須符合操作系統的文件夾命名規則,不能以數字開頭,盡量要有實際意義。

  • IF NOT EXISTS:在創建數據庫之前進行判斷,只有該數據庫目前尚不存在時才能執行操作。此選項可以用來避免數據庫已經存在而重復創建的錯誤。

  • [DEFAULT] CHARACTER SET:指定數據庫的字符集。指定字符集的目的是為了避免在數據庫中存儲的數據出現亂碼的情況。如果在創建數據庫時不指定字符集,那么就使用系統的默認字符集。

  • [DEFAULT] COLLATE:指定字符集的默認校對規則。

  • MySQL 的字符集(CHARACTER)和校對規則(COLLATION)是兩個不同的概念。字符集是用來定義 MySQL 存儲字符串的方式,校對規則定義了比較字符串的方式。

2.修改數據庫

  • 語法:

ALTER DATABASE [數據庫名] { [ DEFAULT ] CHARACTER SET <字符集名> | [ DEFAULT ] COLLATE <校對規則名>}
  • ALTER DATABASE 用于更改數據庫的全局特性。

  • 使用 ALTER DATABASE 需要獲得數據庫 ALTER 權限。

  • 數據庫名稱可以忽略,此時語句對應于默認數據庫。

  • CHARACTER SET 子句用于更改默認的數據庫字符集。

3.刪除數據庫

  • 語法:

DROP DATABASE [ IF EXISTS ] <數據庫名>
  • <數據庫名>:指定要刪除的數據庫名。

  • IF EXISTS:用于防止當數據庫不存在時發生錯誤。

  • DROP DATABASE:刪除數據庫中的所有表格并同時刪除數據庫。

  • 如果要使用 DROP DATABASE,需要獲得數據庫 DROP 權限。

九.表管理

1.關系數據庫的規范化

良好的數據庫設計表現在以下幾方面:

  • 訪問效率高

  • 減少數據冗余,節省存儲空間,便于進一步擴展

  • 可以使應用程序的開發變得更容易

關系數據庫的規范化理論為:關系數據庫中的每一個關系都要滿足一定的規范。根據滿足規范的條件不同,可以分為6個等級:第一范式(1NF)、第二范式(2NF)……第五范式(5NF)。其中,NF是Normal Form的縮寫。一般情況下,只要把數據規范到第三范式標準就可以滿足需要了。

第一范式(1NF)

  • 在一個關系中,消除重復字段,且各字段都是最小的邏輯存儲單位。即,要滿足原子性。

  • 第一范式是第二和第三范式的基礎,是最基本的范式。第一范式包括下列指導原則。 (1)數據組的每個屬性只可以包含一個值。 (2)關系中的每個數組必須包含相同數量的值。 (3)關系中的每個數組一定不能相同。

  • 在任何一個關系數據庫中,第一范式是對關系模式的基本要求,不滿足第一范式的數據庫就不是關系型數據庫。

第二范式(2NF)

  • 第二范式是在第一范式的基礎上建立起來的,即滿足第二范式必先滿足第一范式(1NF)。

  • 第二范式要求數據庫表中的每個實體(即各個記錄行)必須可以被唯一地區分。

  • 為實現區分各行記錄通常需要為表設置一個“區分列”,用以存儲各個實體的唯一標識。這個唯一屬性列被稱為主關鍵字或主鍵。

  • 第二范式要求實體的屬性完完全依賴于主關鍵字,即不能存在僅依賴主關鍵字一部分的屬性,如果存在,那么這個屬性和主關鍵字的這一部分應該分離出來形成一個新的實體,新實體與原實體之間是一對多的關系。

第三范式(3NF)

  • 第三范式是在第二范式的基礎上建立起來的,即滿足第三范式必先滿足第二范式。

  • 第三范式要求關系表不存在非關鍵字列對任意候選關鍵字列的傳遞函數依賴,也就是說,第三范式要求一個關系表中不包含已在其他表中包含的非主關鍵字信息。

  • 除主鍵外,其他字段必須依賴主鍵。

2.表管理語句

創建表

  • 語法:

CREATE TABLE 表名稱 ( 列名稱1 數據類型 [(長度) 約束], 列名稱2 數據類型 [(長度) 約束], 列名稱3 數據類型 [(長度) 約束], .... )

3.常用數據類型

數據類型描述
tinyint(m)1個字節 范圍(-128~127)
smallint(m)2個字節 范圍(-32768~32767)
mediumint(m)3個字節 范圍(-8388608~8388607)
int(m)4個字節 范圍(-2147483648~2147483647)
bigint(m)8個字節 范圍(+-9.22*10的18次方)
float(m,d)單精度浮點型 8位精度(4字節) m總個數,d小數位
double(m,d)雙精度浮點型 16位精度(8字節) m總個數,d小數位
decimal(m,d)m表示十進制數字總的個數,d表示小數點后面數字的位數。常用于貨幣
char(n)固定長度,最多255個字符
varchar(n)不固定長度,最多65535個字符
tinytext可變長度,最多255個字符
text可變長度,最多65535個字符
mediumtext可變長度,最多2的24次方-1個字符
longtext可變長度,最多2的32次方-1個字符
date日期 '2008-12-2'
time時間 '12:25:36'
datetime日期時間 '2008-12-2 22:06:44'
timestamp自動存儲記錄修改時間
enum(選項1, 選項2, ...)單選字符串數據類型,適合存儲表單界面中的“單選值”
set(選項1,選項2, ...)多選字符串數據類型,適合存儲表單界面的“多選值”。

4.示例:

# 創建數據庫mydb mysql> create database mydb default charset utf8mb4; Query OK, 1 row affected (0.00 sec) ? mysql> use mydb; Database changed # 創建部門表 mysql> create table departments (-> id int,-> dept_name varchar(20)-> ); Query OK, 0 rows affected (0.01 sec)

1)修改表

修改列名

  • 語法:

ALTER TABLE 表 CHANGE [COLUMN] 列表 數據類型
  • 示例:

mysql> alter table departments-> change id dept_id int; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0

2)修改列的類型或約束

  • 語法:

ALTER TABLE 表 MODIFY [COLUMN] 列名 類型
  • 示例:

mysql> alter table departments-> modify dept_name varchar(10); Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0

3)添加新列

  • 語法:

ALTER TABLE 表 ADD [COLUMN] 列名 類型
  • 示例:

mysql> alter table departments-> add manager_id int; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0

4)刪除列

  • 語法:

ALTER TABLE 表 DROP [COLUMN] 列名
  • 示例:

mysql> alter table departments-> drop manager_id; Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0

5)修改表名

  • 語法:

ALTER TABLE 表名 RENAME TO 新表名
  • 示例:

mysql> alter table departments-> rename to depts; Query OK, 0 rows affected (0.00 sec)

6)刪除表

  • 語法:

DROP TABLE [IF EXISTS] 表名
  • 示例:

mysql> drop table depts; Query OK, 0 rows affected (0.01 sec)

7)表復制

僅復制表結構

  • 語法:

CREATE TABLE 待創建的表名 LIKE 已有表名
  • 示例:

mysql> create table departments like nsd2021.departments; Query OK, 0 rows affected (0.01 sec)

8)復制表結構及數據

  • 語法:

CREATE TABLE 待創建的表名 SELECT 字段, ... FROM 已有表名
  • 示例:

mysql> create table departments2-> select * from nsd2021.departments; Query OK, 13 rows affected (0.01 sec) Records: 13 Duplicates: 0 Warnings: 0

十.約束

  • 約束是一種限制,用于限制表中的數據,為了保證表中數據的準確性和可靠性。

  • 創建表時可以添加約束

  • 修改表時可以添加約束

1.約束分類

  • PRIMARY KEY:主鍵,用于保證該字段的值具有唯一性并且非空。

  • NOT NULL :非空,用于保證該字段的值不能為空。

  • DEFAULT:默認值,用于保證該字段有默認值。

  • UNIQUE:唯一,用于保證該字段的值具有唯一性,可以為空。

  • FOREIGN KEY:外鍵,用于限制兩個表的關系,用于保證該字段的值必須來自于主表的關聯列的值,在從表添加外鍵約束,用于引用主表中某些的值。

約束可應用在列級或表級。列表所有約束均支持,但外鍵約束沒有效果;表級約束可以支持主鍵、唯一、外鍵約束。

2.約束應用

1)列級應用

  • 創建表時使用約束

mysql> create table employees(-> employee_id int primary key auto_increment, -- 主鍵約束-> name varchar(20) not null, -- 非空約束-> gender enum('男', '女'),-> email varchar(20) unique, -- 唯一約束-> nation varchar(10) default '漢族' -- 默認值約束-> ); Query OK, 0 rows affected (0.00 sec)

2)表級約束

  • 創建表時使用約束

mysql> create table employees2 (-> employee_id int auto_increment,-> name varchar(20),-> email varchar(20),-> dept_id int,-> primary key (employee_id), -- 主鍵-> unique (email), -- 唯一-> foreign key (dept_id) references departments(dept_id) -- 外鍵-> ); # 查看約束 mysql> select * from information_schema.table_constraints where table_name='employees2' \G
  • 自定義約束名稱

mysql> create table employees3 (-> employee_id int,-> name varchar(20),-> dept_id int,-> constraint pk primary key(employee_id), # 不報錯,不生效-> constraint fk_employees3_departments foreign key(dept_id) references departments(dept_id)-> );

3)刪除約束

  • 語法:

ALTER TABLE <表名> DROP FOREIGN KEY <外鍵約束名>
  • 示例:

mysql> alter table employees3-> drop foreign key fk_employees3_departments;

例:創建員工數據庫的三張表

# 創建部門表 create table departments(dept_id int AUTO_INCREMENT PRIMARY KEY,dept_name VARCHAR(10) UNIQUE ); # 創建員工表 create table employees(employee_id INT auto_increment primary key,name VARCHAR(10) not null,hire_date DATE,birth_date DATE,email varchar(25) UNIQUE,phone_number varchar(11),dept_id int,FOREIGN KEY(dept_id) references departments(dept_id) ); # 創建工資表 create table salary(id int AUTO_INCREMENT PRIMARY KEY,date DATE,employee_id int,basic int,bonus int,FOREIGN KEY(employee_id) references employees(employee_id) );

十一.事務控制語言DCL

1.事務

  • 數據庫事務指的是一組數據操作。

  • 主要用于處理操作量大,復雜度高的數據。

  • 在 MySQL 中只有使用了 Innodb 數據庫引擎的數據庫或表才支持事務。

  • 事務處理可以用來維護數據庫的完整性,保證成批的 SQL 語句要么全部執行,要么全部不執行。

  • 事務用來管理 insert,update,delete 語句

2.事務必須滿足的4個條件

  • 原子性(Atomicity):一個事務(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。

  • 一致性(Consistency):在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及后續數據庫可以自發性地完成預定的工作。

  • 隔離性(Isolation):數據庫允許多個并發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務并發執行時由于交叉執行而導致數據的不一致。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重復讀(repeatable read)和串行化(Serializable)。

  • 持久性(Durability):事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。

3.事務控制語句

  • BEGIN 或 START TRANSACTION 顯式地開啟一個事務;

  • COMMIT 也可以使用 COMMIT WORK,不過二者是等價的。COMMIT 會提交事務,并使已對數據庫進行的所有修改成為永久性的;

  • ROLLBACK 也可以使用 ROLLBACK WORK,不過二者是等價的。回滾會結束用戶的事務,并撤銷正在進行的所有未提交的修改;

  • SAVEPOINT identifier,SAVEPOINT 允許在事務中創建一個保存點,一個事務中可以有多個 SAVEPOINT;

  • RELEASE SAVEPOINT identifier 刪除一個事務的保存點,當沒有指定的保存點時,執行該語句會拋出一個異常;

  • ROLLBACK TO identifier 把事務回滾到標記點;

  • SET TRANSACTION 用來設置事務的隔離級別。InnoDB 存儲引擎提供事務的隔離級別有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。

4.MySQL事物處理的方法

  • 用 BEGIN, ROLLBACK, COMMIT來實現

    • BEGIN開始一個事務

    • ROLLBACK事務回滾

    • COMMIT提交事務

  • 直接用 SET 來改變 MySQL 的自動提交模式

    • SET AUTOCOMMIT=0 禁止自動提交

    • SET AUTOCOMMIT=1*開啟自動提交

5.事務的創建

1)隱式事務

  • 事務沒有明顯的開啟和結束的標記。如INSERT、UPDATE、DELETE語句。

mysql> show variables like '%autocommit%'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set (0.00 sec)

2)顯式事務

  • 事務具有明顯的開啟和結束的標記

  • 必須先設置自動提交功能為禁用

mysql> set autocommit=0; # 只對當前會話生效 Query OK, 0 rows affected (0.00 sec)mysql> show variables like '%autocommit%'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | OFF | +---------------+-------+ 1 row in set (0.00 sec)

6.創建事務步驟

1)開啟事務

set aotocommit=0; start transaction; # 可選
  • 編寫事務語句:INSERT、UPDATE、DELETE語句

  • 結束事務

  • commit | rollback;

    7.事務示例

    • 創建銀行表

    mysql> use mydb; mysql> create table bank(-> id int primary key,-> name varchar(20),-> balance int-> ); Query OK, 0 rows affected (0.01 sec)
    • 插入數據

    mysql> insert into bank values-> (1, 'kali', 10000), (2, 'yao', 10000); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0
    • 使用事務:正常提交

    mysql> set autocommit=0; mysql> update bank set balance=balance-1000 where name='kali'; mysql> update bank set balance=balance+1000 where name='yao'; # 此時在另一終端查看bank表,數據并未改變 mysql> commit;
    • 使用事務:回滾

    mysql> set autocommit=0; mysql> update bank set balance=balance+1000 where name='kali'; mysql> update bank set balance=balance-1000 where name='yao'; # 此時在另一終端查看bank表,數據并未改變 mysql> rollback;

    十二.事務隔離

    1.事務隔離要解決的問題

    • 臟讀:臟讀指的是讀到了其他事務未提交的數據,未提交意味著這些數據可能會回滾,也就是可能最終不會存到數據庫中,也就是不存在的數據。讀到了并不一定最終存在的數據,這就是臟讀。

    • 可重復讀:可重復讀指的是在一個事務內,最開始讀到的數據和事務結束前的任意時刻讀到的同一批數據都是一致的。通常針對數據更新(UPDATE)操作。

    • 不可重復讀:對比可重復讀,不可重復讀指的是在同一事務內,不同的時刻讀到的同一批數據可能是不一樣的,可能會受到其他事務的影響,比如其他事務改了這批數據并提交了。通常針對數據更新(UPDATE)操作。

    • 幻讀:幻讀是針對數據插入(INSERT)操作來說的。假設事務A對某些行的內容作了更改,但是還未提交,此時事務B插入了與事務A更改前的記錄相同的記錄行,并且在事務A提交之前先提交了,而這時,在事務A中查詢,會發現好像剛剛的更改對于某些數據未起作用,但其實是事務B剛插入進來的,讓用戶感覺很魔幻,感覺出現了幻覺,這就叫幻讀。

    2.事務隔離級別

    • 讀未提交(READ UNCOMMITTED)

    • 讀提交 (READ COMMITTED)

    • 可重復讀 (REPEATABLE READ)

    • 串行化 (SERIALIZABLE)

    從上往下,隔離強度逐漸增強,性能逐漸變差。采用哪種隔離級別要根據系統需求權衡決定,其中,可重復讀是 MySQL 的默認級別。

    事務隔離其實就是為了解決上面提到的臟讀、不可重復讀、幻讀這幾個問題。只有串行化的隔離級別解決了全部這 3 個問題,其他的 3 個隔離級別都有缺陷。

    隔離級別出現臟讀出現不可重讀出現幻讀
    讀未提交可能可能可能
    讀提交不可能可能可能
    可重復讀不可能不可能可能
    串行化不可能不可能不可能

    3.設置事務隔離級別

    1)查看當前事務隔離級別

    mysql> select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec)

    2)設置隔離事務級別

    mysql> set session transaction isolation level read uncommitted; Query OK, 0 rows affected (0.01 sec)mysql> select @@tx_isolation; +------------------+ | @@tx_isolation | +------------------+ | READ-UNCOMMITTED | +------------------+ 1 row in set (0.00 sec)

    3)測試

    # 在第一個終端上執行以下2條語句 mysql> set autocommit=0; mysql> update bank set balance=balance+1000 where name='kali';# 以下3條語句在第二個終端上執行 mysql> set session transaction isolation level read uncommitted; mysql> set autocommit=0; mysql> select * from bank; # 此時kali賬戶上已經增加1000# 回到第一個終端回滾 mysql> rollback;# 在第2個終端上重新查詢 mysql> select * from bank; # 此時kali賬戶上又減少了1000

    4.SAVEPOINT應用

    1)基本用法

    • 使用mysql中的savepoint保存點來實現事務的部分回滾

    • 語法:

    SAVEPOINT identifier ROLLBACK [WORK] TO [SAVEPOINT] identifier RELEASE SAVEPOINT identifier
    • 使用 SAVEPOINT identifier 來創建一個名為identifier的回滾點

    • ROLLBACK TO identifier,回滾到指定名稱的SAVEPOINT,這里是identifier

    • 使用 RELEASE SAVEPOINT identifier 來釋放刪除保存點identifier

    • 如果當前事務具有相同名稱的保存點,則將刪除舊的保存點并設置一個新的保存點。

    • 如果執行START TRANSACTION,COMMIT和ROLLBACK語句,則將刪除當前事務的所有保存點。

    2)SAVEPOINT示例

    mysql> set autocommit=0; mysql> update bank set balance=balance+1000 where name='kali'; mysql> savepoint aaa; # 創建保存點 mysql> select * from bank; # kali老師賬號已增加1000 mysql> update bank set balance=balance-1000 where name='yao'; mysql> select * from bank; # yao賬號已減少1000 mysql> rollback to aaa; # 回滾到保存點aaa mysql> select * from bank; # kali老師賬號已增加1000,yao賬號未改變 mysql> exit; # 退出 # 再連入之后查詢 mysql> select * from bank; # 因為從未執行過commit。所以查到的結果與執行事務之前查到的結果一樣。

    總結

    以上是生活随笔為你收集整理的SQL基本语句及用法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。