一、MySQL基礎
黑窗口命令操作:
連接MySQL服務器:mysql -u用戶名 -p密碼 [-h數據庫服務器的IP地址 -P端口號]
?
-h 參數不加,默認連接的是本地 127.0.0.1 的MySQL服務器
-P 參數不加,默認連接的端口號是 3306
、
**上述指令,可以有兩種形式:**
密碼直接在-p參數之后直接指定。
密碼在-p回車之后,在命令行中輸入密碼,然后回車
1、對數據庫的操作
-- 展示所有的數據庫
show databases;
?
-- 創建數據庫(文件夾):
creat databases [數據庫名稱];
create database day06;//如果有相同名字的數據庫已經存在了那么程序會報錯。
create database [ if not exists ] 數據庫名;//數據庫不存在,則創建該數據庫;如果存在則不創建
?
-- 刪除數據庫語法
drop databases 數據庫名稱;//數據庫不存在將會報錯
drop database day06;
drop database [ if exists ] 數據庫名 ;//數據庫存在時刪除
?
-- 使用/切換數據庫(■ 切換文件夾意思)
use [數據庫名稱];
use day06;
?
查詢當前數據庫:
select database();
2、創建表
★ 創建表
/*語法:create table student(列名1 列的數據類型1,列名2 列的數據類型2,..........列名n 列的數據類型n);
*/
注意事項:最后一行不能有逗號。
數據類型:/*int:整數double:小數varchar(文字個數): 文字(字符串)data/datetime:日期 年月日/年月日時分秒*/
create table tb_user (id int comment 'ID,唯一標識', ? # id是一行數據的唯一標識(不能重復)username varchar(20) comment '用戶名',name varchar(10) comment '姓名',age int comment '年齡',gender char(1) comment '性別'
) comment '用戶表';
/*剛創建的表它是不存在數據的。
*/
★ /* 約束 */
● not null:非空約束限制該字段值不能為null
● unique:唯一約束保證字段的所有數據都是唯一、不重復的
● primary key:主鍵約束主鍵是一行數據的唯一標識,要求非空且唯一
● default:默認約束保存數據時,如果未指定該字段值,則采用默認值
● foreign key:外鍵約束讓兩張表的數據建立連接,保證數據的一致性和完整性
★ 注意:約束是作用于表中字段上的,可以在創建表/修改表的時候添加約束。
★ 主鍵自增:auto_increment
- 每次插入新的行記錄時,數據庫自動生成id字段(主鍵)下的值
- 具有auto_increment的數據列是一個正數序列開始增長(從1開始自增)
★ 注意:主鍵增長只會增長,不會因為成員的刪除而減少對應的值。
?
create table tb_user (id int primary key auto_increment comment 'ID,唯一標識', #主鍵自動增長username varchar(20) not null unique comment '用戶名',name varchar(10) not null comment '姓名',age int comment '年齡',gender char(1) default '男' comment '性別'
) comment '用戶表';
/******************************************************************************/
★ 數據類型:
類型 | 大小 | 有符號(SIGNED)范圍 | 無符號(UNSIGNED)范圍 | 描述 |
---|
TINYINT | 1byte | (-128,127) | (0,255) | 小整數值 |
SMALLINT | 2bytes | (-32768,32767) | (0,65535) | 大整數值 |
MEDIUMINT | 3bytes | (-8388608,8388607) | (0,16777215) | 大整數值 |
INT/INTEGER | 4bytes | (-2147483648,2147483647) | (0,4294967295) | 大整數值 |
BIGINT | 8bytes | (-2^63,2^63-1) | (0,2^64-1) | 極大整數值 |
FLOAT | 4bytes | (-3.402823466 E+38,3.402823466351 E+38) | 0 和 (1.175494351 E-38,3.402823466 E+38) | 單精度浮點數值 |
DOUBLE | 8bytes | (-1.7976931348623157 E+308,1.7976931348623157 E+308) | 0 和 (2.2250738585072014 E-308,1.7976931348623157 E+308) | 雙精度浮點數值 |
DECIMAL | | 依賴于M(精度)和D(標度)的值 | 依賴于M(精度)和D(標度)的值 | 小數值(精確定點數) |
類型 | 大小 | 描述 |
---|
CHAR | 0-255 bytes | 定長字符串(需要指定長度) |
VARCHAR | 0-65535 bytes | 變長字符串(需要指定長度) |
TINYBLOB | 0-255 bytes | 不超過255個字符的二進制數據 |
TINYTEXT | 0-255 bytes | 短文本字符串 |
BLOB | 0-65 535 bytes | 二進制形式的長文本數據 |
TEXT | 0-65 535 bytes | 長文本數據 |
MEDIUMBLOB | 0-16 777 215 bytes | 二進制形式的中等長度文本數據 |
MEDIUMTEXT | 0-16 777 215 bytes | 中等長度文本數據 |
LONGBLOB | 0-4 294 967 295 bytes | 二進制形式的極大文本數據 |
LONGTEXT | 0-4 294 967 295 bytes | 極大文本數據 |
類型 | 大小 | 范圍 | 格式 | 描述 |
---|
DATE | 3 | 1000-01-01 至 9999-12-31 | YYYY-MM-DD | 日期值 |
TIME | 3 | -838:59:59 至 838:59:59 | HH:MM:SS | 時間值或持續時間 |
YEAR | 1 | 1901 至 2155 | YYYY | 年份值 |
DATETIME | 8 | 1000-01-01 00:00:00 至 9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和時間值 |
TIMESTAMP | 4 | 1970-01-01 00:00:01 至 2038-01-19 03:14:07 | YYYY-MM-DD HH:MM:SS | 混合日期和時間值,時間戳 |
//使用mySql創建一個表
create table emp (id int unsigned primary key auto_increment comment 'ID',username varchar(20) not null unique comment '用戶名',password varchar(32) default '123456' comment '密碼',name varchar(10) not null comment '姓名',gender tinyint unsigned not null comment '性別, 說明: 1 男, 2 女',image varchar(300) comment '圖像',job tinyint unsigned comment '職位, 說明: 1 班主任,2 講師, 3 學工主管, 4 教研主管',entrydate date comment '入職時間',create_time datetime not null comment '創建時間',update_time datetime not null comment '修改時間'
) comment '員工表';
?
?
3、刪除表中數據
★ 查詢當前數據庫所有表:
show tables;
★ 查看指定表結構desc 表名 ;#可以查看指定表的字段、字段的類型、是否可以為NULL、是否存在默認值等信息
★ 查詢指定表的建表語句
show create table 表名 ;
?
刪除表 drop table [ if exists ] 表名
drop table if exists tb_emp; ?
-- 在刪除表時,表中的全部數據也會被刪除。
?
★ 查看表
-- 查看表 desc 表名稱
desc student;
-- DML的插入數據
/*insert into 表明(字段名1,字段名2)values(值1,值2)*/
insert into student (id, name, chinese, math, birthday) values (101,'杜文杰',150,150,'2023-01-02');
insert into student(id, name, chinese, math, birthday) value (102,'周星馳',0,0,'2023-01-3');
insert into student(id,chinese, math)value (104,150,140);
insert into student(id, name, chinese, math, birthday) VALUE (
105,'胡歌',130,120,'2023-01-2');
?
?
★ 條件刪除
-- 刪除
/*
delete語法:delete from 表名 where 條件注意事項:刪除一定帶條件否則就全刪了條件:=:判斷條件相同!=:不等于>:判斷大于<:判斷小于>=:<=:
*/
delete from day06.student where id = 101;
案例1:刪除tb_emp表中id為1的員工
delete from tb_emp where id = 1;刪除tb_emp表中所有員工
delete from tb_emp;
?
注意事項:
? DELETE 語句的條件可以有,也可以沒有,如果沒有條件,則會刪除整張表的所有數據。
? DELETE 語句不能刪除某一個字段的值(可以使用UPDATE,將該字段值置為NULL即可)。
? 當進行刪除全部數據操作時,會提示詢問是否確認刪除所有數據,直接點擊Execute即可。
4、增加
insert語法:
- 向指定字段添加數據:insert into 表名 (字段名1, 字段名2) values (值1, 值2);
全部字段添加數據:
insert into 表名 values (值1, 值2, ...);、
批量添加數據(指定字段):
insert into 表名 (字段名1, 字段名2) values (值1, 值2), (值1, 值2);
批量添加數據(全部字段):
insert into 表名 values (值1, 值2, ...), (值1, 值2, ...);
向tb_emp表的username、name、gender字段插入數據:
-- 因為設計表時create_time, update_time兩個字段不能為NULL,所以也做為要插入的字段
insert into tb_emp(username, name, gender, create_time, update_time)
values ('wuji', '張無忌', 1, now(), now());
向tb_emp表的所有字段插入數據:
insert into tb_emp(id, username, password, name, gender, image, job, entrydate, create_time, update_time)
values (null, 'zhirou', '123', '周芷若', 2, '1.jpg', 1, '2010-01-01', now(), now());
批量向tb_emp表的username、name、gender字段插入數據
insert into tb_emp(username, name, gender, create_time, update_time)
values ('weifuwang', '韋一笑', 1, now(), now()),('fengzi', '張三瘋', 1, now(), now());
?
Insert操作的注意事項:
1. 插入數據時,指定的字段順序需要與值的順序是一一對應的。
2. 字符串和日期型數據應該包含在引號中。
3. 插入的數據大小,應該在字段的規定范圍內。
5、修改
update語法:
update 表名 set 字段名1 = 值1 , 字段名2 = 值2 , .... [where 條件] ;
案例1:將tb_emp表中id為1的員工,姓名name字段更新為'張三'
update tb_emp set name='張三',update_time=now() where id=1;
將tb_emp表的所有員工入職日期更新為'2010-01-01'
update tb_emp set entrydate='2010-01-01',update_time=now();
?
注意事項:
1. 修改語句的條件可以有,也可以沒有,如果沒有條件,則會修改整張表的所有數據。
2. 在修改數據時,一般需要同時修改公共字段update_time,將其修改為當前操作時間。
二、DQL查詢語句
/*語法格式:
SELECT字段列表
FROM表名列表
WHERE條件列表
GROUP BY分組字段列表
HAVING分組后條件列表
ORDER BY排序字段列表
LIMIT分頁參數
*/
-- 基礎查詢:
查詢多個字段
select 字段1, 字段2, 字段3 from 表名;
select id,name,chinese,math,birthday from day06.student;
?
-- 基礎查詢(*的方式不推薦 ,不見名起意)
查詢所有字段(通配符)
select * ?from 表名;
select * from day06.student;
?
-- 設置別名
select 字段1 [ as 別名1 ] , 字段2 [ as 別名2 ] ?from 表名;
?
-- 去除重復記錄
select distinct 字段列表 from 表名;
?
-- 查詢指定列
select name,chinese from day06.student;
-- 查詢指定列并且去除重復元素,去除重復必須查詢的列的值都相同才算重復!!!!
select ?distinct name,chinese from day06.student;
select distinct name from day06.student;
?
-- 給列起別名,使用as關鍵字來起別名,而且as還可以省略!!!!
select name as 姓名, chinese 語文成績 from day06.student;
1、條件查詢
select 字段列表 from 表名 where 條件列表 ; -- 條件列表:意味著可以有多個條件構造條件的運算符分為兩類:
- 比較運算符
- 邏輯運算符
**比較運算符** **功能**
> 大于
>= 大于等于
< 小于
<= 小于等于
= 等于
<> 或 != 不等于
between ... and ... 在某個范圍之內(含最小、最大值)
in(...) 在in之后的列表中的值,多選一
like 占位符 模糊匹配(_匹配單個字符, %匹配任意個字符)
is null 是null
-- ****************************************************************************** --
常用的邏輯運算符如下:
**邏輯運算符** **功能**
and 或 && 并且 (多個條件同時成立)
or 或 || 或者 (多個條件任意一個成立)
not 或 ! 非 , 不是
2、聚合函數
語法:
select 聚合函數(字段列表) from 表名 ;
/*************************************************************************/
函數===============功能
count :按照列去統計有多少行數據。
sum : 計算指定列的數值和,如果不是數值類型,那么計算結果為0
max : 計算指定列的最大值
min : 計算指定列的最小值
avg : 計算指定列的平均值
注意 : 聚合函數會忽略空值,對NULL值不作為統計。-- count 不會對null值進計算的。
select count(gender) from tb_emp;
-- 獲取總數據量的方式
select count('1') from tb_emp;
select count('*') from tb_emp;
-- 推薦使用-- 獲取某條的最小值
select min(entrydate) from tb_emp;
-- 獲取某條的最大值
select max(entrydate) from tb_emp;
-- 獲取某條的平均值
select avg(id) from tb_emp;
-- 求取某條總和
select sum(id) from tb_emp;
3、分組查詢
● 分組: 按照某一列或者某幾列,把相同的數據進行合并輸出。
● 分組其實就是按列進行分類(指定列下相同的數據歸為一類),然后可以對分類完的數據進行合并計算。
分組查詢通常會使用聚合函數進行計算。
● 語法:
select 字段列表 from 表名 [where 條件] group by 分組字段名 [having 分組后過濾條件];> 注意事項:
> ? 分組之后,查詢的字段一般為聚合函數和分組字段,查詢其他字段無任何意義
> ? 執行順序:where > 聚合函數 > having ★★★ where與having區別:- 執行時機不同:where是分組之前進行過濾,不滿足where條件,不參與分組;而having是分組之后對結果進行過濾。
- 判斷條件不同:where不能對聚合函數進行判斷,而having可以。-- 根據性別分組
select gender, count(*) from tb_emp group by gender;-- 對入職時間在2015-01-01之前的職位進行分組
select job, count(*) from tb_emp where entrydate <= '2015-01-01' group by job;-- 上一條的數量大于等于的的組數
select job, count(*) from tb_emp where entrydate <= '2015-01-01' group by job having count(*) >= 2;
4、排序查詢
有升序排序,也有降序排序。
select 字段列表 from 表名 [where 條件列表] [group by 分組字段 ] order by 字段1 排序方式1 , 字段2 排序方式2 … ;★ 排序方式:
- ASC :升序(默認值)
- DESC:降序
-- 按照入職時間進行升序排列
select *from tb_emp order by entrydate asc;
-- 按照入職時間進行降序排列
select *from tb_emp order by entrydate desc;
-- 按照入職時間進行升序排列,當入職時間相同時,按照更新時間進行降序排列
select *from tb_emp order by entrydate asc, update_time desc;
注意事項:如果是升序, 可以不指定排序方式ASC
注意事項:如果是多字段排序,當第一個字段值相同時,才會根據第二個字段進行排序
5、分頁查詢
select 字段列表 from 表名 limit 起始索引, 查詢記錄數 ;
從起始索引0開始查詢員工數據, 每頁展示5條記錄
select id, username, password, name, gender, image, job, entrydate, create_time, update_time
from tb_emp
limit 0 , 5; -- 從索引0開始,向后取5條記錄
-- limit 5; 如果查詢的是第1頁數據,起始索引可以省略,直接簡寫為:limit 條數注意事項:1. 起始索引從0開始。
計算公式 :起始索引=(查詢頁碼 - 1)* 每頁顯示記錄數2. 分頁查詢是數據庫的方言,不同的數據庫有不同的實現,MySQL中是LIMIT3. 如果查詢的是第一頁數據,起始索引可以省略,直接簡寫為 limit 條數-- 分頁查詢
-- 查詢第一頁五條數據
select *from tb_emp
limit 0,5;
-- 查詢第二頁5條數據
select *from tb_emp
limit 5,5;select *from tb_emp where name like '張%' and gender = 1 and entrydate between '2000-01-01' and '2015-12-31'
limit 0,10;
select *from tb_emp where name like '%張%' and gender = 1 and entrydate between '2000-01-01' and '2015-12-31'
limit 0,10;
-- ***************************************************************************
-- if(條件表達式, true取值 , false取值)
select if(gender=1,'男性員工','女性員工') AS 性別, count(*) AS 人數
from tb_emp
group by gender;> if(表達式, tvalue, fvalue) :當表達式為true時,取值tvalue;當表達式為false時,取值fvalue-- case 表達式 when 值1 then 結果1 when 值2 then 結果2 ... else result end
select (case jobwhen 1 then '班主任'when 2 then '講師'when 3 then '學工主管'when 4 then '教研主管'else '未分配職位'end) AS 職位 ,count(*) AS 人數
from tb_emp
group by job;case 表達式 when 值1 then 結果1 [when 值2 then 結果2 ...] [else result] end在實際開發中,盡量避免用到if或者case when then end,因為這種相當于是邏輯判斷的工作最好交給代碼業務層來處理,而不是數據庫
三、多表設計
1、一對多,一對一,多對多
一對多(One-to-Many)是指數據庫關系模型中的一種關聯關系,表示一個實體(表)的記錄對應多個關聯實體(表)的記錄。這種關系常見于現實生活中的許多場景,比如一個部門可以有多個員工,一個訂單可以有多個訂單項等。在MySQL中,可以通過在一方表(通常是“一”那一方)中添加一個外鍵列來實現一對多關系。該外鍵列指向多方(通常是“多”那一方)的主鍵列。外鍵(Foreign Key)是數據庫中用于建立表之間關聯關系的一種約束。它定義在一個表中的字段(或一組字段),它引用另一個表中的主鍵(或唯一鍵),用于創建表之間的關系。★ 外鍵的作用如下:1、建立關系:外鍵可以用來建立表之間的關系,定義了兩個表之間的連接點。通過外鍵,可以將一個表的數據與另一個表的數據關聯起來。2、數據完整性:外鍵約束可以保證數據的完整性和一致性。當設置外鍵約束后,只能插入與外鍵關聯表中存在的值。這樣可以防止插入無效的值以及避免產生孤立的數據。4、數據一致性維護:外鍵約束可以確保數據的一致性。如果外鍵表中的數據發生變動,例如刪除了某個主鍵值,那么在引用該主鍵的其他表中的對應外鍵值將會受到限制或自動更新,以保持數據的一致性。★ 使用外鍵時需要注意以下幾點:1、主鍵和外鍵的類型要匹配:外鍵字段的數據類型必須與所引用表的主鍵(或唯一鍵)的數據類型相匹配。2、外鍵的索引:為了提高查詢性能,建議為外鍵字段創建索引。這樣可以加快關聯查詢的速度。3、外鍵約束的創建和刪除:外鍵約束可以在創建表時定義,也可以在表創建后通過ALTER TABLE語句來添加。當不再需要外鍵約束時,可以使用ALTER TABLE語句來刪除。4、級聯操作:在定義外鍵時,可以指定級聯操作。比如當刪除主表(被引用表)的某行時,可以選擇級聯刪除或級聯更新相關的外鍵表中的數據。★ 外鍵約束的語法:
-- 創建表時指定
create table 表名(字段名 數據類型,...[constraint] [外鍵名稱] foreign key (外鍵字段名) references 主表 (主表列名)
);-- 建完表后,添加外鍵
alter table 表名 add constraint 外鍵名稱 foreign key(外鍵字段名) references 主表(主表列名);-- 修改表: 添加外鍵約束
alter table tb_emp
add constraint fk_dept_id foreign key (dept_id) references tb_dept(id);-- ===========================================================================
物理外鍵和邏輯外鍵:
- 物理外鍵- 概念:使用foreign key定義外鍵關聯另外一張表。- 缺點:- 影響增、刪、改的效率(需要檢查外鍵關系)。- 僅用于單節點數據庫,不適用與分布式、集群場景。- 容易引發數據庫的死鎖問題,消耗性能。- 邏輯外鍵- 概念:在業務層邏輯中,解決外鍵關聯。- 通過邏輯外鍵,就可以很方便的解決上述問題。在現在的企業開發中,很少會使用物理外鍵,都是使用邏輯外鍵。 甚至在一些數據庫開發規范中,會明確指出禁止使用物理外鍵 foreign key ★ 總結:外鍵是一種數據庫約束,用于建立表之間的關系和維護數據的完整性。通過外鍵,可以實現多表之間的關聯查詢和確保數據的一致性。在設計數據庫時,合理使用外鍵可以提高數據的質量和可靠性。在數據庫中,通過外鍵(Foreign Key)關聯表之間的數據是一種常見的數據庫設計模式。下面是創建外鍵的方式示例,包括一對多(One-to-Many)、一對一(One-to-One)和多對多(Many-to-Many)的關系:★ 一對多關系:在一對多關系中,一個實體(表)的記錄對應多個關聯實體(表)的記錄。在創建外鍵時,需將多方表中的外鍵指向一方表的主鍵(或唯一鍵)。 ★ 一對一關系:在一對一關系中,一個實體(表)的記錄對應一個關聯實體(表)的記錄。在創建外鍵時,需將兩個表中的主鍵和外鍵進行關聯。★ 多對多關系:在多對多關系中,一個實體(表)的記錄可以與多個關聯實體(表)的記錄發生多次關聯。通常需要通過中間表來實現多對多關系,中間表中包含兩個表的主鍵作為外鍵。★ 注意事項:在創建外鍵時,需要確保被引用的列(主鍵或唯一鍵)在引用前已經創建好。此外,根據數據庫引擎的不同,外鍵的創建方式可能會有所差異。某些數據庫引擎還可能需要啟用外鍵約束的支持。★ 在插入數據時,如果存在一對多關系,需要注意以下幾點:1. 確保主鍵存在:在插入“一”方表的數據之前,必須確保對應的主鍵值已經存在于“一”方表中。否則,在插入“多”方表時將無法引用有效的外鍵值。2. 設置外鍵值:在插入“多”方表的數據時,需要設置外鍵字段的值與對應的“一”方表的主鍵值相匹配。這樣才能建立起正確的一對多關系。3. 維護數據一致性:插入數據時要確保數據的一致性。也就是說,插入的數據必須符合外鍵約束,即外鍵字段的值必須存在于被引用表的主鍵中。否則,將會引發外鍵約束錯誤。4. 使用事務:對于一對多關系的插入操作,建議使用事務來確保操作的原子性和一致性。在事務中,可以確保要么所有的插入操作都成功,要么全部失敗回滾,以保持數據的完整性。示例:
假設有一個部門表(departments)和一個員工表(employees),一個部門可以有多個員工。在插入員工數據時,需要注意以下事項:1. 確保部門存在:在插入員工數據之前,先確保對應的部門已經存在于部門表中,這樣才能設置正確的外鍵值。2. 設置外鍵值:在插入員工表時,設置外鍵字段(比如department_id)的值與對應的部門表中的主鍵值相匹配,以便與部門建立正確的關聯關系。3. 維護數據一致性:插入員工數據時,要確保設置的department_id值在部門表中存在,以滿足外鍵約束。否則,插入操作將失敗。4. 使用事務(可選):如果涉及到同時插入部門和員工數據,可以使用事務來確保操作的一致性。這樣可以保證要么同時成功插入,要么回滾到初始狀態。總之,插入一對多關系的數據時,需要確保參與關聯的表和字段的一致性,合理設置外鍵值,以及使用事務(如果需要)來保證數據的完整性和一致性。★ 在刪除一對多關系的數據時,需要注意以下幾點:1. 處理相關聯的數據:在刪除“一”方表的數據之前,需要考慮和處理對應的“多”方表的數據。如果存在外鍵關聯,“多”方表的數據可能會依賴于“一”方表的數據。因此,在刪除“一”方表的數據之前,需要先刪除或更新相關聯的“多”方表的數據。2. 外鍵約束:刪除數據時,要遵守外鍵約束。確保要刪除的數據沒有被其他表的外鍵引用,否則數據庫可能會拒絕刪除操作。此時,可以選擇級聯刪除或將外鍵設置為 NULL 值,或者先更新外鍵引用,再進行刪除操作。3. 事務處理:如果涉及到多個表的刪除操作,建議使用事務來確保所有操作的原子性和一致性。在事務中,要么所有的刪除操作都成功,要么全部失敗回滾,以保持數據的完整性。示例:
假設有一個部門表(department)和一個員工表(employee),一個部門可以有多個員工。在刪除部門數據時,需要注意以下事項:1. 處理相關聯的員工數據:在刪除部門數據之前,需要先刪除或更新與該部門關聯的員工表中的數據。可以根據需求,選擇級聯刪除相關的員工數據,或者將員工的部門外鍵設為 NULL 或默認值。2. 遵守外鍵約束:確保要刪除的部門數據不被其他表的外鍵所引用。如果存在其他表中的外鍵引用了部門表的數據,需要先處理這些引用,才能順利刪除部門數據。3. 事務處理(可選):如果需要確保刪除操作的一致性,可以使用事務來包裹刪除部門和員工數據的操作,以確保要么全部成功刪除,要么全部回滾。總之,在刪除一對多關系的數據時,需要首先處理相關聯的數據,遵守外鍵約束,并考慮使用事務來保證操作的一致性和原子性。這樣可以確保數據關聯性的正確性和數據的完整性。
2、多表查詢
多表查詢:查詢時從多張表中獲取所需數據> 單表查詢的SQL語句:select 字段列表 from 表名;
> 那么要執行多表查詢,只需要使用逗號分隔多張表即可,如: select 字段列表 from 表1, 表2;
select * from tb_emp , tb_dept;
查詢結果中包含了大量的結果集,總數 = tb_emp條數 * tb_dept的總條數,這種現象稱之為笛卡爾積。
消除卡爾積的方式:給多表查詢加上連接查詢的條件即可。
select * from tb_emp , tb_dept where tb_emp.dept_id = tb_dept.id ;連接查詢
1. 內連接:內連接查詢:查詢兩表或多表中交集部分數據。內連接從語法上可以分為:- 隱式內連接:select 字段列表 from 表1 , 表2 where 條件 ... ;
/***************************************************************************/
select tb_emp.name , tb_dept.name -- 分別查詢兩張表中的數據
from tb_emp , tb_dept -- 關聯兩張表
where tb_emp.dept_id = tb_dept.id; -- 消除笛卡爾積- 顯式內連接:select 字段列表 from 表1 [ inner ] join 表2 on 連接條件 ... ;
/***************************************************************************/
select tb_emp.name , tb_dept.name from tb_emp inner join tb_dept on tb_emp.dept_id =
tb_dept.id;
注意事項:一旦為表起了別名,就不能再使用表名來指定對應的字段了,此時只能夠使用別名來指定字段。
/************************************************************************************/2. 外連接- 左外連接:查詢左表所有數據(包括兩張表交集部分數據)
select 字段列表 from 表1 left [ outer ] join 表2 on 連接條件 ... ;
左外連接相當于查詢表1(左表)的所有數據,當然也包含表1和表2交集部分的數據。
-- 左外連接:以left join關鍵字左邊的表為主表,查詢主表中所有數據,以及和主表匹配的右邊表中的數據
select emp.name , dept.name
from tb_emp AS emp left join tb_dept AS dept on emp.dept_id = dept.id;- 右外連接:查詢右表所有數據(包括兩張表交集部分數據)
select 字段列表 from 表1 right [ outer ] join 表2 on 連接條件 ... ;
右外連接相當于查詢表2(右表)的所有數據,當然也包含表1和表2交集部分的數據。- 右外連接
select dept.name , emp.name from tb_emp AS emp right join tb_dept AS dept on emp.dept_id = dept.id;
3、子查詢
子查詢
SQL語句中嵌套select語句,稱為嵌套查詢,又稱子查詢。
SELECT * FROM t1 WHERE column1 = ( SELECT column1 FROM t2 ... );
子查詢外部的語句可以是insert / update / delete / select 的任何一個,最常見的是 select。根據子查詢結果的不同分為:
1. 標量子查詢(子查詢結果為單個值[一行一列])子查詢返回的結果是單個值(數字、字符串、日期等),最簡單的形式,這種子查詢稱為標量子查詢。
常用的操作符: = <> > >= < <=
可以將需求分解為兩步:
1. 查詢 "教研部" 部門ID
2. 根據 "教研部" 部門ID,查詢員工信息
-- 1.查詢"教研部"部門ID
select id from tb_dept where name = '教研部'; #查詢結果:2
-- 2.根據"教研部"部門ID, 查詢員工信息
select * from tb_emp where dept_id = 2;-- 合并出上兩條SQL語句
select * from tb_emp where dept_id = (select id from tb_dept where name = '教研部');
-- *********************************************************************************************
2. 列子查詢(子查詢結果為一列,但可以是多行)
子查詢返回的結果是一列(可以是多行),這種子查詢稱為列子查詢。
常用的操作符:**操作符** **描述** IN 在指定的集合范圍之內,多選一 NOT IN 不在指定的集合范圍之內 案例:查詢"教研部"和"咨詢部"的所有員工信息> 分解為以下兩步:> 1. 查詢 "銷售部" 和 "市場部" 的部門ID
> 2. 根據部門ID, 查詢員工信息
-- 1.查詢"銷售部"和"市場部"的部門ID
select id from tb_dept where name = '教研部' or name = '咨詢部'; #查詢結果:3,2
-- 2.根據部門ID, 查詢員工信息
select * from tb_emp where dept_id in (3,2);-- 合并以上兩條SQL語句
select * from tb_emp where dept_id in (select id from tb_dept where name = '教研部' or name = '咨詢部');
-- ******************************************************************************************
3. 行子查詢(子查詢結果為一行,但可以是多列)
子查詢返回的結果是一行(可以是多列),這種子查詢稱為行子查詢。常用的操作符:= 、<> 、IN 、NOT IN案例:查詢與"韋一笑"的入職日期及職位都相同的員工信息
> 可以拆解為兩步進行:
>
> 1. 查詢 "韋一笑" 的入職日期 及 職位
> 2. 查詢與"韋一笑"的入職日期及職位相同的員工信息 -- 查詢"韋一笑"的入職日期 及 職位
select entrydate , job from tb_emp where name = '韋一笑'; #查詢結果: 2007-01-01 , 2
-- 查詢與"韋一笑"的入職日期及職位相同的員工信息
select * from tb_emp where (entrydate,job) = ('2007-01-01',2);-- 合并以上兩條SQL語句
select * from tb_emp where (entrydate,job) = (select entrydate , job from tb_emp where name = '韋一笑');
-- *****************************************************************************************4. 表子查詢(子查詢結果為多行多列[相當于子查詢結果是一張表])子查詢返回的結果是多行多列,常作為臨時表,這種子查詢稱為表子查詢。案例:查詢入職日期是 "2006-01-01" 之后的員工信息 , 及其部門信息> 分解為兩步執行:
> 1. 查詢入職日期是 "2006-01-01" 之后的員工信息
> 2. 基于查詢到的員工信息,在查詢對應的部門信息
select * from emp where entrydate > '2006-01-01';select e.*, d.* from (select * from emp where entrydate > '2006-01-01') e left join dept d on e.dept_id = d.id ;
-- ************************************************************************************************子查詢可以書寫的位置:
1. where之后
2. from之后
3. select之后
四、事務
★ 事務是一組操作的集合,它是一個不可分割的工作單位。事務會把所有的操作作為一個整體一起向系統提交或撤銷操作請求,即這些操作要么同時成功,要么同時失敗。★ 事務作用:保證在一個事務中多次操作數據庫表中數據時,要么全都成功,要么全都失敗。例如:
-- 刪除學工部
delete from dept where id = 1; -- 刪除成功-- 刪除學工部的員工
delete from emp where dept_id = 1; -- 刪除失敗(操作過程中出現錯誤:造成刪除沒有成功)其中員工并沒有被刪除,但是因為刪除了學工部,從而無法獲得學工部的員工信息,于是就成為了數據垃圾。MYSQL中有兩種方式進行事務的操作:1. 自動提交事務:即執行一條sql語句提交一次事務。(默認MySQL的事務是自動提交)
2. 手動提交事務:先開啟,再提交 事務操作有關的SQL語句:SQL語句 描述
start transaction;/ begin ; 開啟手動控制事務 commit; 提交事務 rollback; 回滾事務 手動提交事務使用步驟:
- 第1種情況:開啟事務 => 執行SQL語句 => 成功 => 提交事務
- 第2種情況:開啟事務 => 執行SQL語句 => 失敗 => 回滾事務-- 開啟事務
start transaction ;
-- 刪除學工部
delete from tb_dept where id = 1;
-- 刪除學工部的員工
delete from tb_emp where dept_id = 1;
-- 提交事務 (成功時執行)
commit ;
-- 回滾事務 (出錯時執行)
rollback ;
1、事務四大特性
★★★ 面試題:事務有哪些特性?● 1、原子性(Atomicity) :原子性是指事務包裝的一組sql是一個不可分割的工作單元,事務中的操作要么全部成功,要么全部失敗。
● 2、一致性(Consistency):一個事務完成之后數據都必須處于一致性狀態。? 如果事務成功的完成,那么數據庫的所有變化將生效。? 如果事務執行出現錯誤,那么數據庫的所有變化將會被回滾(撤銷),返回到原始狀態。
● 3、隔離性(Isolation):多個用戶并發的訪問數據庫時,一個用戶的事務不能被其他用戶的事務干擾,多個并發的事務之間要相互隔離。? 一個事務的成功或者失敗對于其他的事務是沒有影響。
● 4、持久性(Durability):一個事務一旦被提交或回滾,它對數據庫的改變將是永久性的,哪怕數據庫發生異常,重啟之后數據亦然存在。> 事務的四大特性簡稱為:ACID
五、數據庫的優化方式
數據庫優化是一種提高數據庫性能和效率的過程,可以采取以下方式進行數據庫優化:1. 優化數據庫設計:- 合理設計數據庫模式,包括表的結構、關系和索引的設計,以適應實際的業務需求。- 規范化數據庫,消除數據冗余,減少數據的存儲空間和提高查詢效率。- 使用適當的數據類型和字段大小,避免過度使用或浪費存儲空間。2. 優化查詢:- 使用合適的索引,以加快查詢速度。在頻繁查詢的列上建立索引,但避免過多的索引,以免降低寫操作的性能。- 使用合適的查詢語句,優化 SQL 語句的編寫,避免不必要的計算和漫長的查詢。- 避免使用 SELECT * 查詢所有列,只選擇需要的列,減少數據的傳輸量。- 調整查詢順序,使用連接(Join)等技術,減少查詢的復雜性。3. 硬件和系統優化:- 配置適當的硬件資源,包括 CPU、內存、磁盤和網絡等,以滿足數據庫的需求。- 針對具體數據庫系統,調整和優化相關的參數設置,以提高性能和并發能力。- 定期維護數據庫,包括備份、數據清理、重建索引等操作,保持數據庫的健康狀態。4. 緩存和緩沖優化:- 使用緩存技術,將常用的數據存儲在內存中,減少對磁盤的訪問,從而提高讀取速度。- 配置適當的緩沖區大小,優化緩沖區的管理和利用,減少讀寫操作對磁盤的直接訪問。5. 優化事務管理:- 合理劃分事務的粒度,盡量減少事務的持有時間和范圍,以提高并發處理能力并減輕鎖的爭用。- 對于批量處理或大量數據操作,考慮使用批量提交或分批處理的方式,減少事務的開銷和資源占用。6. 查詢性能監控和調優:- 使用數據庫監控工具,對數據庫的查詢性能進行監控和分析,找出慢查詢和瓶頸,并進行針對性的調優。- 使用性能測試工具模擬負載,進行壓力測試和性能測試,評估數據庫的性能瓶頸和擴展能力。數據庫優化是一個持續的過程,需要不斷地監控和調整,根據實際情況進行優化。同時,也要根據具體的數據庫系統和應用場景,采取相應的優化策略和技術手段。
1、索引
索引(index):是幫助數據庫高效獲取數據的數據結構 。- 簡單來講,就是使用索引可以提高查詢的效率。
優點:1. 提高數據查詢的效率,降低數據庫的IO成本。
2. 通過索引列對數據進行排序,降低數據排序的成本,降低CPU消耗。
缺點:1. 索引會占用存儲空間。
2. 索引大大提高了查詢效率,同時卻也降低了insert、update、delete的效率。MySQL數據庫支持的索引結構有很多,如:Hash索引、B+Tree索引、Full-Text索引等。如果沒有特別指明,都是指默認的 B+Tree 結構組織的索引。采用二叉搜索樹或者是紅黑樹來作為索引的結構有什么問題?說明:如果數據結構是紅黑樹,那么查詢1000萬條數據,根據計算樹的高度大概是23左右,這樣確實比之前的方式快了很多,但是如果高并發訪問,那么一個用戶有可能需要23次磁盤IO,那么100萬用戶,那么會造成效率極其低下。所以為了減少紅黑樹的高度,那么就得增加樹的寬度,就是不再像紅黑樹一樣每個節點只能保存一個數據,可以引入另外一種數據結構,一個節點可以保存多個數據,這樣寬度就會增加從而降低樹的高度。這種數據結構例如BTree就滿足。
-- ***************************************************************************B+Tree結構:- 每一個節點,可以存儲多個key(有n個key,就有n個指針)
- 節點分為:葉子節點、非葉子節點- 葉子節點,就是最后一層子節點,所有的數據都存儲在葉子節點上- 非葉子節點,不是樹結構最下面的節點,用于索引數據,存儲的的是:key+指針
- 為了提高范圍查詢效率,葉子節點形成了一個雙向鏈表,便于數據的排序及區間范圍查詢-- *************************************************************************************************
**拓展:**非葉子節點都是由key+指針域組成的,一個key占8字節,一個指針占6字節,而一個節點總共容量是16KB,那么可以計算出一個節點可以存儲的元素個數:16*1024字節 / (8+6)=1170個元素。- 查看mysql索引節點大小:show global status like 'innodb_page_size'; -- 節點大小:16384當根節點中可以存儲1170個元素,那么根據每個元素的地址值又會找到下面的子節點,每個子節點也會存儲1170個元素,那么第二層即第二次IO的時候就會找到數據大概是:1170*1170=135W。也就是說B+Tree數據結構中只需要經歷兩次磁盤IO就可以找到135W條數據。對于第二層每個元素有指針,那么會找到第三層,第三層由key+數據組成,假設key+數據總大小是1KB,而每個節點一共能存儲16KB,所以一個第三層一個節點大概可以存儲16個元素(即16條記錄)。那么結合第二層每個元素通過指針域找到第三層的節點,第二層一共是135W個元素,那么第三層總元素大小就是:135W*16結果就是2000W+的元素個數。結合上述分析B+Tree有如下優點:- 千萬條數據,B+Tree可以控制在小于等于3的高度
- 所有的數據都存儲在葉子節點上,并且底層已經實現了按照索引進行排序,還可以支持范圍查詢,葉子節點是一個雙向鏈表,支持從小到大或者從大到小查找查看索引信息:
show index from 表名;
show index from tb_emp;
刪除索引
drop index 索引名 on 表名;
drop index idx_emp_name on tb_emp;注意事項:
- 主鍵字段,在建表時,會自動創建主鍵索引
- 添加唯一約束時,數據庫實際上會添加唯一索引