數據庫
一,MySQL基礎
1,單行函數
1,字符函數
- 長度函數:LENGTH
SELECT LENGTH (last_name) from user ; -- 字節長度
- 字符串拼接:CONCAT
select concat(last_name,'_',first_name) as 姓名 from user
- 大小寫轉換:UPPER , LOWER
select concat(UPPER(last_name),'_',LOWER(first_name)) as 姓名 from user
- 字符串截取:substr , substring
-- 索引從1開始,往後截取(字符長度)
select substr('好好學習,天天向上',6) 目標; -- 天天向上
-- 從1開始截取4個長度
select substr('好好學習,天天向上',1,4) 目標; -- 好好學習
- 起始索引位置:instr
-- 第一次出現的起始位置索引,沒有則返回 0
select instr('好好學習,天天向上','天') 位置;
- 去空格:trim
-- 去除前後空格,中間不管
select trim(' 好好學習, 天天向上 ') 目標; -- 好好學習, 天天向上
-- 去除前後連續的a字符
select trim('a' from 'aaaaa好好學習, aa天天向上aaaaa') 目標;-- 好好學習, aa天天向上
- 左右填充:lpad,rpad
-- 從左開始按照10個字符長度用day填充
SELECT lpad('好好學習',10,'day'); -- dayday好好學習
SELECT rpad('好好學習',10,'day'); -- 好好學習dayday
- 替換:replace
select replace('aaaaa好好學習, aa天天向上aaaaa','a', '') 目標;
2,數學函數
- 四捨五入:round
-- 默認取整
select round(1.23); -- 1
-- 四捨五入保留小數後2位
select round(1.2356,2); -- 1.24
- 向上取整:ceil
-- 向上取整,返回>=當前值的最小整數
select ceil(1.23) -- 2
- 向下取整:floor
-- 向下取整,返回<=當前值的最大整數
select floor(1.23) -- 1
- 截斷:truncate
-- 直接截斷,保留小數後2位
select truncate(1.234,2); -- 1.23
- 取餘:mod
select mod(10,-3); -- 1
3,日期函數
- 當前時間(包含時分秒):now()
select now(); --2019-10-22 22:44:09
- 當前日期(不包含時分秒):curdate()
select curdate(); -- 2019-10-22
- 當前時間(只有時分秒):curtime()
select curtime(); -- 22:45:41
- 特指年月日:
SELECT YEAR(now());
SELECT MONTH(now());
SELECT DAY(now());
- 日期格式化:str_to_date
SELECT STR_TO_DATE('2019-10-22','%Y-%m-%d');
- 日期轉字符:str_to_date
SELECT DATE_FORMAT(now(),'%Y年%m月%d日');-- 2019年10月22日
日期格式化格式符
格式符 | 功能 |
---|---|
%Y | 4位年份,如 2019 |
%y | 2位年份 ,如 19 |
%m | 月份,如 01,02,,,11,12 |
%c | 月份,如 1,2,,,11,12 |
%d | 日,如 01,02,,, |
%H | 時,24小時制 |
%h | 時,12小時制 |
%i | 分鐘,如 00,01,,,58,59 |
%s | 秒,如 00,01,,,58,59 |
4,其他函數
不限於此
-- 當前版本
SELECT VERSION();
-- 當前數據庫
SELECT DATABASE();
-- 當前用戶
SELECT User();
5,流程控制函數
- 三元運算,IF
select if(1>0,'1大','0大'); -- 1大
- case…when…then
select salary,department
case department
when 'java' then salary*2
when 'python' then salary*3
when 'bigdata' then salary*4
else salary
end as '績效工資'
where employees;
2,分組函數
- 求和,sum (只支持數值型,忽略爲null的行)
select sum(salary) from employees;
- 求平均,avg(只支持數值型,忽略爲null的行)
select avg(salary) from employees;
- 最小值,min(支持數值型,字符型,日期型,忽略爲null的行)
select min(salary) from employees;
- 最大值,max(支持數值型,字符型,日期型,忽略爲null的行)
select max(salary) from employees;
- 數量統計,count (該表中參數行非空的個數統計)
select count(1) from employees;
select count(*) from employees;
-- 以上的區別,count(1) 相當於在列中加一個爲1的常量值列,這個列貫穿所有行,可做總行數統計。coun(*) 相當於統計含有字段不爲空的所有行,可做總行數統計;
-- 在Myisam引擎下,count(*)效率高(引擎自帶次函數),在Innodb引擎下,count(1)和count(*)效率相仿,但高於count(字段),因爲字段需要做判空
特點:
- sum ,avg一般只處理數值類型;
- min,max,count支持所有類型;
- 分組函數都忽略null值;
- 可以和distinct搭配實現去重;
-- 第一個根據薪水去重再求和,第二個直接求和
select sum(distinct salary),sum(salary) from employees;
-- 根據薪水去重再算數量
select count(distinct salary) from employees;
- 和分組函數一同查詢的字段需要是group by後的字段;
3,分組查詢
- 分組篩選:group by
select 分組函數 ,列(出現在group by 後面的字段)
from 表
where 條件 -- 分組前的篩選條件
group by 分組的列
order by 排序;
-- 如:統計部門平均工資
select avg(salary),department
from employees group by department;
- 分組後的篩選:having (having後可以放原始函數,如:max,min,count等)
-- 根據部門分組篩選出人數大於100的
select count(*),department
from employees group by department
having -- 分組後的篩選條件
count(*)>100;
- 多字段分組:
-- 多字段分組順序可以不一致
select department,job,work_no
from employees group by department,work_no,job
特點:
- 分組篩選條件分兩種:
數據源 | 位置 | 關鍵字 | |
---|---|---|---|
分組前篩選 | 當前表 | group by 前面 | where |
分組後篩選 | 分組後的結果集 | group by 後面 | having |
- 優先考慮分組前篩選;
- 分組函數做查詢一定屬於分組後篩選;
- 支持別名;
4,關聯查詢
SQL92標準
- 等值連接(取交集)
-- 當關聯表中存在相同字段名稱時,需要制定到表
select e.name 員工名稱,d.name 部門名稱 from employees e,department d where e.dep_id=d.id;
- 非等值連接
select e.salary,g.grand
from employees e,grand g
where e.salary between g.lowest and g.highest;
- 自連接
-- 查詢員工名稱及其對應的領導名稱
select e.name as 員工名稱,m.name as 領導名稱
from employees e,employees m
where e.leander_id=m.id
SQL99標準
- 內連接 inner join … on
select e.name 員工名稱,d.name 部門名稱
from
employees e inner join department d
on e.dep_id=d.id; -- on 等同於 where
- 外連接 left join … on(左外:左主) ; right join … on(右外:右主)
-- 主表不爲null的全部查詢出來,從表爲空用null填充
select e.name 員工名稱,d.name 部門名稱
from
employees e left join department d
on e.dep_id=d.id;
- 全外連接 full
-- 查詢所有,一方爲空時用null填充
select e.name 員工名稱,d.name 部門名稱
from
employees e full join department d
on e.dep_id=d.id;
- 交叉連接(笛卡爾積) cross
select e.name 員工名稱,d.name 部門名稱
from
employees e cross join department d
on e.dep_id=d.id;
5,子查詢
- select子查詢:只能子查詢一行一列的
-- 查詢每個部門的員工個數
selec d.* ,(
select count(*) from employees e
where e.dep_id = d.id
) from department d;
- from子查詢:子查詢結果當做表使用
- where/having子查詢
- exists子查詢:標識查詢的結果是否存在,返回1(存在)或0(不存在)
6,分頁查詢
- limit
-- limit 開始索引,查詢條數
select * from employees limit 5;
select * from employees limit 0,5;
7,聯合查詢
- union:將多條語句的查詢結果合併成一個結果
select name,age from employees
union
select user_name,user_age from user;
特點:
- 要求union的多條查詢語句字段數量一致,否則報錯;
- union的字段順序最好一致,默認按照第一條語句的字段名稱順序顯示;
- union會根據所查字段內容進行去重,如果多條sql中有相同的字段結果則會被去重,如果想避免去重,需使用union all ;
8,六大約束&一大標識
- not null:非空約束,保證字段非空;
- default:默認約束,保證有默認值;
- primary key:主鍵約束,保證非空且唯一;
- unique:唯一約束,唯一但可以爲空;
- check:檢查約束,mysql不支持;
- foreign key:外鍵約束,限定表之間的關係 ;
- auto_increment:自增長,定義列的自增長標識;通過set auto_increment_increment=10,來設置自增步長,alter table table_name auto_increment =10000,設置自增初始值;
9,事務
mysql存儲引擎Innodb支持事務;
事務的ACID
- 原子性(Atomicity):是指事務是一個不可分割的單元,事務中的操作要麼全發生,要麼都不發生;
- 一致性(Consistency):事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態;
- 隔離性(Isolation):是指一個事務的執行不能被其他事務干擾,即一個事務的內部操作及使用的數據對併發的其他操作的事務是隔離的,併發執行的各個事務之間不能相互干擾;
- 持久性(Durability):是指一個事務一旦被提交,那麼他對數據庫中數據的改變是永久性的,即使數據庫故障都不應該對其有任何影響;
事務的創建
- 隱式事務:事務沒有明顯的開啓和結束的標記,如:insert、update、delete語句的執行;
- 顯式事務:事務具有明顯的開啓和結束的標記,但必須關閉事務的自動提交,手動去觸發事務開啓、關閉,如:用set autocommit=0關閉事務的自動提交(關閉只對當前事務有效),用commit提交事務,用rollback回滾事務;
常見數據庫讀錯誤
- 髒讀:對於兩個事務T1,T2,T1讀取了T2更新但沒有提交的數據,之後若T2回滾了,T1讀取的內容就是臨時且無效的數據(更新時);
- 不可重複讀:對於兩個事務T1,T2,T1讀取了一字段,然後T2修改了該字段,之後T1再去讀取該字段發現值不一樣了;
- 幻讀:對於兩個事務T1,T2,T1從表中讀取一些行,然後T2在表中插入了新的行,之後T1再去讀取的時候發現行多了(插入時);
事務的隔離級別
隔離級別 | 表述 |
---|---|
read uncommited(讀未提交數據) | 允許事務讀取其他事務沒有提交的變更,可能會出現髒讀、不可重複讀、幻讀 |
read commited(讀已提交數據) | 只允許事務讀取其他事務已經提交的變更,可以避免髒讀,但不能避免不可重複讀、幻讀 |
repeatable read(可重複讀) | 確保事務可以多次從一個字段中讀取相同的值,在本次事務持續期間,禁止其他事務對這個字段進行更改,可以避免髒讀、不可重複讀,但可能出現幻讀 |
serializable(串行化) | 確保事務可以多次從一個字段中讀取相同的值,在本次事務持續期間,禁止其他事務對該整張表的插入、刪除、修改,可以避免所有併發問題,但性能低 |
注:
- mysql默認隔離級別爲repeatable read(可重複讀);
- oracle默認隔離級別爲read commited(讀已提交)
- delete支持事務回滾,truncate不支持事務回滾
- repeatable read相當於行級鎖,serializable相當於表級鎖;
回滾點
set autocommit = 0;
start transaction ;
delete from user where id = 10;
savepoint a;-- 設置名稱爲a的保存點
delete from user where id = 11;
rollback to a;-- 回滾到保存點a,此時10唄刪除,11得以回滾
10,視圖
一種虛擬的表,和普通表一樣使用,可以將一些複雜的查詢封裝的一個視圖中,當做一個新的臨時表,在使用時動態生成虛擬表;
- 創建視圖
create view 視圖名稱V1
as
複雜的sql語句;
-- 使用視圖
select * from V1 where xxx
- 修改視圖
create or replace view 視圖名稱V1
as
複雜的sql語句;
------------------------
alter view 視圖名稱V1
as
複雜的sql語句;
- 刪除視圖
drop view 視圖名V1,視圖名V2....
- 視圖查看
desc 視圖名稱V1;
show create view 視圖名稱V1;
- 視圖修改:對視圖的增刪改都會同步修改原始表,但複雜sql中包含:分組函數、distinct、group by、having、union、union all、子查詢、join、from後跟一個不能修改的視圖、where語句的子查詢引用了from中的表時,或視圖爲常量視圖時,視圖不允許更新;
11,變量
系統變量
- 全局變量:
-- 查看全部系統變量
show global variables;
-- 查看指定系統變量
select @@global 系統變量名 ;-- 或模糊查詢 show global variables like ‘xxx’
- 會話變量
-- 查看全部會話變量 session可以省略,查詢方式同上
show session variables;
- 系統變量賦值
-- 或 set @@ 系統變量名 = 值;
set 系統變量名 = 值;
自定義變量
- 用戶變量
-- 初始化/賦值
set @用戶變量名 = 值;
set @用戶變量名 := 值;
select @用戶變量名 := 值;
- 局部變量
-- 只在begin ... end 中有效
declare 變量名 類型 default 值;
-- 初始化/賦值
set 局部變量名 = 值;
set 局部變量名 := 值;
select @局部變量名 := 值;
select 值 into 變量名
-- 使用
select 局部變量名;
12,存儲過程&函數
一組預先編譯好的sql語句的集合;
存儲過程
存儲過程創建
delimiter $
create procedure 存儲過程名(參數列表)
begin
存儲過程體(一組sql語句體);-- 過程體只有一句時,begin...end 可以省略
end $
-- 參數列表:參數模式 參數名 參數類型,如:in nume varchar(20)
-- 參數模式:in、out、inout,in修飾的爲入參,out修飾的可以爲出參,inout兩者皆可
delimiter 結束標記 -- 如:delimiter $
存儲過程調用
call 存儲過程名(實參列表) $ -- 注意結束標記,需要統一
函數
函數創建
delimiter $
create function 函數名(參數列表) returns 返回類型
begin
函數體;(一組sql語句體,含return 值);-- 過程體只有一句時,begin...end 可以省略
return 結果;
end $
-- 參數列表:參數名 參數類型,如:in nume varchar(20)
-- 函數體:必須有返回體,否則會報錯
delimiter 結束標記 -- 如:delimiter $
函數調用
select 函數名(實參列表) $ -- 注意結束標記,需要統一
13,流程控制結構
- 順序結構
-- if函數
select if(表達式1,表達式2,表達式3)
-- 如果表達式1爲true,則返回表達式2,否則返回表達式3
-- if結構(只能用在begin...end中)
if 條件1 then 語句1;
elseif 條件2 then 語句2;
...
else 語句n;
end if;
- 分支結構
-- case1
select xxx
case 變量|表達式|字段
when 要判斷的值 then 返回值1或語句1;
when 要判斷的值 then 返回值2或語句2;
...
else 返回值n或語句n;
end case;
-- case2
select xxx
case
when 條件1 then 返回值1或語句1;
when 條件2 then 返回值2或語句2;
...
else 返回值n或語句n;
end case;
- 循環結構
-- while
名稱1: while 循環條件 do
循環體;
end while 名稱1;
-- loop
名稱2: loop
循環體;
end loop 名稱2;
-- repeat
名稱3: repeat
循環體;
until 結束條件
end repeat 名稱3;
實例
-- 向user 表中插入數據,只插入爲偶數時的數據,並且超過100的時候退出
delimiter $
create procedure test(into num int)
begin
declare i int default 0;
a:while i<=num do
set i=i+1;
if mod(i,2)!=0 then iterate a; -- iterate(相當於java中continue)
end if;
if i==100 then leave a; -- leave(相當於java中break)
end if;
insert into user(username,password) values(concat('neei',i),1000+i);
end while a;
end $