《黑马程序员 MySQL数据库入门到精通,从MySQL安装到MySQL高级、MySQL优化全囊括》——学习笔记基础篇
基礎篇
前言
本文僅用作個人筆記使用,整理自《黑馬程序員 MySQL數據庫入門到精通,從MySQL安裝到MySQL高級、MySQL優化全囊括》(https://www.bilibili.com/video/BV1Kr4y1i7ru/)
什么是數據庫?
- 數據庫:DataBase 簡稱 :DB
- 是按照數據結構來組織、存儲和管理數據的倉庫。
- 是保存有組織的數據的一種容器,通常表現為一個或一組文件
- 我們也可以將數據存儲在文件中,但是在文件中讀寫數據速度相對較慢。
- 所以,現在我們使用關系型數據庫管理系統(RDBMS)來存儲和管理大數據量。所謂的關系型數據庫,是建立在關系模型基礎上的數據庫,借助于集合代數等數學概念和方法來處理數據庫中的數據。
- 數據庫的作用:將一組具有相同特征的數據以表為基礎單位通過存儲介質進行高效地存儲,存儲介質:內存、磁盤
- 概念混淆點:數據庫及數據庫軟件是錯誤的
- 數據庫系統:DataBase System = DBMS + DB
- 數據庫軟件——DBMS,數據庫管理系統,過DBMS來創建和管理數據庫
- 一般開發人員會針對每一個應用創建一個數據庫。為保存應用中實體的數據,一般會在數據庫創建多個表,以保存程序中實體用戶的數據
數據庫類別
-
基于存儲介質可以分為關系型數據庫與非關系型數據庫:
- 關系型數據庫是將數據存放于磁盤中,非關系型數據庫則存放于內存里
- 在數據訪問性能上看非關系型數據庫的效率更高;在數據安全性、持久性看,關系型數據庫有明顯優勢。關系型數據庫有利于數據的持久化保存與管理
-
關系型數據庫產品:
-
大型:Oracle、DB2
-
中型:MySQL、SQL-SERVER等
-
小型:access等
-
-
非關系型數據庫產品:
- Memcached
- MongoDB
- Redis(同步技術,數據同步到磁盤)
-
數據庫排名:https://db-engines.com/en/ranking
-
定義:關系型數據庫是建立在關系模型上的數據庫,關系模型是一種建立在關系上的模型,大致上分為:
- 數據結構:數據以二維表形式存儲(行和列)
- 操作指令集合:SQL語句
- 完整性約束:對于表內的約束和表與表之間的約束(實體內部、實體之間)
而本文所學習、研究的對象就是RDBMS中的MySQL數據庫。
RDBMS 即關系數據庫管理系統(Relational Database Management System)的特點:
- 數據以表格的形式出現
- 每行為各種記錄名稱
- 每列為記錄名稱所對應的數據域
- 許多的行和列組成一張表單
- 若干的表單組成database,格式統一,便于維護
- 使用SQL語言操作,標準同意,使用方便
**概念:**建立在關系模型基礎上,由多張相互連接的二維表組成的數據庫。
SQL語言
SQL通用語法
SQL語句可以單行或多行書寫,最后以分號結尾。
SQL語句可以使用空格/縮進來增強語句的可讀性。
MySQL數據庫的SQL語句不區分大小寫,但是為了可讀性建議關鍵字使用大寫。
注釋:
單行注釋: --單行注釋 或 #單行注釋多行注釋: /* 這是多行注釋 這是多行注釋 這是多行注釋 */SQL分類
| DDL | Data Definition Language | 數據定義語言,用來定義數據庫對象(數據庫,表,字段) |
| DML | Data Manipulation Language | 數據操作語言,用來對數據庫表中的數據進行增刪改 |
| DQL | Data Query Language | 數據查詢語言,用來查詢數據庫中表的記錄 |
| DCL | Data Control Language | 數據控制語言,用來創建數據庫的用戶以及權限的管理 |
DDL-數據定義語言
數據庫-查詢
查詢所有數據庫:SHOW DATABASES;
(Wed Aug 10 13:44:49 2022)[root@MySQL][(none)]>show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.00 sec)查詢當前數據庫:SELECT DATABASE();
(Wed Aug 10 13:46:52 2022)[root@MySQL][mysql]>select database(); +------------+ | database() | +------------+ | mysql | +------------+ 1 row in set (0.00 sec)數據庫-創建
創建數據庫:CREATE DATABASE [IF NOT EXISTS] 數據庫名稱 [DEFAULT CHARSET 編碼] [COLLATE 排序規則];
#如果當前服務端不存在testdb數據庫的話就創建一個名叫testdb的數據庫,并指定它的編碼為utf8mb4。(Wed Aug 10 13:50:33 2022)[root@MySQL][(none)]>create database if not exists testdb default charset utf8mb4; Query OK, 1 row affected (0.00 sec)(Wed Aug 10 13:53:52 2022)[root@MySQL][(none)]>show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | testdb | +--------------------+ 5 rows in set (0.00 sec)在這里多提一嘴,在創建數據庫時不建議將編碼指定為utf8,因為在MySQL中utf8的存儲長度為3字節,而有一些特殊的字符需要占到4字節。
數據庫-刪除
刪除數據庫:DROP DATABASE [IF EXISTS] 數據庫名稱;
#如果存在名稱為testdrop的數據庫,那么就將其刪除。(Wed Aug 10 14:01:00 2022)[root@MySQL][(none)]>show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | testdb | +--------------------+ 5 rows in set (0.00 sec)數據庫-切換
切換數據庫:USE 數據庫名稱;
#將當前數據庫切換至testdb數據庫。(Wed Aug 10 14:01:02 2022)[root@MySQL][(none)]>use testdb; Database changed (Wed Aug 10 14:02:34 2022)[root@MySQL][testdb]> #原先這里的none就變成了testdb表-數據類型
原文地址:詳解MySQL數據類型 - 五月的倉頡 - 博客園 (cnblogs.com)
整型
| TINYINT | 1 | -128 | 127 | 0 | 255 |
| SMALLINT | 2 | -32768 | 32767 | 0 | 65535 |
| MEDIUMINT | 3 | -8388608 | 8388607 | 0 | 16777215 |
| INT | 4 | -2147483648 | 2147483647 | 0 | 4294967295 |
| BIGINT | 8 | -9223372036854775808 | 9223372036854775807 | 0 | 18446744073709551616 |
即使是帶符號的BIGINT,其實也已經是一個天文數字了,什么概念,9223372036854775807我們隨便舉下例子:
- 以byte為例可以表示8589934592GB–>8388608TB–>8192PB
- 以毫秒為例可以表示292471208年
所以從實際開發的角度,我們一定要為合適的列選取合適的數據類型,即到底用不用得到這種數據類型?舉個例子:
- 一個枚舉字段明明只有0和1兩個枚舉值,選用TINYINT就足夠了,但在開發場景下卻使用了BIGINT,這就造成了資源浪費
- 簡單計算一下,假使該數據表中有100W數據,那么總共浪費了700W字節也就是6.7M左右,如果更多的表這么做了,那么浪費的更多
要知道,MySQL本質上是一個存儲,以Java為例,可以使用byte類型的地方使用了long類型問題不大,因為絕大多數的對象在程序中都是短命對象,方法執行完畢這塊內存區域就被釋放了,7個字節實際上不存在浪不浪費一說。但是MySQL作為一個存儲,8字節的BIGINT放那兒就放那兒了,占據的空間是實實在在的。
舉個例子:
drop table if exists test_tinyint; create table test_tinyint (num tinyint ) engine=innodb charset=utf8;insert into test_tinyint values(-100); insert into test_tinyint values(255);執行第7行的代碼時候報錯"Out of range value for column ‘num’ at row 1",即很清楚的我們可以看到插入的數字范圍越界了,這也同樣反映出MySQL中整型默認是帶符號的。
把第3行的num字段定義改為"num tinyint unsigned"第7的插入就不會報錯了,但是第6行的插入-100又報錯了,因為無符號整型是無法表示負數的。
整型(N)形式
在開發中,我們會碰到有些定義整型的寫法是int(11),這種寫法從我個人開發的角度看我認為是沒有多大用,不過作為一個知識點做一下講解吧。
int(N)我們只需要記住兩點:
- 無論N等于多少,int永遠占4個字節
- N表示的是顯示寬度,不足的用0補足,超過的無視長度而直接顯示整個數字,但這要整型設置了unsigned zerofill才有效
浮點型
整型之后,下面是浮點型,在MySQL中浮點型有兩種,分別為float、double,它們用一張表格總結一下:
| float | 4 | 單精度浮點數 |
| double | 8 | 雙精度浮點數 |
從這個結果我們總結一下float(M,D)、double(M、D)的用法規則:
- D表示浮點型數據小數點之后的精度,假如超過D位則四舍五入,即1.233四舍五入為1.23,1.237四舍五入為1.24
- M表示浮點型數據總共的位數,D=2則表示總共支持五位,即小數點前只支持三位數,所以我們并沒有看到1000.23、10000.233、100000.233這三條數據的插入,因為插入都報錯了
當我們不指定M、D的時候,會按照實際的精度來處理。
定點型
介紹完float、double兩種浮點型,我們介紹一下定點型的數據類型decimal類型,有了浮點型為什么我們還需要定點型?
float、double類型存在精度丟失問題,即寫入數據庫的數據未必是插入數據庫的數據,而decimal無論寫入數據中的數據是多少,都不會存在精度丟失問題,這就是我們要引入decimal類型的原因,decimal類型常見于銀行系統、互聯網金融系統等對小數點后的數字比較敏感的系統中。
最后講一下decimal和float/double的區別:
- float/double在db中存儲的是近似值,而decimal則是以字符串形式進行保存的
- decimal(M,D)的規則和float/double相同,但區別在float/double在不指定M、D時默認按照實際精度來處理而decimal在不指定M、D時默認為decimal(10, 0)
日期類型
接著我們看一下MySQL中的日期類型,MySQL支持五種形式的日期類型:date、time、year、datetime、timestamp,用一張表格總結一下這五種日期類型:
| date | 3 | yyyy-MM-dd | 存儲日期值 |
| time | 3 | HH:mm:ss | 存儲時分秒 |
| year | 1 | yyyy | 存儲年 |
| datetime | 8 | yyyy-MM-dd HH:mm:ss | 存儲日期+時間 |
| timestamp | 4 | yyyy-MM-dd HH:mm:ss | 存儲日期+時間,可作時間戳 |
MySQL的時間類型的知識點比較簡單,這里重點關注一下datetime與timestamp兩種類型的區別:
- 上面列了,datetime占8個字節,timestamp占4個字節
- 由于大小的區別,datetime與timestamp能存儲的時間范圍也不同,datetime的存儲范圍為1000-01-01 00:00:00——9999-12-31 23:59:59,timestamp存儲的時間范圍為19700101080001——20380119111407
- datetime默認值為空,當插入的值為null時,該列的值就是null;timestamp默認值不為空,當插入的值為null的時候,mysql會取當前時間
- datetime存儲的時間與時區無關,timestamp存儲的時間及顯示的時間都依賴于當前時區
char和varchar類型
最后看一下常用到的字符型,說到MySQL字符型,我們最熟悉的應該就是char和varchar了,關于char和varchar的對比,我總結一下:
varchar型數據占用空間大小及可容納最大字符串限制探究
接上一部分,我們這部分來探究一下varchar型數據實際占用空間大小是如何計算的以及最大可容納的字符串為多少,首先要給出一個結論:這部分和具體編碼方式有關,且MySQL版本我現在使用的是5.7,當然5.0之后的都是可以的。
先寫一段SQL創建表,utf8的編碼格式:
drop table if exists test_varchar; create table test_varchar (varchar_value varchar(100000) ) engine=innodb charset=utf8;執行報錯:
Column length too big for column 'varchar_value' (max = 21845); use BLOB or TEXT instead按照提示,我們把大小改為21845,執行依然報錯:
Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs改為21844就不會有問題,因此在utf8編碼下我們可以知道varchar(M),M最大=21844。那么gbk呢:
drop table if exists test_varchar; create table test_varchar (varchar_value varchar(100000) ) engine=innodb charset=gbk;同樣的報錯:
Column length too big for column 'varchar_value' (max = 32767); use BLOB or TEXT instead把大小改為32766,也是和utf8編碼格式一樣的報錯:
Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs可見gbk的編碼格式下,varchar(M)最大的M=32765,那么為什么會有這樣的區別呢,分點詳細解釋一下:
- MySQL要求一個行的定義長度不能超過65535即64K
- 對于未指定varchar字段not null的表,會有1個字節專門表示該字段是否為null
- varchar(M),當M范圍為0<=M<=255時會專門有一個字節記錄varchar型字符串長度,當M>255時會專門有兩個字節記錄varchar型字符串的長度,把這一點和上一點結合,那么65535個字節實際可用的為65535-3=65532個字節
- 所有英文無論其編碼方式,都占用1個字節,但對于gbk編碼,一個漢字占兩個字節,因此最大M=65532/2=32766;對于utf8編碼,一個漢字占3個字節,因此最大M=65532/3=21844,上面的結論都成立
- 舉一反三,對于utfmb4編碼方式,1個字符最大可能占4個字節,那么varchar(M),M最大為65532/4=16383,可以自己驗證一下
同樣的,上面是表中只有varchar型數據的情況,如果表中同時存在int、double、char這些數據,需要把這些數據所占據的空間減去,才能計算varchar(M)型數據M最大等于多少。
varchar、text和blob
最后講一講text和blob兩種數據類型,它們的設計初衷是為了存儲大數據使用的,因為之前說了,MySQL單行最大數據量為64K。
先說一下text,text和varchar是一組既有區別又有聯系的數據類型,其聯系在于當varchar(M)的M大于某些數值時,varchar會自動轉為text:
- M>255時轉為tinytext
- M>500時轉為text
- M>20000時轉為mediumtext
所以過大的內容varchar和text沒有區別,同時varchar(M)和text的區別在于:
- 單行64K即65535字節的空間,varchar只能用63352/65533個字節,但是text可以65535個字節全部用起來
- text可以指定text(M),但是M無論等于多少都沒有影響
- text不允許有默認值,varchar允許有默認值
varchar和text兩種數據類型,使用建議是能用varchar就用varchar而不用text(存儲效率高),varchar(M)的M有長度限制,之前說過,如果大于限制,可以使用mediumtext(16M)或者longtext(4G)。
至于text和blob,簡單過一下就是text存儲的是字符串而blob存儲的是二進制字符串,簡單說blob是用于存儲例如圖片、音視頻這種文件的二進制數據的。
表-創建
創建一張表:
CREATE TABLE 表名稱(字段1 類型 [COMMENT 字段1注釋],字段2 類型 [COMMENT 字段2注釋],...字段n 類型 [COMMENT 字段n注釋] )[COMMENT 表注釋];思考一下,如何創建出下方這張表?
| 1 | 甲殼蟲 | 22 | 一班 |
| 2 | 花蝴蝶 | 27 | 一班 |
| 3 | 劉六六 | 66 | 二班 |
表-查詢
查詢當前數據庫下所有表:SHOW TABLES;
(Wed Aug 10 14:18:05 2022)[root@MySQL][mysql]>SHOW TABLES; +------------------------------------------------------+ | Tables_in_mysql | +------------------------------------------------------+ | columns_priv | | component | | db | | default_roles | | engine_cost | | func | | general_log | | global_grants | | gtid_executed | | help_category | | help_keyword | | help_relation | | help_topic | | innodb_index_stats | | innodb_table_stats | | password_history | | plugin | | procs_priv | | proxies_priv | | replication_asynchronous_connection_failover | | replication_asynchronous_connection_failover_managed | | role_edges | | server_cost | | servers | | slave_master_info | | slave_relay_log_info | | slave_worker_info | | slow_log | | tables_priv | | time_zone | | time_zone_leap_second | | time_zone_name | | time_zone_transition | | time_zone_transition_type | | user | +------------------------------------------------------+ 35 rows in set (0.00 sec)查詢某一張表的表結構:DESC 表名稱;
(Wed Aug 10 14:32:52 2022)[root@MySQL][testdb]>DESC table_student; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int | YES | | NULL | | | name | varchar(10) | YES | | NULL | | | age | int | YES | | NULL | | | class | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 4 rows in set (0.01 sec)查詢指定表的建表語句:SHOW CREATE TABLE 表名稱;
(Wed Aug 10 14:33:44 2022)[root@MySQL][testdb]>SHOW CREATE TABLE table_student; +---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | table_student | CREATE TABLE `table_student` (`id` int DEFAULT NULL COMMENT '編號',`name` varchar(10) DEFAULT NULL COMMENT '姓名',`age` int DEFAULT NULL COMMENT '年齡',`class` varchar(20) DEFAULT NULL COMMENT '班級' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='學生表' | +---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.02 sec)表-修改
添加字段:ALTER TABLE 表名 ADD 字段名 類型(長度) [COMMENT 注釋] [約束];
#為emp表新增一個字段“昵稱”為nickname,類型為varchar(20)(Wed Aug 10 16:35:22 2022)[root@MySQL][testdb]>ALTER TABLE Employee_info ADD nickname varchar(20) comment '昵稱'; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0(Wed Aug 10 16:35:31 2022)[root@MySQL][testdb]>DESC Employee_info; +-------------------+------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------------+------------------+------+-----+---------+-------+ | id | int | YES | | NULL | | | employee_no | varchar(10) | YES | | NULL | | | employee_name | varchar(10) | YES | | NULL | | | employee_gender | char(1) | YES | | NULL | | | employee_age | tinyint unsigned | YES | | NULL | | | employee_idnum | char(18) | YES | | NULL | | | employee_hiredate | date | YES | | NULL | | | nickname | varchar(20) | YES | | NULL | | +-------------------+------------------+------+-----+---------+-------+ 8 rows in set (0.00 sec)修改數據類型:ALTER TABLE 表名 MODIFY 字段名 新數據類型(長度);
修改字段名和字段類型:ALTER TABLE 表名 CHANGE 舊字段名 新字段名 新數據類型(長度) [COMMENT 注釋] [約束];
#將Employee_info表的nickname字段修改為employee_username,類型為varchar(30)。(Wed Aug 10 16:45:47 2022)[root@MySQL][testdb]>ALTER TABLE Employee_info CHANGE nickname employee_username varchar(30); Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0(Wed Aug 10 16:46:19 2022)[root@MySQL][testdb]>DESC Employee_info; +-------------------+------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------------+------------------+------+-----+---------+-------+ | id | int | YES | | NULL | | | employee_no | varchar(10) | YES | | NULL | | | employee_name | varchar(10) | YES | | NULL | | | employee_gender | char(1) | YES | | NULL | | | employee_age | tinyint unsigned | YES | | NULL | | | employee_idnum | char(18) | YES | | NULL | | | employee_hiredate | date | YES | | NULL | | | employee_username | varchar(30) | YES | | NULL | | +-------------------+------------------+------+-----+---------+-------+ 8 rows in set (0.00 sec)修改表名:ALTER TABLE 表名 RENAME TO 新表名;
#將Employee_info表名修改為Emp_info(Wed Aug 10 16:50:52 2022)[root@MySQL][testdb]>ALTER TABLE Employee_info RENAME TO Emp_info; Query OK, 0 rows affected (0.01 sec) (Wed Aug 10 16:53:09 2022)[root@MySQL][testdb]>SHOW TABLES; +------------------+ | Tables_in_testdb | +------------------+ | Emp_info | | table_student | +------------------+ 2 rows in set (0.00 sec)表-刪除
刪除字段:ALTER TABLE 表名 DROP 字段名;
#刪除Employee_info表的字段employee_username(Wed Aug 10 16:46:29 2022)[root@MySQL][testdb]>ALTER TABLE Employee_info DROP employee_username; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0(Wed Aug 10 16:50:46 2022)[root@MySQL][testdb]>DESC Employee_info; +-------------------+------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------------+------------------+------+-----+---------+-------+ | id | int | YES | | NULL | | | employee_no | varchar(10) | YES | | NULL | | | employee_name | varchar(10) | YES | | NULL | | | employee_gender | char(1) | YES | | NULL | | | employee_age | tinyint unsigned | YES | | NULL | | | employee_idnum | char(18) | YES | | NULL | | | employee_hiredate | date | YES | | NULL | | +-------------------+------------------+------+-----+---------+-------+ 7 rows in set (0.00 sec)刪除表:DROP TABLE [IF EXISTS] 表名;
#刪除table_student表(Wed Aug 10 16:53:22 2022)[root@MySQL][testdb]>DROP TABLE IF EXISTS table_student; Query OK, 0 rows affected (0.01 sec)(Wed Aug 10 16:59:53 2022)[root@MySQL][testdb]>SHOW TABLES; +------------------+ | Tables_in_testdb | +------------------+ | Emp_info | +------------------+ 1 row in set (0.00 sec)刪除指定表,并重新創建該表:TRUNCATE TABLE 表名;
(Wed Aug 10 17:00:14 2022)[root@MySQL][testdb]>TRUNCATE TABLE Emp_info; Query OK, 0 rows affected (0.01 sec)(Wed Aug 10 17:08:20 2022)[root@MySQL][testdb]>SHOW TABLES; +------------------+ | Tables_in_testdb | +------------------+ | Emp_info | +------------------+ 1 row in set (0.00 sec)小結
DML-數據操作語言
數據-添加
給指定字段添加數據:INSERT INTO 表名(字段1,字段2,...) VALUES(值1,值2,...);
(Thu Aug 11 14:49:37 2022)[root@MySQL][testdb]>INSERT INTO Emp_info(id,employee_no,employee_name,employee_gender,employee_age,employee_idnum,employee_hiredate) VALUES(2,'2','張十五','男',25,'123456789012345687','2021-05-16'); Query OK, 1 row affected (0.01 sec)(Thu Aug 11 14:58:07 2022)[root@MySQL][testdb]>select * from Emp_info; +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | id | employee_no | employee_name | employee_gender | employee_age | employee_idnum | employee_hiredate | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | 1 | 1 | 劉六六 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 2 | 2 | 張十五 | 男 | 25 | 123456789012345687 | 2021-05-16 | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ 2 rows in set (0.00 sec)給全部字段添加數據:INSERT INTO 表名 VALUES(值1,值2,...);
(Thu Aug 11 14:49:37 2022)[root@MySQL][testdb]>INSERT INTO Emp_info VALUES(1,'1','劉六六','男',21,'123456789012345678','2022-08-10'); Query OK, 1 row affected (0.01 sec)(Thu Aug 11 14:49:52 2022)[root@MySQL][testdb]>select * from Emp_info; +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | id | employee_no | employee_name | employee_gender | employee_age | employee_idnum | employee_hiredate | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | 1 | 1 | 劉六六 | 男 | 21 | 123456789012345678 | 2022-08-10 | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ 1 row in set (0.00 sec)批量添加數據:INSERT INTO 表名(字段1,字段2,...) VALUES(值1,值2,...),(值1,值2,...);
INSERT INTO 表名 VALUES(字段1,字段2,...),(字段1,字段2,...),(字段1,字段2,...);
(Thu Aug 11 14:58:25 2022)[root@MySQL][testdb]>INSERT INTO Emp_info VALUES(1,'1','劉六六','男',21,'123456789012345678','2022-08-10'),(1,'1','劉六六','男',21,'123456789012345678','2022-08-10'),(1,'1','劉六六','男',21,'123456789012345678','2022-08-10'),(1,'1','劉六六','男',21,'123456789012345678','2022-08-10'); Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0(Thu Aug 11 15:00:01 2022)[root@MySQL][testdb]>select * from Emp_info; +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | id | employee_no | employee_name | employee_gender | employee_age | employee_idnum | employee_hiredate | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | 1 | 1 | 劉六六 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 2 | 2 | 張十五 | 男 | 25 | 123456789012345687 | 2021-05-16 | | 1 | 1 | 劉六六 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 1 | 1 | 劉六六 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 1 | 1 | 劉六六 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 1 | 1 | 劉六六 | 男 | 21 | 123456789012345678 | 2022-08-10 | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ 6 rows in set (0.01 sec)注意:
- 插入數據時,指定的字段順序需要與值的順序是一一對應的。
- 字符串和日期型數據應該包含在引號中。
- 插入的數據大小,應該在字段的規定范圍內。
數據-修改
修改數據:UPDATE 表名 SET 字段1=值1,字段2=值2,...[WHERE 條件];
注意:修改語句的條件可以有,也可以沒有,如果沒有條件,則會修改整張表的所有數據
#修改id為1的數據,將name修改為王哈哈(Thu Aug 11 15:18:37 2022)[root@MySQL][testdb]>select * from Emp_info; +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | id | employee_no | employee_name | employee_gender | employee_age | employee_idnum | employee_hiredate | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 2 | 2 | 張十五 | 男 | 25 | 123456789012345687 | 2021-05-16 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2022-08-10 | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ 6 rows in set (0.00 sec) #修改id為2的數據,將name改為小花,gender改為女(Thu Aug 11 15:29:25 2022)[root@MySQL][testdb]>UPDATE Emp_info SET employee_name='小花',employee_gender='女' WHERE id=2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0(Thu Aug 11 15:29:31 2022)[root@MySQL][testdb]>select * from Emp_info; +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | id | employee_no | employee_name | employee_gender | employee_age | employee_idnum | employee_hiredate | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 2 | 2 | 小花 | 女 | 25 | 123456789012345687 | 2021-05-16 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2022-08-10 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2022-08-10 | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ 6 rows in set (0.00 sec) #修改所有人的入職日期為2021年8月15日(Thu Aug 11 15:29:34 2022)[root@MySQL][testdb]>UPDATE Emp_info SET employee_hiredate='2021-08-15'; Query OK, 6 rows affected (0.00 sec) Rows matched: 6 Changed: 6 Warnings: 0(Thu Aug 11 15:33:41 2022)[root@MySQL][testdb]>select * from Emp_info; +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | id | employee_no | employee_name | employee_gender | employee_age | employee_idnum | employee_hiredate | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2021-08-15 | | 2 | 2 | 小花 | 女 | 25 | 123456789012345687 | 2021-08-15 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2021-08-15 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2021-08-15 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2021-08-15 | | 1 | 1 | 王哈哈 | 男 | 21 | 123456789012345678 | 2021-08-15 | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ 6 rows in set (0.00 sec)數據-刪除
刪除數據:DELETE FROM 表名 [WHERE 條件];
#刪除gender為男的員工(Thu Aug 11 15:33:42 2022)[root@MySQL][testdb]>DELETE FROM Emp_info WHERE employee_gender='男'; Query OK, 5 rows affected (0.00 sec)(Thu Aug 11 15:44:48 2022)[root@MySQL][testdb]>select * from Emp_info; +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | id | employee_no | employee_name | employee_gender | employee_age | employee_idnum | employee_hiredate | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ | 2 | 2 | 小花 | 女 | 25 | 123456789012345687 | 2021-08-15 | +------+-------------+---------------+-----------------+--------------+--------------------+-------------------+ 1 row in set (0.00 sec) #刪除所有員工(Thu Aug 11 15:44:52 2022)[root@MySQL][testdb]>DELETE FROM Emp_info; Query OK, 1 row affected (0.01 sec)(Thu Aug 11 15:46:40 2022)[root@MySQL][testdb]>select * from Emp_info; Empty set (0.00 sec)注意:
- DELETE語句的條件可以有也可以沒有,如果不加上WHERE的話,是刪除整張表的數據。
- DELETE語句不能刪除某一個字段的值,但可以使用UPDATE。
小結
DQL-數據查詢語言
語法:
SELECT字段1,字段2,... FROM表1,表2,... WHERE條件1,條件2,... GROUP BY分組字段1,分組字段2,... HAVING分組后條件1,分組后條件2,... ORDER BY排序字段1,排序字段2,... LIMIT分頁參數基本查詢
實例:
#查詢指定字段 name,workno,age返回SELECT name,workno,age FROM emp; #查詢所有字段返回SELECT * FROM emp; #查詢所有員工的工作地址,起別名SELECT name AS '姓名',workaddress AS '工作地址' FROM emp; #查詢員工的工作地址,不要重復的SELECT DISTINCT workaddress FROM emp;條件查詢
語法:SELECT 字段1,字段2,... FROM 表名 WHERE 條件...;
實例:
#查詢年齡為53歲的員工SELECT * FROM emp WHERE age = 53; #查詢年齡小于20的員工SELECT name,age FROM emp WHERE age < 20; #查詢年齡小于等于20的員工SELECT name,age FROM emp WHERE age <= 20; #查詢身份證號為空的員工SELECT name,idcard FROM emp WHERE idcard IS NULL; #查詢身份證號不為空的員工SELECT name,idcard FROM emp WHERE idcard IS NOT NULL; #查詢年齡不等于25的員工 SELECT name,age FROM emp WHERE age <> 25; #或 SELECT name,age FROM emp WHERE age != 25; #查詢年齡在18-28歲之間的員工SELECT name,age FROM emp WHERE age BETWEEN 18 AND 28; #查詢性別為女且年齡小于23的員工SELECT name,age,gender FROM emp WHERE gender='女' AND age < 23; #查詢年齡為18或23或40的員工SELECT name,age FROM emp WHERE age = 18 or age = 23 or age = 40; #查詢姓名為兩個字的員工SELECT name FROM emp WHERE name LIKE "__"; #查詢身份證號最后一位是X的員工SELECT name,idcard FROM emp WHERE idcard LIKE "%X";聚合函數
| count | 統計數量 |
| max | 最大值 |
| min | 最小值 |
| avg | 平均數 |
| sum | 求和 |
語法:SELECT 聚合函數(字段) FROM 表名;
實例:
#統計該企業員工數量SELECT COUNT(*) FROM emp; #或 SELECT COUNT(字段) FROM emp; #統計該企業員工的平均年齡SELECT ROUND(AVG(age),0) FROM emp; #這里的ROUND是四舍五入,其中0是保留幾位小數,從0開始。 #統計該企業員工最大年齡SELECT MAX(age) FROM emp; #統計該企業員工最小年齡SELECT MIN(age) FROM emp; #統計北京市員工年齡之和以及平均值SELECT workaddress as '工作地址',SUM(age) as '北京地區年齡之和',AVG(age) as '北京地區年齡平均值' FROM emp WHERE workaddress = '北京市';注意:所有的NULL值不參與聚合函數的計算。
分組查詢
語法:SELECT 字段列表 FROM 表名 [WHERE 條件] GROUP BY 字段名 [HAVING 過濾條件]
WHERE和HAVING的區別:
- 執行的順序不同:WHERE時分組之前進行過濾,不滿足WHERE條件的數據不參與分組。而HAVING是對分組之后的結果進行過濾。
- 判斷的條件不同:WHERE不能對聚合函數進行判斷,但是HAVING可以。
實例:
#根據性別分組,分別統計男性員工和女性員工的數量SELECT gender,count(*) FROM emp GROUP BY gender; #根據性別分組,統計男性員工和女性員工的平均年齡SELECT gender,ROUND(avg(age),0) FROM emp GROUP BY gender; #查詢年齡小于45的員工,并根據工作地址分組,獲取員工數量大于等于100的工作地址 SELECT workaddress,COUNT(*) FROM emp WHERE age < 45 GROUP BY workaddress HAVING COUNT(*) >= 100;注意
- 執行順序:WHERE -> 聚合函數 -> HAVING。
- 分組之后,查詢的字段一般為聚合函數和分組字段。
排序查詢
語法:SELECT 字段1, 字段2,... FROM 表名 ORDER BY 字段1 排序方式1, 字段2 排序方式2;
排序方式:
- ASC:升序(默認)
- DESC:降序
注意:如果是多字段排序,當第一個字段值相同時,才會根據第二個字段進行排序。
#根據年齡對員工進行升序排序SELECT * FROM emp ORDER BY age ASC; #根據入職時間,對員工進行降序排序SELECT * FROM emp ORDER BY entrydate DESC; #根據年齡對員工進行升序排序,年齡相同再根據入職時間降序排序SELECT * FROM emp ORDER BY age ASC, entrydate DESC;分頁查詢
語法:SELECT 字段1, 字段2, ... FROM 表名 LIMIT 起始索引, 查詢的記錄條數;
注意:
- 起始索引從0開始,起始索引=(查詢頁碼 - 1)* 查詢的記錄條數。
- 分頁查詢是數據庫的方言,不同的數據庫有不同的實現,MySQL中是LIMIT。
- 如果查詢的是第一頁的數據,則可以忽略起始索引。
實例:
#查詢第16頁員工數據,每頁顯示50條數據 SELECT * FROM emp LIMIT 750, 50;小測試
#查詢年齡為20,21,22,23歲的員工信息SELECT * FROM emp WHERE age BETWEEN 20 AND 23; #查詢性別為男,年齡在30-50歲(含)且名字為三個字的員工SELECT name,age FROM emp WHERE age BETWEEN 30 AND 50 AND name LIKE '___'; #統計員工表中,年齡小于50的男性員工和女性員工人數。SELECT gender,COUNT(*) FROM emp WHERE age < 50 GROUP BY gender; #查詢所有年齡小于等于35歲員工的姓名和年齡,并對查詢結果根據年齡升序排序,如果年齡相同按入職時間降序排序SELECT name,age FROM emp WHERE age <= 35 ORDER BY age, entrydate DESC; #查詢性別為男,且年齡在30-50歲(含)以內的前20個員工信息,對結果按年齡升序排序,如果年齡相同按入職時間升序排序SELECT * FROM emp WHERE age BETWEEN 30 AND 50 ORDER BY age, entrydate LIMIT 20;執行順序
編寫順序:SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY -> LIMIT
執行順序:FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT
小結
1.DQL語句
SELECT字段1,字段2,... FROM表1,表2,... WHERE條件1,條件2,... GROUP BY分組字段1,分組字段2,... HAVING分組后條件1,分組后條件2,... ORDER BY排序字段1,排序字段2,... LIMIT分頁參數DCL-數據控制語言
用戶-查詢用戶
#查詢所有用戶USE mysql; SELECT * FROM user;用戶-創建用戶
語法:CREATE USER '用戶名'@'主機名' IDENTIFIED BY '密碼';
#創建一個新用戶名為Mask1密碼為MySQL123,只能被本機localhost登錄CREATE USER 'Mask1'@'localhost' IDENTIFIED BY 'MySQL123'; #創建一個新用戶名為Mask2密碼為MySQL123,且可以被任意主機登錄CREATE USER 'Mask2'@'%' IDENTIFIED BY 'MySQL123';用戶-修改密碼
語法:ALTER USER '用戶名'@'主機名' IDENTIFIED WITH mysql_native_password BY '新密碼';
#修改Mask2用戶的密碼為MySQL321ALTER USER 'Mask2'@'%' IDENTIFIED BY 'MYSQL321';用戶-刪除用戶
語法:DROP USER '用戶名'@'主機名';
#刪除Mask1用戶 DROP USER 'Mask1'@'localhost';注意:主機名可以用’%'通配。
常用權限:
| ALL,ALL PRIVILEGES | 所有權限 |
| SELECT | 查詢數據 |
| INSERT | 插入數據 |
| UPDATE | 修改數據 |
| DELETE | 刪除數據 |
| ALTER | 修改表 |
| DROP | 刪除數據庫/表/視圖 |
| CREATE | 創建數據庫/表 |
權限-查詢權限
語法:SHOW GRANTS FOR '用戶名'@'主機名';
#查詢Mask2用戶的權限SHOW GRANTS FOR 'Mask2'@'%';權限-授予權限
語法:GRANT 權限 ON 數據庫名.表名 TO '用戶名'@'主機名';
#給Mask2用戶所有數據庫所有表的ALL PRIVILEGES權限GRANT ALL PRIVILEGES ON *.* TO 'Mask2'@'%';權限-撤銷權限
語法:REVOKE 權限 ON 數據庫名.表名 FROM '用戶名'@'主機名';
#撤銷Mask2用戶的所有權限REVOKE ALL PRIVILEGES ON *.* FROM 'Mask2'@'localhost';注意:
- 多個權限之間,使用逗號分割。
- 授權時,數據庫名和表名可以使用’**'進行通配,代表所有。
小結
#用戶管理 CREATE USER '用戶名'@'主機名' IDENTIFIED BY '密碼'; ALTER USER '用戶名'@'主機名' IDENTIFIED WITH mysql_native_password BY '新密碼'; DROP USER '用戶名'@'主機名'; #權限控制 SHOW GRANTS FOR '用戶名'@'主機名'; GRANT ALL PRIVILEGES ON *.* TO 'Mask2'@'%'; REVOKE ALL PRIVILEGES ON *.* FROM 'Mask2'@'localhost';函數
函數是指一段可以直接被另一端程序調用的程序或代碼。
字符串函數
| CONCAT(S1,S2,…) | 字符串拼接,將S1,S2,…拼接成一個字符串 |
| LOWER(STR) | 將字符串STR全部轉為小寫R |
| UPPER(STR) | 將字符串STR全部轉為大寫 |
| LPAD(STR,N,PAD) | 左填充,用字符串PAD對STR左邊進行填充,使STR字符串長度達到N |
| RPAD(STR,N,PAD) | 右填充,用字符串PAD對STR右邊進行填充,使STR字符串長度達到N |
| TRIM(STR) | 去掉字符串頭部和尾部的空格 |
| SUBSTRING(STR,START,LEN) | 返回字符串STR從START位置開始的LEN個長度的字符串 |
實例:
#由于業務需求變更,企業員工工號統一為5位數,不足5位數的全部在前面補0.UPDATE emp SET workno = LPAD(workno,5,'0');數值函數
| CEIL(X) | 向上取整 |
| FLOOR(X) | 向下取整 |
| MOD(X,Y) | 返回X/Y的模 |
| RAND() | 返回0-1之間的隨機數 |
| ROUND(X,Y) | 求參數X的四舍五入值,并保留Y位小數 |
實例:
#通過函數,生成一個六位數的隨機驗證碼SELECT LPAD(ROUND(RAND()*1000000,0),6,0);日期函數
| CURDATE() | 返回當前日期 |
| CURTIME() | 返回當前時間 |
| NOW() | 返回當前日期和時間 |
| YEAR(DATE) | 獲取指定DATE的年份 |
| MONTH(DATE) | 獲取指定DATE的月份 |
| DAY(DATE) | 獲取指定DATE的日期 |
| DATE_ADD(DATE, INTERVAL EXPR TYPE) | 返回一個日期/時間值加上一個時間間隔expr后的時間值 |
| DATEDIFF(DATE1,DATE2) | 返回起始時間DATE1和結束時間DATE2之間的天數 |
實例:
#查詢所有員工的入職天數SELECT name,DATEDIFF(CURDATE(),entrydate) AS entryday FROM EMP ORDER BY entryday DESC;流程函數
| IF(VALUE,T,F) | 如果VALUE為true,返回t,否則返回f |
| IFNULL(VALUE1,VALUE2) | 如果VALUE1不為空,返回VALUE1,否則返回VALUE2 |
| CASE WHEN [VAL1] THEN [RES1] … ELSE [DEFAULT] END | 如果VAL1為true,返回RES1,…否則返回DEFAULT |
| CASE [EXPR] WHEN [VAL1] THEN [RES1] … ELSE [DEFAULT] END | 如果EXPR的值等于VAL1,返回RES1, … 否則返回DEFAULT |
實例:
#查詢員工姓名和工作地址(北京上海->一線城市,其他->二線城市)SELECT name,CASE WHEN workaddress='北京市' or workaddress='上海市' THEN '一線城市' ELSE '二線城市' END FROM EMP; create table score( id int comment 'ID', name varchar(20) comment '姓名', math int comment '數學', english int comment '英語', chinese int comment '語文' ) comment '學生成績表'; #統計班級各個學員的成績,規則如下:>= 85,顯示優秀>= 60,顯示及格否則顯示不及格小結
約束
概述
概念:約束是作用于表中字段上的規則,用于限制存儲在表中的數據。
目的:保證數據庫中數據的正確、有效和完整性。
分類:
| 非空約束 | 限制該字段的數據不能為NULL | NOT NULL |
| 唯一約束 | 保證該字段的所有數據都是唯一并不重復的 | UNIQUE |
| 主鍵約束 | 主鍵是一行數據的唯一標識,要求非空且唯一 | PRIMARY KEY |
| 默認約束 | 保存數據時,如果未指定該字段的值,則采用默認 | DEFAULT |
| 檢查約束(8.0.16版本+) | 保證字段值滿足某一個條件 | CHECK |
| 外鍵約束 | 用來讓兩張表的數據之間建立連接,保證數據的一致性和完整性 | FOREIGN KEY |
注意:約束是作用于表中字段上的,可以在創建表/修改表的時候添加約束
約束演示
需求表:
| id | ID唯一標識 | int | 主鍵,自動遞增 |
| name | 姓名 | varchar(10) | 不為空 |
| age | 年齡 | int | 大于0,小于120 |
| status | 狀態 | char(1) | 如果沒有值默認為1 |
| gender | 性別 | char(1) | 無 |
外鍵約束
概念:外鍵用來讓兩張表之間建立連接,從而保證數據的一致性和完整性。
注意:在數據庫層面,未建立外鍵關聯,是無法保證數據的一致性和完整性的。
語法:
#創建表時添加外鍵 CREATE TABLE 表名(字段名 數據類型,字段名 數據類型 [CONSTRAINT] [外鍵名稱] FOREIGN KEY(外鍵字段名) REFERENCES 主表(主表列名) );#創建表后添加外鍵 ALTER TABLE 表名 ADD CONSTRAINT 外鍵名稱 FOREIGN KEY(外鍵字段名) REFERENCES 主表(主表列名);#刪除外鍵 ALTER TABLE 表名 DROP FOREIGN KEY 外鍵名稱;實例:
#為emp表的dept_id字段添加外鍵,關聯dept表的id字段。ALTER TABLE emp ADD CONSTRAINT fk_emp_dept_id FOREIGN KEY(dept_id) REFERENCES dept(id); #刪除名為fk_emp_dept_id的外鍵ALTER TABLE emp DROP FOREIGN KEY fk_emp_dept_id;刪除/更新行為
| NO ACTION | 當在父表中刪除/更新對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則不允許刪除/更新。 (與 RESTRICT 一致) 默認行為 |
| RESTRICT | 當在父表中刪除/更新對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則不允許刪除/更新。 (與 NO ACTION 一致) 默認行為 |
| CASCADE | 當在父表中刪除/更新對應記錄時,首先檢查該記錄是否有對應外鍵,如果有,則也刪除/更新外鍵在子表中的記錄。 |
| SET NULL | 當在父表中刪除對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則設置子表中該外鍵值為null(這就要求該外鍵允許取null)。 |
| SET DEFAULT | 父表有變更時,子表將外鍵列設置成一個默認的值 (Innodb不支持) |
小結
多表查詢
多表關系
項目開發中,在進行數據庫表結構設計時,會根據業務需求及業務模塊之間的關系,分析并設計表結構,由于業務之間相互關聯,所以各個表結構之間也存在著各種聯系,基本上分為三種:
- 一對多(多對一)
- 多對多
- 一對一
一對多(多對一)
- 例如:部門與員工的關系、班級與學生的關系
- 關系:一個部門對應多個員工,一個班級對應多個學生
- 實現:在多的一方建立外鍵,指向一的一方的主鍵。學生(外鍵)->班級(主鍵)
多對多
- 例如:學生與課程的關系
- 關系:一個學生可以選修多門課程,一個課程可以被多個學生選修
- 實現:建立一張中間表,至少包含兩個外鍵,分別關聯兩方主鍵
一對一
- 例如:用戶與個人詳情的關系
- 關系:一對一關系,多用于單表拆分,將一張表的基礎字段放在一張表中,其他詳細字段放在另一張表中,以提升操作效率
- 實現:在任意一方添加外鍵,關聯另一方的主鍵,并且設置外鍵為唯一(UNIQUE)
多表查詢概述
- 概述:從多張表中查詢數據
- 笛卡爾積:笛卡爾乘積是指在數學中,兩個集合A和B的所有組合情況。(在多表查詢時,需要消除無效的笛卡爾積)
- 分類:
- 連接查詢
- 內連接:相當于查詢A、B交集部分數據
- 外連接:
- 左外連接:查詢左表所有數據,以及兩張表交集部分數據
- 右外連接:查詢右表所有數據,以及兩張表交集部分數據
- 自連接:當前表與自身的連接查詢,自連接必須使用表別名
- 連接查詢
內連接
語法:
#隱式內連接 SELECT 字段列表 FROM 表列表 WHERE 條件...;#顯式內連接 SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 連接條件;內連接查詢的是兩張表交集的部分
實例:
#查詢每一個員工的姓名,以及關聯的部門名稱(隱式) SELECT emp.name,dept.name FROM emp,dept WHERE emp.dept_id = dept.id;#查詢每一個員工的姓名,以及關聯的部門名稱(顯示) SELECT e.name,d.name FROM emp e INNER JOIN dept d ON e.dept_id = d.id;外連接
語法:
#左外連接 SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 條件...;#右外連接 SELECT 字段列表 FROM 表1 RIGHT [OUTER] JOIN 表2 ON 條件...;實例:
#查詢emp表的所有數據,和對應的部門信息(左外連接) SELECT * FROM emp e LEFT OUTER JOIN dept d ON e.dept_id = d.id;#查詢dept表的所有數據,和對應的員工信息(右外連接) SELECT d.*,e.* FROM emp e RIGHT OUTER JOIN dept d ON e.dept_id = d.id;自連接
語法:
SELECT 字段列表 FROM 表A 別名A JOIN 表A 別名B ON 條件...;自鏈接查詢,可以是內連接查詢,也可以是外連接查詢
實例:
#查詢員工及其直屬領導的名字 SELECT e1.name 員工,e2.name 領導 FROM emp e1 JOIN emp e2 ON e1.managerid = e2.id;#查詢所有員工emp及其領導的名字emp,如果沒有領導也要查詢出來 SELECT e1.*,e2.name 領導 FROM emp e1 LEFT JOIN emp e2 ON e1.managerid = e2.id;聯合查詢
對于UNION查詢,就是把多次查詢的結果合并起來,形成一個新的查詢結果集
語法:
SELECT 字段列表 FROM 表A ... UNION [ALL] SELECT 字段列表 FROM 表B ...;實例:
#將薪資低于5000的員工,和年齡大于50歲的員工都查詢出來。 SELECT * FROM emp WHERE salary < 5000 UNION SELECT * FROM emp WHERE age > 50 ORDER BY id ASC;- 對于聯合查詢的多張表的列數必須保持一致,字段類型也需要保持一致
- UNION ALL會直接將兩個結果集合并,而UNION會進行去重
子查詢
概念:SQL語句中嵌套SELECT語句,稱為嵌套查詢,又稱子查詢
語法:
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);子查詢外部的語句可以是INSERT/UPDATE/DELETE/SELECT的任何一個
根據子查詢結果不同,分為:
- 標量子查詢(結果為單個值)
- 列子查詢(結果為一列)
- 行子查詢(結果為一行)
- 表子查詢(結果為多行多列)
根據子查詢位置,分為:WHERE之后、FROM之后、SELECT之后
標量子查詢
子查詢返回的結果是單個值(數字、字符串、日期等),最簡單的形式,這種子查詢稱為標量子查詢。
常用操作符:=、<>、>、>=、<、<=
實例:
#查詢銷售部的所有員工信息 SELECT * FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '銷售部');#查詢方東白之后入職的員工信息 SELECT * FROM emp WHERE entrydate > (SELECT entrydate FROM emp WHERE name = '方東白');列子查詢
子查詢返回的結果是一列(可以是多行),這種子查詢稱為列子查詢
常用操作符:IN、NOT IN、ANT、SOME、ALL
| IN | 在指定的集合范圍內,多選一 |
| NOT IN | 不在指定的集合范圍之內 |
| ANY | 子查詢返回列表中,有任意一個滿足即可 |
| SOME | 與ANY相同,使用SOME的地方都可以使用ANY |
| ALL | 子查詢返回的所有值都必須滿足 |
實例:
#查詢銷售部和市場部的所有員工信息 SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE name = '銷售部' OR name = '市場部');#查詢比財務部所有人工資都高的員工信息 SELECT * FROM emp WHERE salary > ALL (SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '財務部'));#查詢比研發部其中任意一人工資高的員工信息 SELECT * FROM emp WHERE salary > ANY (SELECT salary FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '研發部'));行子查詢
子查詢返回的結果是一行(可以是多列),這種子查詢稱為行子查詢。
常用操作符:=、<>、IN、NOT IN
實例:
#查詢與張無忌的薪資及直屬領導都相同的員工 SELECT * FROM emp WHERE salary = (SELECT salary FROM emp WHERE name = '張無忌') AND managerid = (SELECT managerid FROM emp WHERE name = '張無忌'); #或 SELECT * FROM emp WHERE (salary,managerid) = (SELECT salary,managerid FROM emp WHERE name = '張無忌');表子查詢
子查詢返回的結果是多行多列,這種子查詢稱為表子查詢
常用操作符:IN
實例:
#查詢與鹿杖客、宋遠橋的職位和薪資相同的員工信息SELECT * FROM emp WHERE job IN (SELECT job FROM emp WHERE name = '鹿杖客' OR name = '宋遠橋') AND salary IN (SELECT salary FROM emp WHERE name = '鹿杖客' OR name = '宋遠橋');#查詢入職日期是2006-01-01之后的員工信息,及部門信息 SELECT e.*,d.name FROM emp e LEFT JOIN dept d ON e.dept_id = d.id WHERE e.entrydate > '2006-01-01';多表查詢案例
#查詢員工的姓名、年齡、職位、部門信息 SELECT e.name,e.age,e.job,d.name FROM emp e LEFT JOIN dept d ON e.dept_id = d.id;#查詢年齡小于30歲的員工姓名、年齡、職位、部門信息 SELECT e.name,e.age,e.job,d.name FROM emp e LEFT JOIN dept d ON e.dept_id = d.id WHERE age < 30;#查詢擁有員工的部門ID、部門名稱 SELECT d.* FROM dept d WHERE d.id IN (SELECT e.dept_id FROM emp e);#查詢所有年齡大于40的員工,及其歸屬的部門名稱;如果員工沒有分配部門,也需要展示出來 SELECT e.name,d.name FROM emp e LEFT JOIN dept d ON e.dept_id = d.id WHERE e.age > 40;#查詢所有員工的工資等級 SELECT e.name,s.grade FROM emp e,salgrade s WHERE e.salary >s.losal AND e.salary <s.hisal;#查詢研發部所有員工的信息及工資等級 SELECT e.name,s.grade FROM emp e,salgrade s WHERE e.salary >s.losal AND e.salary <s.hisal AND e.dept_id = 1;#查詢研發部員工的平均工資 SELECT AVG(salary) FROM emp WHERE dept_id = 1;#查詢工資比滅絕高的員工信息 SELECT * FROM emp WHERE salary > (SELECT salary FROM emp WHERE name = '滅絕');#查詢比平均工資高的員工信息 SELECT * FROM emp WHERE salary > (SELECT AVG(salary) FROM emp);#查詢比本部門平均工資低的員工信息 SELECT * FROM emp e2 WHERE e2.salary < (SELECT AVG(e1.salary) FROM emp e1 WHERE e1.dept_id = e2.dept_id);#查詢所有的部門信息,并統計部門的員工人數 SELECT d.id,d.name,(SELECT COUNT(*) FROM emp e WHERE e.dept_id = d.id) 人數 FROM dept d;小結
SELECT 字段列表 FROM 表列表 WHERE 條件...;
SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 連接條件;
SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 條件...;
SELECT 字段列表 FROM 表1 RIGHT [OUTER] JOIN 表2 ON 條件...;
事務
事務簡介
事務是一組操作的集合,他是一個不可分割的工作單位,事務會把所有的操作作為一個整體一起向系統提交或撤銷操作請求,即這些操作要么同時成功,要么同時失敗。
MySQL默認事務是自動提交的,也就是當執行一條DML(數據操作語言)時,MySQL會馬上隱式的提交事務。
事務操作
#表準備 drop table if exists account; create table account( id int primary key AUTO_INCREMENT comment 'ID', name varchar(10) comment '姓名', money double(10,2) comment '余額' ) comment '賬戶表'; insert into account(name, money) VALUES ('張三',2000), ('李四',2000); #張三給李四轉賬1000元#1.查詢張三賬戶余額 SELECT money FROM account WHERE name = '張三';#2.將張三賬戶余額減少1000 UPDATE account SET money = money - 1000 WHERE name = '張三';#3.將李四賬戶余額增加1000 UPDATE account SET money = money + 1000 WHERE name = '李四';查看/設置事務提交方式:
SELECT @@AUTOCOMMIT;#1--為開啟自動提交; 0--為關閉自動提交; SET @@AUTOCOMMIT = 0;#關閉自動提交提交事務:
COMMIT;回滾事務:
ROLLBACK;開啟事務:
START TRANSACTION 或 BEGIN;提交事務:
COMMIT;回滾事務:
ROLLBACK;事務四大特性(ACID)
- 原子性(Atomicity):事務是不可分割的最小操作單元,要么全部成功,要么全部失敗
- 一致性(Consistency):事務完成時,必須使所有的數據都保持一致狀態
- 隔離性(Isolation):數據庫系統提供的隔離機制,保證事務在不受外部并發操作影響的獨立環境下運行
- 持久性(Durability):事務一旦提交或回滾,它對數據庫中的數據的改變就是永久的。
并發事務問題
| 臟讀 | 一個事務讀到另一個事務還沒有提交的數據 |
| 幻讀 | 一個事務按照條件查詢數據時,沒有對應的數據行,但是在插入時,又發現這行數據已經存在了,好像出現了“幻覺” |
| 不可重復讀 | 一個事務先后讀取同一條記錄,但兩次讀取出來的數據不同,稱為不可重復讀 |
事務隔離級別
| Read Uncommitted讀未提交 | √ | √ | √ |
| Read Committed讀已提交(Orcal默認) | × | √ | √ |
| Repeatable Read可重復讀(MySQL默認) | × | × | √ |
| Serializable串行化 | × | × | × |
注意:事務隔離級別越高,數據越安全,性能越低。
小結
-
事務簡介
- 事務是一組操作的集合,他是一個不可分割的工作單位,事務會把所有的操作作為一個整體一起向系統提交或撤銷操作請求,即這些操作要么同時成功,要么同時失敗。
-
事務操作
- START TRANSACTION;#開啟事務 COMMIT/ROLLBACK;#提交或回滾
-
四大特性
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔離性(Isolation)
- 持久性(Durability)
-
并發事務問題
- 臟讀
- 幻讀
- 不可重復讀
-
事務隔離級別
- READ UNCOMMITTED讀未提交
- READ COMMITTED讀已提交
- REPEATABLE READ可重復讀
- SERIALIZABLE串行化
李四’;
提交事務:
COMMIT;回滾事務:
ROLLBACK;開啟事務:
START TRANSACTION 或 BEGIN;提交事務:
COMMIT;回滾事務:
ROLLBACK;事務四大特性(ACID)
- 原子性(Atomicity):事務是不可分割的最小操作單元,要么全部成功,要么全部失敗
- 一致性(Consistency):事務完成時,必須使所有的數據都保持一致狀態
- 隔離性(Isolation):數據庫系統提供的隔離機制,保證事務在不受外部并發操作影響的獨立環境下運行
- 持久性(Durability):事務一旦提交或回滾,它對數據庫中的數據的改變就是永久的。
并發事務問題
| 臟讀 | 一個事務讀到另一個事務還沒有提交的數據 |
| 幻讀 | 一個事務按照條件查詢數據時,沒有對應的數據行,但是在插入時,又發現這行數據已經存在了,好像出現了“幻覺” |
| 不可重復讀 | 一個事務先后讀取同一條記錄,但兩次讀取出來的數據不同,稱為不可重復讀 |
事務隔離級別
| Read Uncommitted讀未提交 | √ | √ | √ |
| Read Committed讀已提交(Orcal默認) | × | √ | √ |
| Repeatable Read可重復讀(MySQL默認) | × | × | √ |
| Serializable串行化 | × | × | × |
注意:事務隔離級別越高,數據越安全,性能越低。
小結
-
事務簡介
- 事務是一組操作的集合,他是一個不可分割的工作單位,事務會把所有的操作作為一個整體一起向系統提交或撤銷操作請求,即這些操作要么同時成功,要么同時失敗。
-
事務操作
- START TRANSACTION;#開啟事務 COMMIT/ROLLBACK;#提交或回滾
-
四大特性
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔離性(Isolation)
- 持久性(Durability)
-
并發事務問題
- 臟讀
- 幻讀
- 不可重復讀
-
事務隔離級別
- READ UNCOMMITTED讀未提交
- READ COMMITTED讀已提交
- REPEATABLE READ可重復讀
- SERIALIZABLE串行化
總結
以上是生活随笔為你收集整理的《黑马程序员 MySQL数据库入门到精通,从MySQL安装到MySQL高级、MySQL优化全囊括》——学习笔记基础篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 游戏 新手引导 设计_我认为每个新手设计
- 下一篇: 前端学习(2938):vue对象之间的实