系列文章目錄
MySQL的基礎操作-CSDN博客
目錄
系列文章目錄
前言
一、數據庫的約束
1. 約束類型:not null
2. 約束類型:unique
3. 約束類型:default
4. 約束類型:primary key
5. 約束條件:foreign key
二、表的設計
1. 一對一
2. 一對多
3. 多對多
三、查詢操作進階
1. 插入搭配查詢
2. 聚合查詢
1. sql 中的聚合函數
2. group by
3. 聯合查詢
1. 內連接
2. 外連接
3. 自連接?
4. 子查詢
5. 合并查詢
前言
本文介紹了MySQL數據庫的基礎操作,主要包括三個方面內容:數據庫約束、表設計和查詢操作進階。數據庫約束部分詳細講解了NOT NULL、UNIQUE、DEFAULT、PRIMARY KEY和FOREIGN KEY五種約束類型的作用和使用方法。表設計部分闡述了如何根據需求場景設計表結構,重點分析了一對一、一對多和多對多三種關系的實現方式。查詢操作進階部分介紹了聚合查詢、分組查詢、聯合查詢(內連接、外連接、自連接)、子查詢和合并查詢等高級查詢技巧,特別強調了在數據量大時聯合查詢可能帶來的性能問題。全文通過大量SQL示例代碼,系統性地講解了MySQL數據庫的基礎操作知識。
一、數據庫的約束
數據庫的約束:數據庫自動對數據的合法性進行校驗檢查的一系列機制;
目的:保證數據庫中避免被插入或修改一些非法數據;
1. 約束類型:not null
?not null:指示某列不能存儲 null 值;
create table 表名 (列名 not null, 列名...);
2. 約束類型:unique
unique:保證某列的每行必須有唯一的值;
create table 表名 (列名 unique, 列名...);
unique 約束會讓后續插入數據,修改數據的時候都先觸發一次查詢操作,通過這個查詢操作來確認當前這個記錄是否已經存在;
3. 約束類型:default
?default:規定沒有給列賦值時的默認值;
create table 表名 (列名 default "默認值", 列名...);
?default 主要應用于指定列插入,未被指定的列會使用默認值;
4. 約束類型:primary key
primary key:not null 和 unique 的結合,確保某列有唯一標識,有助于快速查詢到表中的特定記錄;
create table 表名 (列名 primary key, 列名...);
primary key 最重要的約束,是一行數據記錄的身份標識;
一張表里面只能有一個 primary key;一張表里的記錄,只能有一個作為身份標識的數據;
對于帶有主鍵的表,每次插入修改數據也會涉及到進行先查詢的操作;
mysql 會把帶有 primary key 和 unique 的列自動生成索引,從而加快查詢速度;
保證主鍵唯一的方式:自增主鍵
不手動指定主鍵值,由數據庫和服務器自動分配,服務器會從 1 開始,依次遞增分配主鍵的值;
- 插入數據時,可以將設置為自增主鍵的列設置為 null,表示由服務器自動分配;
- 插入數據時,也可以手動指定主鍵的值;
- 手動指定主鍵值插入后,再插入下一個數據,如果不手動指定,主鍵就從當前主鍵的最大值加 1 開始,向后分配;
如果是分布式系統,如何保證生成的主鍵唯一?
- 1. 如果插入數據的速度比較慢,通常是通過時間戳,就能保證生成的主鍵唯一;
- 2. 如果插入數據速度很塊,就需要時間戳拼接機房編號/主機編號,落在不同主機上的數據也能保證主鍵唯一;
- 3. 如果數據是插入到同一臺機器上,還需要在上述基礎上拼接一個隨機因子,保證插入數據的主鍵唯一;
5. 約束條件:foreign key
foreign key:保證表中的數據匹配另一個表中的值的參照完整性;
create table 表名2(列名1,列名2..., foreign key (列名1) references 表名2(列名1));
描述了兩個表之間的關聯關系,用于約束的表叫做父表(表名2),被約束的表叫做子表(表名1);?
插入數據時,服務器會先觸發一次查詢操作,查看被外鍵約束的列的值是否在父表對應的列中存在;
父表對子表的約束要注意:
- 1. 子表中插入或者修改數據時,被約束的列的值要在父表對應的列中存在;
- 2. 父表中刪除數據時,要保證該數據沒有在子表中用到;
- 3. 即使子表為空,也不能刪除父表,因為新插入數據時還需要參考父表;
- 4. 指定外鍵約束的時候,要求父表被關聯的這一列得是主鍵或者 unique;
注意事項:
數據庫引入約束之后,執行效率就會受到影響,就可能會降低很多;
二、表的設計
根據實際的需求場景,明確當前要創建幾個表,每個表都有哪些列,這些表之間是否存在一定的聯系。
1. 梳理好需求中的實體;
2. 再確定好實體間的關系(一對一,一對多,多對多);
1. 一對一
例如:一用戶只能擁有一個賬號;一個賬號也只能被一個用戶擁有;
-- 一個用戶只能擁有一個賬號
user(userId, name, acountId);-- 一個賬戶也只能被一個用戶擁有
acount(acountId, username, password, userId);
2. 一對多
例如:一個用戶只能在一個地區;一個地區,可以包含多個用戶;
-- 一個用戶只能有一個地區
user(userId, username, address);-- 一個地區可以有多個用戶
address(addressId, addressName);
3. 多對多
?一個用戶可以選擇多個游戲,一個游戲可以有多個用戶;
-- 一個用戶可以參與多個游戲
user(userId, username);-- 一個游戲可以有多個用戶
game(gameId, gameName);-- 借助關聯表表示
user_game(userId, gameId);
三、查詢操作進階
1. 插入搭配查詢
把查詢語句的結果,作為插入的數值;
-- 插入搭配查詢
insert into 表1 select * from 表2;
要求查詢出來的結果集合,列數和類型要和要插入的表匹配;
2. 聚合查詢
表達式查詢是針對列和列之間運算;
聚合查詢是針對行和行之間運算;
1. sql 中的聚合函數
1. count:查詢出來的結果集的行數;
-- 查詢總的行數
select count(*) from 表名;-- 查詢有多少列不為空的行數
select count(列名) from 表名;-- 查詢列不重復的行數
select count(distinct 列名) from 表名;
count 里面填寫的是 *,表示查詢的是總的行數;
如果 count 里面填寫的是列名,遇到空行就不統計了;
同時 count 里面可以填寫 distinct 和列名,統計不重復的行數;??
count 在代碼中調用是非常有必要的;
2. sum:把某一列的若干行進行求和運算;
-- 針對某一列求和
select sum(列名) from 表名;-- 針對表達式求和
select sum(表達式) from 表名;
如果列的值為 null,就會被自動排除掉;
求和時 mysql 會嘗試把列轉換為 double,如果轉換成功,就可以進行運算,如果沒轉成就會報錯;
針對表達式求和時,會先求表達式的值,得到臨時表,再針對臨時表求和;
avg,max,min 用法和 sum 相同;
2. group by
使用 group by 分組,再針對每個組分別進行聚合查詢;
針對列進行分組,把這一列中值相同的行,分成到一組中,得到若干個組;
再針對這些組,分別使用聚合函數;
-- 分組聚合查詢
select 列名1, avg(列名2) from 表名 group by 列名1;
如果針對分組之后,不適用聚合函數,此時的結果就是查詢出每一組中的某個代表數據;
因此,分組通常時搭配聚合函數使用的;?
使用 group by 的時候,還可以搭配條件,但是需要區分清楚是分組之前的條件還是分組之后的條件;
分組之前:條件在 group by 前面,用 where
-- 聚合查詢搭配條件:分組之前
select 列名1, avg(列名2) from 表名 where 條件 group by 列名1;
分組之后:條件在 group by 后面,用 having
-- 聚合查詢搭配條件:分組之后
select 列名1, avg(列名2) from 表名 group by 列名1 having 條件;
分組前后都有條件: 分組前使用 where,分組后使用 having
-- 分組前后都有條件,分組前條件用 where,分組后條件用 having
select 列名1, avg(列名2) from 表名 where 條件1 group by 列名1 having 條件2;
3. 聯合查詢
1. 內連接
笛卡爾積是將兩張表的行通過排列組合的方式,得到一個更大的表;
笛卡爾積的列數,是這兩個表的列數相加;
笛卡爾積的行數,是這兩個表的行數相乘;
-- 笛卡爾積
select * from 表1, 表2;
笛卡爾積的基礎上,加上連接條件:
-- 加上連接條件
select * from 表1, 表2 where 表1.列名 = 表2.列名;select * from 表1 join 表2 on 表1.列名 = 表2.列名;
?在上述基礎上,添加條件(聚合查詢等),對數據進行篩選:
-- 添加條件篩選數據
select * from 表1, 表2 where 表1.列名 = 表2.列名 and 條件;select * from 表1 join 表2 on 表1.列名 = 表2.列名 and 條件;-- 多張表聯合查詢
select 列名1, 列名2, 列名3... from 表1, 表2, 表3... where 連接條件1 and 連接條件2 and ... ;select 列名1, 列名2, 列名3... from 表1 join 表2 on 連接條件1 and 表2 join 表3 on 連接條件2...;
注意:如果實際情況中,數據量很大,多表聯合查詢會生成大量的臨時結果,這個過程非常消耗時間,給服務器的響應速度造成很大的影響;因此,聯合查詢之前要評估好數據量。
2. 外連接
如果兩張表,里面的記錄存在對應關系,內連接和外連接的結果是一致的;
如果存在不對應的記錄,內連接和外連接就會出現差別;
左外連接:以左側表為基準,保證左側表的每個數據都會出現在最終結果中;如果在右側表中不存在,對應列就會填成空;
右外連接:以右側表為基準,保證右側表的每個數據都會出現在最終結果中;如果在左側表中不存在,對應列就會填成空;
-- 左外連接
select * from 表1 left join 表2 on 表1.列名 = 表2.列名;-- 右外連接
select * from 表1 right join 表2 on 表1.列名 = 表2.列名;
3. 自連接?
進行行和行之間的比較;
SQL 不能進行行和行之間的比較,這時候需要用到自連接;
-- 進行行與行之間的比較,自連接
select 列名, 列名... from 表名 as 表1, 表名 as 表2 where 連接條件 and 條件...;
4. 子查詢
?把多個簡單 sql 拼接成一個復雜 sql;
-- 單行子查詢
select 列名, 列名... from 表名 where 列名 = (select 列名 from 表名 where 列名 = ?) and 條件;-- 多行子查詢
select 列名, 列名... from 表名 where 列名 in (select 列名 from 表名 where 條件1 or 條件2);
5. 合并查詢
允許把兩個不同的表?sql 查詢的結果集合,合并到一起;
合并的兩個 sql 結果集的列需要匹配,列的個數和類型需要一致;
合并的時候會去重,如果不想去重,需要用 union all;
-- 合并查詢
select 列名 from 表1 union select 列名 from 表2;