- 本教程來源:我學習MySQL語法時所做的筆記
- 補充:在cmd、PowerShell中進入MySQL命令行的一般命令是
mysql -u root -p
,然後輸入密碼即可 - 今日,將筆記整理歸納後發出來供大家學習使用
相關文章推薦:
目錄一:概述
數據庫:
- 本質上是文件(爲了讓數據永久保存)
- 有很多寫好的流程(可以幫我們操作文件:讀、寫…)
- 我們想要讀取和保存的數據,給數據庫發送指令,讓它幫我們操作文件的讀寫(省去了我們操作I/O的過程)
數據庫可以分爲兩類:
- 關係型數據庫(以表格的形式記錄數據和關係),用的指令是SQL(Structured Query Language,結構化查詢語言)
- 非關係型數據庫(以key-value形式只記錄數據本身),用的指令是NOSQL(Not Only SQL)
SQL:
(Structured Query Language,結構化查詢語言)
歷經幾乎20年,在1989年,由國際標準化組織(ISO)頒佈SQL正式國際標準
現在很多的數據庫廠商還在遵循沿用着這套規範(SQL89標準)
各家的數據庫:
學習任何一家的數據庫產品,其實都差不多一樣(大同小異,學習了一個數據庫後,再學習其它數據庫就簡單的多了)
- IBM
- DB2數據庫
- Microsoft
- SQLServer(和windows系統融合的很好,但是在其他系統上兼容性就差了挺多)
- Access(Office辦公軟件中的很小的一個數據庫,不多見)
- Oracle
- Oracle(商用的)
- MySQL(開源免費的,最早是一家瑞典的公司的,先被SUN併購,後SUN被Oracle併購,現在很流行)
MySQL:
- 操作數據庫的語言規範:SQL(關鍵字不區分大小寫,但是建議寫大寫,風格統一)
-
DDL(Data Definition Language,數據定義語言)
- 創建、刪除、修改數據庫中的對象(表格,用戶,索引,視圖,存儲過程,觸發器)
- 三個關鍵字:創建
create
、刪除drop
、修改alter
- 請看目錄二
-
DML(Data Manipulation Language,數據操作語言)
- 操作數據庫表格中的具體數據
- 寫數據:新增
insert
、刪除delete
、修改update
- 讀數據:查詢
select
- 請看目錄三
-
DCL(Data Control Language,數據控制語言)
- 控制用戶權限
- (賦予)grant 權限,權限 to 用戶
- (回收)revoke 權限,權限 from 用戶
- 請看目錄四
-
TPL(Transaction Process Language,事務處理語言)
- 可以理解爲多線程併發訪問同一個文件資源,帶來的安全問題
- begin Transaction
- 操作
- commit提交
- rollback回滾
- save point A 保存還原點
- 這部分內容,在使用編程語言操作數據庫的時候用的非常頻繁,而且用起來很簡單,本文暫不講
目錄二: 數據庫、表格的創建、修改和刪除(DDL)
1. 先在MySQL數據庫中創建一個database
create database 數據庫名;
建議大家起名字最好遵循一定的規範----英文(要見名知義)
注意:在很多編程語言中(比如:Python、Java),英文字母區分大小寫
而MySQL英文字母不區分大小寫(關鍵字、表格名字、列名字…)
顯然,test
數據庫創建成功了
2. 在我們自己的database裏面創建table的格式
(暫時,創建的表格中列的屬性只有數據類型和長度)
create table(
列名 數據類型(長度),
列名 數據類型(長度),
列名 數據類型(長度)
)
這個寫法其實和Java中domain實體類的寫法非常相似
3. 數據庫中的數據類型
按存儲數據的方式來分類,分爲三類:
- 數值型
- 整數:
tinyint
1字節,smallint
2字節,mediumint
3字節,int
或者integer
4字節,bigint
8字節 - 小數:
float
4字節,double
8字節;decimal
,numeric
(前兩個的底層的計數方式更加精確,可以表示更多的數字;後兩者和前兩者差不多,但是則相對固定了些)
- 整數:
- 字符串
- (數據庫裏所有的字符串類型都是用單引號,不是雙引號)
char
字符串,定義之後長度是固定的varchar
可變長字符串,定義之後長度是根據存儲信息發生改變的,這個用的更多binary
字符串形式存儲二進制,varbinary
是可變二進制blob
二進制大文本,text
正常字符大文本
- 日期/時間
date
日期time
時間datetime
日期&時間- 日期和時間,在定義的時候都不需要長度,因爲他們的格式是固定的
- 還有,
date
只有年月日,time
只有時分秒,datetime
有年月日時分秒 timestamp
時間戳:時間表示的信息比上面三個更加精細,顯示的時間除了年月日時分秒外,還有毫秒、時區
4. 在自己的datebase中創建一個表格
[例] 先選擇 test 數據庫
use test;
[例] 然後,在 test 數據庫中創建一個 student 表格
create table student(
sid int(11),
sname varchar(20),
ssex varchar(4)
);
5. 通過DDL語句修改表格的結構
- 表格名字錯誤
- 修改原有的列(列名錯誤,列類型不對、列長度不夠)
- 新增一個列
- 刪除一個列
修改表名:
alter table 表名 rename [to] 新名字;
[例] 修改 student 的表名爲 zgh
alter table student rename to zgh;
[例] to
可以省略:
alter table zgh rename student;
修改原有的列(列名錯誤,列類型不對、列長度不夠):
alter table 表名 change 原列名 新列名 新類型 新長度;
[例] 將 student 表的 sid 列 改名爲 snum,並將類型改爲 char(11)
alter table student change sid snum char(11);
新增一個列:
alter table 表名 add 新列名 新類型 新長度;
[例] 在 student 表中新增一個列,列名爲 sbirthday,類型爲 date
alter table student add sbirthday date;
刪除原有的列:
alter table 表名 drop 原列名;
[例] 將 student 表的 sbirthday 列 刪除
alter table student drop sbirthday;
6. 刪除表格
drop table 表名;
[例] 刪除 student 表
drop table student;
7. 刪除數據庫
drop database 數據庫名;
[例] 將 test 數據庫刪除
drop database test;
目錄三:表格的增刪改查(DML)
- 操作 的是 表格 中的 數據信息
- 表格:
行:記錄
列:屬性 - 寫入信息(數據庫中的信息發生了真實的改變)
新增insert
,刪除delete
,修改update
- 讀取信息(數據庫中的信息沒有發生改變)
查詢select
學習DDL語句之前,
[例] 先創建一個數據庫 test,選擇這個數據庫,再在這個 test 中創建一個表格 student
create database test;
use test;
create table student(
sid int(11),
sname varchar(20),
sage int(4),
ssex varchar(4),
saddress varchar(30)
);
然後,開始學習了:
1. 新增記錄
insert into 表名(列名,列名,列名,...)values(值,值,值,...);
注意:列名和值是對應的(數據類型,數據的長度),還有列名可以根據需求,有不同的數量
[例]
insert into student(sid, sname) values(1, 'zgh');
2. 查詢記錄
select 列名,列名,列名,... from 表名
[例]
select sid, sname, sage, ssex, saddress from student;
可以看出,數據庫的表中存儲的元素都是引用類型的
如果是要查詢的信息包含所有的屬性(即:列)
還有一種寫法更加的簡單,不過它在底層方面上,比上面的的寫法的查詢速度要慢
select * from 表名;
[例]
select * from student;
要在表中新增一行信息,包含所有的屬性(即:列),有一個更加簡單的寫法
- 省略掉列名不寫
- 不過values裏面的值要和表格的屬性的順序對應好,類型,長度也要一一對應
insert into 表名 values(值,值,值,...);
[例]
insert into student values(2, 'hq', 18, 'male', 'whxyedu');
一次性增加多條記錄:
insert into 表名 values(值,值,值,...),(值,值,值,...);
[例]
insert into student
values(3, 'licw', 3, 'male', 'whxyedu'),
(4, 'xy', 38, 'male', 'whxyedu');
不能存儲中文的解決辦法
3. 存儲中文信息
此命令可以查詢數據庫的默認字符集:
select schema_name,default_character_set_name
from information_schema.schemata
where schema_name = 'test';
我記得MySQL5.7的默認默認字符集是不支持存儲中文的,
前幾天,我使用zip壓縮包(免安裝方式)重新安裝了MySQL8.0,發現在命令行中可以直接存儲中文,研究之後發現:
- 在MySQL5.7中,數據庫的默認字符集是latinl(不支持中文)
- 而在MySQL8.0中,數據庫的默認字符集變爲了utf8mb4(兼容utf8,是支持中文的)
3 - 擴展:字符集設置
- 如果你在使用MySQL的過程中,發現不能存儲中文字符,可以看一下這部分的內容
這部分內容是我很久以前的筆記,當時是使用installer安裝MySQL5.7,並且只選擇安裝MySQL Community Server,安裝完成後有兩個命令行客戶端給我使用,然後我學習時的截圖都是基於這兩個客戶端
其中一個客戶端是Unicode字符,但是使用此命令行客戶端直接輸入中文字符是不可以的,還要進行一些設置
原因是,MySQL8.0之前的某些版本,數據庫的默認字符集可能不支持存儲中文,
- MySQL有四個默認的database,
information_schema
是其中一個:
- 方法一:設置database的默認字符集爲utf8,從此之後,使MySQL創建的新數據庫支持存儲中文
但是基於默認字符集創建的(原有的)數據庫,其字符集不能修改了,若要使它存儲中文,只能刪掉咯 - 方法二:不修改MySQL的全局字符集,在創建數據庫的時候可以單獨設置這個數據庫的字符
create database test default character set = 'utf8';
- 方法三:如果不想讓創建的數據庫中的所有表存儲中文,只單純的某一張表格需要中文,創建表格的時候設置字符集
create table 表名(
列名 類型 長度,
列名 類型 長度
)character set utf8;
還可以同時設置排序規則:
create table 表名(
列名 類型 長度,
列名 類型 長度
)character set utf8 collate utf8_general_ci;
排序規則有兩個:
utf8_general_ci
默認,性能比較高,可能不太精確utf8_unicode_ci
性能比較低,擴展性好
4. 刪除記錄
如果不寫where,表中全部記錄將被全部刪掉:
delete from 表名
where 條件;
[例]
delete from student;
5. 修改記錄
update 表名 set 列=值,列=值
[where 條件];
[例] 先在 student 表中增加兩行數據,再進行修改操作
insert into student values(1, 'zgh', 18, 'male', '地府'),
(2, '索兒呀', 18, 'male', '冥府');
select * from student;
update student set sname = 'zhangguohao666', ssex = 'boy';
select * from student;
可以很明顯的看到,由於沒有對錶中的值進行篩選,默認選擇了 student 表中所有的內容,所有內容的 sname 和 ssex 都被改了
6. 顯示錶格的狀態
顯示student表格的狀態:
show table status
from test
like 'student';
這就是命令行客戶端的侷限性了,因爲查詢的內容太多,就如上圖這樣重合了
目錄四:用戶的創建、刪除與權限配置(DCL)
數據控制語言
- 控制用戶的權限
grant
賦予revoke
回收
常用的MySQL權限
數據庫/數據表/數據列權限:
Create
建立新的數據庫或數據表Alter
修改已存在的數據表(例如增加/刪除列)Drop
刪除數據庫或數據表Insert
增加表的記錄Delete
刪除表的記錄Update
修改表中已存在的記錄Select
顯示/搜索表的記錄- ==================================
References
允許創建外鍵Index
建立或刪除索引Create View
允許創建視圖Create Routine
允許創建存儲過程和包Execute
允許執行存儲過程和包Trigger
允許操作觸發器Create User
允許更改、創建、刪除、重命名用戶和收回所有權限
全局管理MySQL用戶權限:
Grant Option
允許向其他用戶授予或移除權限Show View
允許執行show create view
語句Show Databases
允許賬戶執行show databases
來查看數據庫Lock Table
允許執行lock tables
來鎖定表格File
在MySQL上讀寫文件Process
顯示或殺死屬於其它用戶的服務線程Reload
重載訪問控制表,刷新日誌等ShutDown
關閉MySQl服務
特別的權限:
-
All
允許做任何事(和root一樣) -
Usage
只允許登錄,其它什麼也不允許做 -
如果一開始是通過MySQL命令行客戶端來學習MySQL,那麼本目錄內容需要在終端中進行,因爲MySQL命令行客戶端一打開就是以 root 身份登錄
-
如果你會使用終端來玩MySQL,請自行跳過本目錄中擴展一、擴展二的內容
擴展一:Windows中配置環境變量(如果配置過,請自行跳過)
使用 installer 安裝MySQL5.7,並且只選擇安裝MySQL Community Server,安裝完成後有兩個命令行客戶端給我使用,然後我學習時的截圖都是基於這兩個客戶端
-
使用這兩個客戶端,打開時默認以 root 身份進入
-
如果要換身份登錄,我們需要先進行MySQL的環境變量配置,再使用windows的終端(cmd、PowelShell)
-
MySQL的默認安裝路徑:
C:\Program Files\MySQL\MySQL Server 版本號
-
需要配置的環境變量(比如說我安裝的是MySQL5.7):
C:\Program Files\MySQL\MySQL Server 5.7\bin
右鍵此電腦 > 屬性 > 高級系統設置 > 高級 > 環境變量
上面的和下面都有一個 path ,這就是需要設置的環境變量了
選中其中一個,點擊編輯
連續點擊三次確定!!!直至所有打開的窗口都關閉了
好了,環境變量配置完成
擴展二:Windows中使用cmd或者PowerShell玩MySQL
鍵盤同時按下 win + r,打開運行窗口,在輸入框中輸入cmd 或者 PowerShell
點擊確定,windows的控制檯就打開了
也是很熟悉的黑框框
在 終端中 進入MySQL
mysql -u 用戶名 -p
回車後,發現這和我原來玩的MySQL命令行窗口一樣了
輸入密碼後,盤符變成了mysql
在 終端 中退出MySQL
輸入 exit;
或者 鍵盤同時按下 Ctrl + z ,然後回車
我現在的身份是SYSDBA管理員(即MySQL中的root賬號,管理員可以操作其他普通用戶的權限)
查看用戶信息
先用root賬號看一下MySQL中四個默認database
其中mysql
數據庫中的user
表格記錄了MySQL的用戶信息
user表格中有很多屬性
我們現在只需要查詢三個屬性
user
用戶名host
IP地址,默認是localhost
,即本機- 在MySQL的5.5版本之前,密碼是存儲在
password
列中;我的版本是5.7,用戶密碼被md5加密了,放在了另一個列authentication_string
列
創建新用戶
create user '用戶名'@'IP' identified by '密碼';
然而一個新創建的用戶,只有一個默認的權限usage
,只允許登錄,不允許做其他事情
控制用戶的權限
1. 給新的用戶賦予權限
查看用戶權限
可以通過一個語句查看用戶的權限
show grants for '用戶名'@'IP';
給用戶賦予權限
grant 權限 on 數據庫.表格 to '用戶名'@'IP';
(補充*.*
代表所有數據庫的所有表格)
賦予權限之後,如果發現沒起作用,最好做一個刷新
flush privileges;
2. 註銷 用新用戶登錄
註銷
exit;
然後
因爲zgh用戶的權限和root一樣
3. 回收用戶的權限
revoke 權限 on 數據庫.表格 from '用戶名'@'IP';
重新用root賬號登錄,
然後
(補充,usage
權限是一定會保留的)
再進入zgh賬號看一下:
4. 修改用戶密碼(DML)
update user set authentication_string = password('密碼')
where user = '用戶名'@'IP';
如果嘗試重新登錄改了密碼的用戶,發現改了的密碼不好用
那就返回root賬戶刷新一下數據庫
flush privileges;
5. 刪除創建的用戶(DDL)
使用DDL語句刪除用戶是最好的,因爲它刪除的更加乾淨
drop user '用戶名'@'IP';
目錄五:列的約束
- 主鍵約束
- 外鍵約束
- 唯一約束
- 非空約束
- 檢查約束
前情提要:
先創建一個數據庫cons
(因爲數據庫名字長度有限制,cons是constraint的縮寫)
然後在cons數據庫中
創建一張表:
myclass表
create table myclass(
classid int(4),
cname varchar(20),
loc varchar(20)
);
然後設置一下myclass表的字符集
alter table myclass character set utf8;
我先在myclass表中添加一行元素
如果我在myclass表中添加一行相同的元素,會有衝突嗎?
顯然,相同的元素可以添加進去
但是,有時候對於存儲的元素是不允許重複的
爲了方便下面的學習,我把myclass的元素清空
一:主鍵約束
primary key
- 在每一個表格中,只能有一個列被設置爲主鍵約束
- 主鍵通常用來標記表格中數據的唯一存在
- 主鍵約束要求當前的列,不能爲null值
- 主鍵約束要求當前的列,值是唯一存在的,不能重複
添加約束,到底是改變表結構還是操作數據呢?
很顯然,添加約束時,表中是沒有元素的
所以要用DDL語句
添加主鍵約束的標準寫法
alter table 表名 add constraint 約束名字 約束類型(列);
查看錶的約束
然後,怎麼查看錶是否有約束呢?
有兩個辦法:
第一個辦法:
desc 表名;
desc是description的縮寫
第二個辦法:
show keys from 表名;
添加主鍵約束的簡寫
可以看出,兩種查看約束的方式都與約束名無關
所以添加約束的語句可以簡寫爲:
alter table 表名 add 約束類型(列);
主鍵的自增操作
添加主鍵之後,若想要主鍵自增,可以做相應的設計
alter table 表名 modify 列名 類型(長度) autu_increment;
或者
alter table 表名 change 原列名 新列名 類型(長度) autu_increment;
change
和modify
兩個關鍵字的不同在於,change
關鍵字還可以更改列名
這個語句,沒有做起始值的說明,主鍵列會從1開始
再加一條記錄:
設置主鍵自增的起始值:
alter table 表名 auto_increment = 起始值;
去掉主鍵自增:
重新設置一下列就好:
刪除主鍵約束
刪除主鍵:
alter table 表名 drop primary key;
刪除主鍵約束後,有一個小細節要注意一下:
刪除主鍵約束後,不重複的特性取消了,但是非空特性還在
所以,在刪除主鍵約束後,還要非空特性改回去:
alter table 表名 modify 列名 類型(長度) null;
二:唯一約束
unique key
,key
可以不寫- 可以爲表格中的某一個列添加唯一約束
- 唯一約束表示的是列的值,不能重複,但是可以爲空
- 在表格中可以有多個列存在唯一約束
先把myclass表清空
先在myclass表中添加一行元素
添加唯一約束的標準約束
然後給myclass表的loc屬性添加唯一約束
例如:
標準的:
alter table myclass add constraint uk_myclass unique key(loc);
簡寫的:
alter table myclass add unique key(loc);
//約束名是默認的列名
唯一約束不止一個,需要起約束名,方便通過約束名刪除唯一約束
刪除唯一約束
寫法有一些特殊:
alter table myclass drop index 約束名;
添加唯一約束的簡寫
alter table myclass add unique key(loc);
//約束名是默認的列名
三:非空約束
- 在表格的某一個列上添加非空元素
- 當前的列的值不能爲null
先把myclass表中的唯一約束刪掉
設置非空約束
非空約束,要通過modify
或者change
來改變表的結構
alter table 表名 modify 列名 類型(長度) not null;
去掉非空約束
alter table 表名 modify 列名 類型(長度) null;
設置非空約束的另一種寫法:
alter table 表名 change 原列名 新列名 類型(長度) not null;
刪除非空約束的另一種寫法:
alter table 表名 change 原列名 新列名 類型(長度) null;
四:默認值
當myclass表的cname屬性有非空約束,假如在開發中某一時間不知道填寫什麼
可以使用default
關鍵字來避免這個問題
如果你不填寫,就是這個默認值
然後我在myclass表中添加一行元素:
五:外鍵約束
foreign key
- 表格中可以有多個列被設置爲外鍵約束
- 當前列的值可以爲空,可以重複
- 當前列的值不能隨便填寫,值要去另一張表格中尋找
- 外鍵是當前列的值受另外一張表格某一個列的影響
- 另外一張表的列的值是唯一的(唯一約束或主鍵約束)
表之間的關聯,玩的就是外鍵約束
玩外鍵約束之前,先創建一個表格student
create table student(
sid int(4),
sname varchar(20),
ssex varchar(10),
classid int(4)
);
alter table student character set utf8;
然後在student表格中添加元素
insert into student values(1,'ahri','female',1);
insert into student values(2,'lux','female',1);
insert into student values(3,'garen','male',2);
insert into student values(4,'akali','female',2);
student表:
還要涉及另外一張表myclass:
添加外鍵約束的標準寫法
alter table 表名字 add constraint fk_當前表_關聯表 foreign key(列) references 另一個表(列);
不過在添加外鍵約束時,要先使另一張表的列的值是唯一的(非空約束,主鍵約束)
MUL指的是multiple(多樣,並聯)
刪除外鍵約束
alter table 表名字 drop foreign key 約束名字;
注意:通過上述語句其實已經將這張表格的外鍵約束刪掉了
但是,外鍵約束涉及到兩張表格,爲了保證另外一張表的記錄不丟失,會自動在當前的表格內添加一個新的key
show create table 表名;
//這個語句可以看key
我們需要再次手動將這個生成的key刪掉,外鍵約束才真的刪乾淨
alter table 表名 drop key 外鍵約束名;
添加外鍵約束的簡寫
alter table 表名字 add foreign key(列) references 另一個表(列);
那麼,外鍵約束名是什麼呢?
只能以通過show create table 表名;
查的外鍵約束名爲準(不是默認的列名!)
所以簡寫的方式,使刪掉外鍵時挺麻煩的(儘量不要這麼使用)
但是key的名字確是默認的列名
六:檢查約束
- 列在存值的時候做一個細緻的檢查,值的範圍是否合理
首先,看一下student表的結構:
然後,我添加一個屬性
現在,我要對sage的值進行更新(但是更新的值要合理,就可以用檢查約束來保證數據的合理性)
添加檢查約束
alter table 表名 add constraint 約束名 check(值的範圍);
然後發現檢查約束的語句執行了,但是在MySQL中不好使(被MySQL的底層屏蔽了)
不過檢查約束,在Oracle數據庫中是好使的
目錄六: 關鍵字:any,some ,all ,union,union all
學習這幾個關鍵字之前的準備
student表
再創建一個myclass表
create table myclass(
classid int(3),
classname varchar(20),
classloc varchar(20)
);
在myclass表中插入元素
insert into myclass values(1,'classone','zhuhe');
insert into myclass values(2,'classtwo','xihe');
insert into myclass values(3,'classthree','wuhan');
insert into myclass values(4,'classfour','hubei');
myclass表:
- 先說一下
in
關鍵字
滿足查詢子集中的一個即可
in 後面跟的語句可以是常量固定值,也可以是嵌套查詢 - 如下三個關鍵字
any
,some
,all
使用起來與in
類似,查詢是否滿足後面的子集中的條件
但是這三個關鍵字的後面只能跟嵌套查詢,而且要配合運算符來使用
一:any,some
any和some的用法完全一樣
>any
大於最小值
<any
小於最大值
=any
等價於in
關鍵字
!=any
二:all
all滿足查詢子集的全部纔可以
<all
>all
=all
!=all
和not in
關鍵字等價
三:union,union all
對集合的操作有:
- 並集
union
- 交集(Oracle數據庫有這個語句
intersect
) - 差集(Oracle數據庫有這個語句
minus
)
並集union
,將兩個表合併在一起
有兩個表,
student
teacher
create table teacher(
tid int(4),
tname varchar(20),
tsex varchar(10),
tbirthday date
);
insert into teacher values(1,'zgh1','male','1999-08-05');
insert into teacher values(2,'zgh2','male','1998-08-17');
insert into teacher values(3,'zgh3','male','1998-08-16');
並集的語句是這麼寫的,舉個例子:
select sid,sname,ssex from student union select tid,tname,tsex from teacher;
把兩張表的寫的順序調換一下:
select tid,tname,tsex from teacher union select sid,sname,ssex from student;
很顯然,並集後的表的列名取決於語句中寫的前一張表,當然,也可以取別名
合併的要求:
- 要求前後兩個查詢子集的列數是一致的
- 拼接後顯示的列名是前一個子集默認的列名
- 類型和長度是沒有要求的,可以不一樣
- 注意
union
和union all
的區別:對於重複元素的處理
我再創建一個新的newteacher表格
create table newteacher as select * from teacher;
//這個語句可以通過後面一張表創建一個完全一樣的表格
再對newteacher表箇中的數據改動兩行,保留一行和teacher表中一樣的元素
update newteacher set tid = 10 where tname = 'zgh2';
update newteacher set tid = 11 where tname = 'zgh3';
union
會在拼接的時候,又做一個處理,看一看有沒有重複,有就把重複的元素拒絕加入(所以性能較慢)
而union all
將兩張查詢的子集直接合並,不做任何處理,性能比較快
當數據沒有重複時,建議用union all
來進行合併處理
目錄七: 函數的使用
用student表來學習函數的使用
函數直接放置在語句中,
可以放置在:
select 函數(列)
from 表格
where 函數(值) > 值
按照函數功能進行劃分
- 比較函數
- 數學函數(數值函數)
abs(值)
絕對值
floor(值)
向下取整
mod(值,值)
取餘數
pow(值,值)
求次方
round(值)
四捨五入 - 日期和時間
now()
year(date)
mouth(date)
day(date)
week(date)
- 控制流程函數(轉換函數)
if(expr1,expr2,expr3)
三目運算符
ifnull(值,v)
是空值顯示v,如果非空就正常顯示 - 字符串函數
大部分和java中的String類的方法差不多 - 分組函數(聚合函數)
最最最重要的
常用函數:
一:日期和時間函數
爲什麼會出現7個記錄,因爲student表格有七列
SQL有一個關鍵字distinct
可以去重複
(注意,distinct
修飾的是每一行記錄的全部選擇的屬性(列))
然後MySQL中有一個獨有的寫法,可以這樣寫:
二:流程控制函數
if(expr1,expr2,expr3)
三目運算符
ifnull(值,v)
是空值顯示v,如果非空就正常顯示
先把student表中的某行的某個值修改爲null
然後:
三:字符串函數
字符串函數 String類
length() length()
concat() concat()
substr() substring()
instr() indexOf()
replace() replace()
upper() toUpperCase()
lower() toLowerCase()
ltrim(),rtrim() trim()
lpad()
rpad()
reverse() StringBuffer,StringBuilder中的reverse()
lpad()
sname
的長度不夠10則在左邊補*
,補到10個爲止
四:聚合函數+分組條件
count()
個數max()
最大值min()
最小值avg()
平均數sum()
和
舉一個例子:
查詢student表中語文成績最高的
目錄八: 條件篩選、排序、分組、嵌套
一:條件篩選
在找尋數據的時候做一個篩選
條件篩選where
- 除了insert語句以外的其它三個語句(update,select,delete)都可以進行篩選
where
是一個關鍵字,拼接在語句的基本結構之後 - 篩選用來篩選符合條件的記錄行數
並不是控制顯示的列 - 按照某一列或者某一些條件進行篩選
列,滿足一定的條件 where
後面具體怎麼用,連接什麼東西
在學習條件篩選之前,先創建一個database,再在裏面創建一個table,用來記錄學生信息
補充:float(m,n)
總共可以存儲m位數字,小數點之後有n位;m的取值範圍是1-65,n的取值範圍是0-30;如果不寫參數,默認效果:m是10,n是0
然後在student表中加入這些數據
insert into student values(1,'zhangsan','male',18,'2000-01-01',10,60,80,1,100);
insert into student values(2,'lisi','female',18,'2000-12-5',61,59,35,1,0);
insert into student values(3,'wangwu','male',18,'2000-11-11',89,33,77,2,100);
insert into student values(4,'zhaoliu','female',18,'2000-05-01',60,60,60,3,60);
insert into student values(5,'qianqi','male',18,'2000-03-03',70,80,100,3,90);
insert into student values(6,'wangba','female',18,'2000-02-02',100,70,10,2,10);
insert into student values(7,'zgh','male',18,'1999-08-05',100,100,100,2,100);
student表格:
where後面具體怎麼用,連接什麼東西
- 比較運算符
> >= < <= != =
select *
選擇全部屬性(列)
選擇部分的屬性(列)
- 算術運算符
+ - * /
- 邏輯運算符
and or not
優先級,做左往右,優先級降低
數據庫底層做的事情
- 解析SQL語句
- 從表格中把全部數據都讀取出來,放在數據庫中緩存,用集合list
- 將list集合做一個遍歷循環,每一次拿到一行記錄,然後和where語句做比較
假設我們的表格有7條記錄
如果只寫一個where條件
執行七次循環就可以出來了
但如果and連接了不止一個where條件
先按照第一個條件篩選(7個循環,假設有6個滿足)
然後按照第二個條件篩選(6個循環)
and語句的執行效率很低,and語句儘量少用;但如果在語句中寫了and,儘量將條件苛刻的寫在前面,提高執行效率,
or也是如此
所以SQL提供了許多可以替代and和or的執行效率更高的語句
如:
between
between 左邊界值 and 右邊界值
查詢的範圍:[ 左邊界值,右邊界值]
補充一個
not between 左邊界值 and 右邊界值
in
in
補充一個:
not in
like(模糊查詢)
like
%
用來代替0-n個字符_
用來代替1個字符
先把表的內容看一下:
進行模糊查詢
刪除delete
,修改update
語句中的條件篩選的玩法和查詢select
語句一樣,不多說了
二:排序
- 連接在查詢的語句之後的
order by 列
- 升序排列
asc
,默認就是升序的,可以省略不寫 - 降序排列
desc
排序語句和條件篩選語句一起寫:
聯合查詢
當前面的排序語句相等時,再按照次級排序語句排序
三:分組
group by 列
如果SQL語句中一旦搭配了分組條件,能展示的信息只有兩種
- 分組條件
- 分組函數
先看一下studnet表:
- 查詢student表中每一個班級有多少個同學
- 查詢student表中男,女同學的人數
- 查詢student表中每個年齡層段有多少人
- 查詢student表中每一個班級的語文平均分
- 查詢student表中每一個班級的語文平均分,並且按照平均分升序排序
四:對於分組條件+分組函數的查詢
- 查詢student表中所有男同學,他們都在哪個班級
先進行where
,再進行分組group by
- 查詢student表中語文平均成績高於90分的班級
先分組,再對平均成績條件篩選
(但是where
比group by
的優先級別高)
所以SQL給我們提供了一個關鍵字having
,它的用法和where
差不多,但是它的優先級比group by
低
所以,一般group by
和having
搭配使用
- 在查詢之前需要先考慮,到底是先分組,還是先篩選條件
如果是先篩選,後分組where
+group by
如果是先分組,再篩選group by
+having
- 在查詢的時候一旦分組了,行數會減少
想要展示的信息的個數需要與分組條件的個數一致
五:嵌套
在一個完整的SQL語句中,嵌套了另一個完整的SQl語句(當涉及到多個不同的表)
嵌套可以將一個查詢的結果當作條件,來再次查詢(這種用法很常用)
- 查詢student表中語文成績最高分的同學
嵌套可以將一個查詢的結果當作一個表格(需要給這張表格取別名),在這張的表格的基礎上再次查詢
- 查詢student表中男同學的sname,ssex,sage,classid
目錄九: 表格之間的聯合查詢
就是將多張表的數據沒有任何條件的組合在一起,形成一張完整的大的表格,然後在這張大的表格上進行篩選
- 等值連接(等值連接之前,需要先進行廣義笛卡爾積)
- 外連接
- 內連接(自連接)
一:廣義笛卡爾積
廣義笛卡爾積將兩張表格或多張表格,進行無條件的拼接
先看兩張表:
emp表(存儲僱員信息):
dept表(存儲部門信息):
然後,把這兩個表的數據沒有任何條件的組合在一起,形成一張完整的大的表格(廣義笛卡爾積)
列數爲兩張表的列數相加
行數爲兩張表的行數相乘
廣義笛卡爾積,簡單粗暴,兩張表的全部數據都組合起來了
但是很多數據是沒有意義的,
比如僱員smith和四個部門的組合的數據中,只有部門20的那一行組合的信息纔有意義
二:等值連接
在廣義笛卡爾積的基礎上,進行條件篩選
因爲一般篩選都是通過=
來進行的,所以才叫等值連接
(注意,不一定必須是=
,其它的判斷語句也行)
比如:
然後:
因爲emp表格中我在定義和插入數據時有一些錯誤,我把這些錯誤更正後的emp表:
然後,我創建一個表salgrade(記錄工資的等級),然後插入一些數據和一些約束:
create table salgrade(
grade int(4),
losal int(6),
hisal int(6)
);
alter table salgrade add primary key(grade);
insert into salgrade values(1,700,1200);
insert into salgrade values(2,1201,1400);
insert into salgrade values(3,1401,2000);
insert into salgrade values(4,2001,3000);
insert into salgrade values(5,3001,9999);
salgrade表:
然後,把emp表個salgrade表進行等值連接:
查詢一下每個工資等級有多少個僱員
其實,等值連接的性能不太好
因爲先要進行笛卡爾積,然後進行條件篩選
爲了提高查詢的性能,SQL提供了兩種查詢辦法(外連接和內連接,性能更高)
三:外連接
select * from A left/right [outer] join B on 條件;
補充:[]
內的語句代表可有可無,/
代表或者
看到left
就是左外連接,right
是右外連接
on
關鍵字和where
的作用差不多,但是where
的優先級比from
的低;而on
的優先級比from
的優先級高
- 兩張表格A和B,取決於誰的數據在左邊顯示
A表格先出現,A左邊顯示
B表格先出現,B左邊顯示 left
和right
來控制以哪一個表格的數據作爲基準
作爲基準的表格的數據必須全部顯示出來
非基準的表格按照on條件與之拼接,條件滿足的正常顯示,不滿足條件的則爲null
拿emp表和dept表做演示
因爲兩張表的deptno的屬性都可以對應上,
我先在emp表中插入一個特殊的數據:
emp表:
dept表:
左外連接
右外連接
四:內連接
select * from A inner join B on 條件;
可以看出,內連接的查詢結構和等值連接的查詢結果是一樣的(但是,內連接的性能更加棒)
還有一個比較特殊的玩法(在當前表格中再次查詢當前表格的信息):
先看一下emp表:
(補充,其實等值連接也可以這玩)
目錄十: 行列互換、分頁查詢、設計範式
一:行列互換
先創建一個表warehouse(存儲倉庫信息):
create table warehouse(
wname varchar(8),
winventory int(8),
wmonth varchar(8)
)character set utf8;
insert into warehouse values
('A',100,'一月份'),('B',1000,'一月份'),('C',10,'一月份'),
('A',200,'二月份'),('B',2000,'二月份'),('C',20,'二月份'),
('A',300,'三月份'),('B',3000,'三月份'),('C',30,'三月份');
若要使表格像這麼顯示:
首先,要使用group by
關鍵字進行條件分組
通過倉庫名稱分組:
- A組 三個值 每一個月份對應一個庫存
- B組 三個值 每一個月份對應一個庫存
- C組 三個值 每一個月份對應一個庫存
分組後,顯示的屬性的值要分情況討論,要使用if()
三目運算函數
select
wname 倉庫名,
max(if(wmonth = '一月份',winventory,0)) 一月份,
max(if(wmonth = '二月份',winventory,0)) 二月份,
max(if(wmonth = '三月份',winventory,0)) 三月份
from warehouse
group by wname;
因爲,一旦使用了group by
分組條件
select
可以顯示的列只有兩種(分組條件和分組函數)
(注意:select
中用到的分組函數可以是max()
,也可以是min()
…因爲反正只有一個嘛)
二:分頁查詢,limit
emp表格:
emp表格有14行記錄,假如每一頁只能顯示5行記錄,必然會產生分頁
怎麼做呢?
MySQL中有一個關鍵字limit a,b
(a代表想要顯示的起始行索引,索引行是從0開始的;b代表想要顯示的行數)
顯示前五行:
select *
from emp
order by sal desc
limit 0,5;
顯示中間五行:
select *
from emp
order by sal desc
limit 5,5;
顯示最後面的:
select *
from emp
order by sal desc
limit 10,5;
(補充:如果行數不夠,就算了)
Oracle數據庫的查詢就比較麻煩了,它要使用一個僞列rownum
還有level
,rowid
SQL Server要使用top
三:數據庫設計的範式Normal Form
- 設計數據庫時,遵循的不同規範,這些規範統稱範式
- 範式的目的是爲了減少數據庫的冗餘,管理表格的時候變得容易(修改、刪除)
- 但是查詢的時候可能涉及到表格聯合的問題(性能會降低一點)
有這麼一張表格(用來記錄學校裏面不同樓宇項目的一些信息)
上表存在很多問題
- 數據有大量冗餘
- 所以修改起來比較麻煩
1FN
- 數據庫中每一張表格的每一個列都是不可分割的(數據的原子性)
通俗的解釋:行列交叉點的單元格內只存儲一個數據 - 每一個表格中必須有主鍵約束(快速查詢某一行記錄)
(上表不遵循1FN,原子性可以保證,
但表格內沒有主鍵----設定聯合主鍵:項目編號+工程師編號)
2FN
- 在滿足1FN的前提下,
- 不允許出現部分依賴性(非主鍵列不能受主鍵列或主鍵列的一部分影響)
(如果產生了非主鍵列受到主鍵或主鍵的部分影響----將數據拆開存儲在兩張表中)
看上表,當設定(聯合主鍵:項目編號+工程師編號)之後,雖然滿足了1FN
但是,工程師名稱和工程師編號有關係,這個沒問題
但是工程師名稱和項目編號本應該沒有關係的,但是由於聯合主鍵的緣故,工程師名稱受到了項目編的影響,不滿足2FN
改動:
將上表拆成兩個表格
工程表格
(拆開之後會發現,工程表格沒有了主鍵,這個先放在這裏,往後面看)
工程師表格
3FN
- 在滿足前兩個範式的前提下,
- 不允許出現傳遞依賴性(非主鍵列不能受到非主鍵列或非主鍵的一部分影響)
(如果非主鍵列受到了非主鍵列或非主鍵的一部分影響----將沒有關係的數據拆開單獨存放在表格中)
在工程表格中,
小時工資受到了職稱的影響,不滿足第三範式
改動:
將工程表格拆成兩個表格
項目表格
(主鍵是:項目編號)
職稱表格
(給職稱表格加一個屬性:職稱編號,來作爲主鍵)
再看一下
工程師表格
(主鍵是:工程師編號)
雖然滿足了3FN
但是,在實際應用中,用戶需要對這三張表格做聯合查詢
所以,三張表格之間的關係也要處理一下:
- 工程師和項目是多對多的關係,所以需要構造另一張表(項目_工程師中間表)
(項目編號和工程師編號是這張表的聯合主鍵;
項目編號是項目表的外鍵;
工程師編號是工程師表格的外鍵)
- 工程師和職稱是多對一的關係
所以工程師表格需要添加一個職稱表格的外鍵
最終成果:
項目表格
職稱表格
項目_工程師中間表
工程師表格