1.mysql高級
1.關系
創建學生成績關系表
drop table if exists scores;
drop table if exists students;
drop table if exists subjects;
create table students(
id int auto_increment primary key,
sname varchar(20)
);
create table subjects(
id int auto_increment primary key,
stitle varchar(20)
);
/*
create table scores(
id int auto_increment primary key,
stuid int,
subid int,
score decimal(5,2),
foreign key(stuid) references students(id), #引用的第一種寫法
foreign key(subid) references subjects(id)
);
*/
create table scores(
id int auto_increment primary key,
stuid int,
subid int,
score decimal(5,2)
);
#引用的第二種寫法
alter table scores
add constraint fk_scores_stuid foreign key(stuid)
references students(id) on delete cascade; #外鍵的級聯操作
alter table scores
add constraint fk_scores_subid foreign key(subid)
references subjects(id) on delete cascade;
insert into students(sname) values('小茗');
insert into students(sname) values('可樂');
insert into students(sname) values('小伊');
insert into subjects(stitle) values('語文');
insert into subjects(stitle) values('數學');
insert into subjects(stitle) values('英語');
select * from students;
select * from subjects;
select * from scores;
insert into scores(stuid,subid,score) values(1,1,88);
insert into scores(stuid,subid,score) values(1,2,90);
insert into scores(stuid,subid,score) values(2,3,99);
insert into scores(stuid,subid,score) values(2,1,70);
-- 查詢一個學生各科的成績
select t1.id,t1.sname,t2.score
from students t1,scores t2
where t1.id = t2.stuid;
三張表如圖
查詢一個學生各科成績的結果
級聯操作的類型包括:
- restrict(限制):默認值,拋異常
- cascade(級聯):如果主表的記錄刪掉,則從表中相關聯的記錄都將被刪除
- set null:將外鍵設置為空
- no action:什么都不做
2.連接查詢
- 當需要對有關系的多張表進行查詢時,需要使用連接 join
連接查詢分類如下:
-
表A inner join 表B
:表A與表B匹配的行會出現在結果中 -
表A left join 表B
:表A與表B匹配的行會出現在結果中,外加表A中獨有的數據,未對應的數據使用null填充 -
表A right join 表B
:表A與表B匹配的行會出現在結果中,外加表B中獨有的數據,未對應的數據使用null填充
- 在查詢或條件中推薦使用“表名.列名”的語法
- 如果多個表中列名不重復可以省略“表名.”部分
- 如果表的名稱太長,可以在表名后面使用' as 簡寫名'或' 簡寫名',為表起個臨時的簡寫名稱
實例一
-- 先建立關系表
drop table if exists x_emp;
drop table if exists x_dept;
create table x_dept(
id int auto_increment primary key,
dname varchar(20)
);
create table x_emp(
id int auto_increment primary key,
ename varchar(20),
did int not null,
mgr int,
foreign key(did) references x_dept(id),
foreign key(mgr) references x_emp(id)
);
insert into x_dept(dname) values('研發部');
insert into x_dept(dname) values('人事部');
insert into x_dept(dname) values('財務部');
insert into x_emp(ename,did,mgr) values('老王',1,null);
insert into x_emp(ename,did,mgr) values('老張',1,1);
insert into x_emp(ename,did,mgr) values('老趙',1,1);
insert into x_emp(ename,did,mgr) values('小茗',2,3);
insert into x_emp(ename,did,mgr) values('小伊',2,3);
select * from x_dept;
select * from x_emp;
創建的兩個表
/*查詢員工的編號,姓名,上級的姓名*/
select * from x_emp 員工表,x_emp 上級表
where 員工表.mgr = 上級表.id;
-- 第一種寫法
select t1.id,t1.ename,t2.ename
from x_emp t1,x_emp t2
where t1.mgr = t2.id;
-- 第二種寫法
select t1.id,t1.ename,t2.ename
from x_emp t1
inner join x_emp t2
on t1.mgr = t2.id;
查詢員工額編號,姓名,上級的姓名
-- 'left',表x_emp與表x_dept匹配的行會出現在結果中,外加表x_emp中獨有的數據,未對應的數據使用null填充
select *
from x_emp left outer join x_dept
on x_emp.did = x_dept.id;
left
-- 'right',表x_emp與表x_dept匹配的行會出現在結果中,外加表x_dept中獨有的數據,未對應的數據使用null填充
select *
from x_emp right outer join x_dept
on x_emp.did = x_dept.id;
right
/*x_emp中,查詢是經理的人的名字
1、哪些是經理啊?
2、再找名字
*/
select ename
from x_emp
where id in(
select mgr from x_emp
);
查詢哪些是經理
實例二
drop table if exists scores;
drop table if exists students;
drop table if exists subjects;
create table students(
id int auto_increment primary key,
sname varchar(20)
);
create table subjects(
id int auto_increment primary key,
stitle varchar(20)
);
create table scores(
id int auto_increment primary key,
stuid int,
subid int,
score decimal(5,2),
foreign key(stuid) references students(id),
foreign key(subid) references subjects(id)
);
insert into students(sname) values('小茗');
insert into students(sname) values('可樂');
insert into students(sname) values('小伊');
insert into subjects(stitle) values('語文');
insert into subjects(stitle) values('數學');
insert into subjects(stitle) values('英語');
insert into scores(stuid,subid,score) values(1,1,88);
insert into scores(stuid,subid,score) values(1,2,90);
insert into scores(stuid,subid,score) values(2,3,99);
insert into scores(stuid,subid,score) values(3,1,70);
select * from students;
select * from subjects;
select * from scores;
創建的三個表
/*查詢學生的編號,姓名,科目的名稱,成績*/
-- 三種方法都可以
select t1.id,t1.sname,t2.stitle,t3.score
from students t1,subjects t2,scores t3
where t3.stuid = t1.id and t3.subid = t2.id;
select t1.id,t1.sname,t2.stitle,t3.score
from scores t3
inner join students t1
on t3.stuid = t1.id
inner join subjects t2
on t3.subid = t2.id;
select t1.id,t1.sname,t2.stitle,t3.score
from students t1
inner join scores t3
on t3.stuid = t1.id
inner join subjects t2
on t3.subid = t2.id;
查詢學生的編號,姓名,科目的名稱,成績
實例三
drop table if exists emp1;
drop table if exists salgrade;
create table emp1(
id int auto_increment primary key,
name VARCHAR(20),
sal int
);
create table salgrade(
id int auto_increment primary key,
low int,
high int
);
insert into emp1(name,sal) values('小茗',4000);
insert into emp1(name,sal) values('可樂',5000);
insert into emp1(name,sal) values('小伊',8800);
insert into salgrade(low,high) values(1000,3999);
insert into salgrade(low,high) values(4000,7999);
insert into salgrade(low,high) values(8000,10000);
select * from emp1;
select * from salgrade;
創建的兩個表
-- 查詢員工的編號,工資和等級
select t1.id,t1.name,t1.sal,t2.id
from emp1 t1 inner join salgrade t2
on t1.sal between t2.low and t2.high;
查詢員工的編號,工資和等級
create view myView2
as
select * from emp1;
delete from emp1;
select * from myView2;
delete from emp1后,表emp1數據為空
實例四
/*查詢各學生的語文、數學、英語的成績*/
select sname,
(select sco.score from scores sco inner join subjects sub on sco.subid=sub.id where sub.stitle='語文' and stuid=stu.id) as 語文,
(select sco.score from scores sco inner join subjects sub on sco.subid=sub.id where sub.stitle='數學' and stuid=stu.id) as 數學,
(select sco.score from scores sco inner join subjects sub on sco.subid=sub.id where sub.stitle='英語' and stuid=stu.id) as 英語
from students stu;
-- 這里我們可以用視圖來查詢,視圖的用途就是查詢
/*視圖*/
create view myView
as
select sname,
(select sco.score from scores sco inner join subjects sub on sco.subid=sub.id where sub.stitle='語文' and stuid=stu.id) as 語文,
(select sco.score from scores sco inner join subjects sub on sco.subid=sub.id where sub.stitle='數學' and stuid=stu.id) as 數學,
(select sco.score from scores sco inner join subjects sub on sco.subid=sub.id where sub.stitle='英語' and stuid=stu.id) as 英語
from students stu;
select * from myView;
select sname from myView;
查詢各學生的語文、數學、英語的成績
用視圖以后查詢的結果如圖
事務
- 當一個業務邏輯需要多個sql完成時,如果其中某條sql語句出錯,則希望整個操作都退回,保證數據的正確性。
- 使用事務可以完成退回的功能,保證業務邏輯的正確性
- 兩個功能:有一個出問題,回滾。都沒有問題,提交。(同生共死)
事務四大特性(簡稱ACID)
- 原子性(Atomicity):事務中的全部操作在數據庫中是不可分割的,要么全部完成,要么均不執行
- 一致性(Consistency):幾個并行執行的事務,其執行結果必須與按某一順序串行執行的結果相一致
- 隔離性(Isolation):事務的執行不受其他事務的干擾,事務執行的中間結果對其他事務必須是透明的
- 持久性(Durability):對于任意已提交事務,系統必須保證該事務對數據庫的改變不被丟失,即使數據庫出現故障
要求:表的類型必須是innodb或bdb類型(表的默認類型就是innodb),才可以對此表使用事務
查看表的創建語句
show create table students;
修改表的類型
alter table '表名' engine=innodb;
事務語句
- 開啟
begin
; - 提交
commit
; - 回滾
rollback
;
示例
drop table if exists bank;
create table bank(
id int primary key,
name varchar(20),
money int
);
insert into bank values(1,'王明哲',100);
insert into bank values(2,'張妙涵',1);
select * from bank;
update bank set money = money-10 where id=1;
update bank set money = money+10 where id=2;
select * from bank;
-- 查看建表語句
show create table students;
CREATE TABLE `students` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sname` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
-- 從建表語句中我們可以看出默認的是InnoDB類型
/*事務,一般用來做測試*/
begin;
delete from bank;
rollback;
commit;
用事務來進行測試
3.內置函數
1.字符串函數
/*字符串函數,sql里函數都是有返回值的*/
-- 查看字符的ascii碼值ascii(str),str是空串時返回0
select ascii('a');
97
-- 查看ascii碼值對應的字符char(數字)
select char(97);
a
-- 拼接字符串concat(str1,str2...)
select concat(12,34,'ab','小茗');
1234ab小茗
-- 包含字符個數length(str)
select length('中a')
4
select length(ename),ename from x_emp;
/*截取字符串
left(str,len)返回字符串str的左端len個字符
right(str,len)返回字符串str的右端len個字符
substring(str,pos,len)返回字符串str的位置pos起len個字符*/
select substring('abc123',2,3);
bc1
/*去除空格
ltrim(str)返回刪除了左空格的字符串str
rtrim(str)返回刪除了右空格的字符串str
trim([方向 remstr from str)返回從某側刪除remstr后的字符串str,方向詞包括both、leading、trailing,表示兩側、左、右*/
select trim(' bar ');
bar
select trim(leading 'x' FROM 'xxxbarxxx');
barxxx
select trim(both 'x' FROM 'xxxbarxxx');
bar
select trim(trailing 'x' FROM 'xxxbarxxx');
xxxbar
--返回由n個空格字符組成的一個字符串space(n)
select space(10);
-- 替換字符串replace(str,from_str,to_str)
select replace('abc123','123','def');
-- 大小寫轉換,函數如下
lower(str)
upper(str)
select lower('aBcD');
2.數學函數
-- 求絕對值abs(n)
select abs(-32);
32
-- 求m除以n的余數mod(m,n),同運算符%
select mod(10,3);
1
select 10%3;
1
-- 地板floor(n),表示不大于n的最大整數
select floor(2.3);
2
-- 天花板ceiling(n),表示不小于n的最大整數
select ceiling(2.3);
3
-- 求四舍五入值round(n,d),n表示原數,d表示小數位置,默認為0
select round(1.6);
2
-- 求x的y次冪pow(x,y)
select pow(2,3);
8
-- 獲取圓周率PI()
select PI();
3.141593
-- 隨機數rand(),值為0-1.0的浮點數
select rand();
0.7000933091157053
select floor(2.3),ceil(2.3),round(2.3456,2);
2 3 2.35
3.日期函數
獲取子值,語法如下:
-
year(date)
返回date的年份(范圍在1000到9999) -
month(date)
返回date中的月份數值 -
day(date)
返回date中的日期數值 -
hour(time)
返回time的小時數(范圍是0到23) -
minute(time)
返回time的分鐘數(范圍是0到59) -
second(time)
返回time的秒數(范圍是0到59) - 日期計算,使用+-運算符,數字后面的關鍵字為year、month、day、
hour、minute、second - 日期格式化date_format(date,format),format參數可用的值如下
- 獲取年%Y,返回4位的整數
- 獲取年%y,返回2位的整數
- 獲取月%m,值為1-12的整數
- 獲取日%d,返回整數
- 獲取時%H,值為0-23的整數
- 獲取時%h,值為1-12的整數
- 獲取分%i,值為0-59的整數
- 獲取秒%s,值為0-59的整數
/*日期-->字符串*/
select date_format('2017-10-20','%Y年%m月%d日')
2017年10月20日
/*字符串-->日期*/
select str_to_date('2017年10月20日','%Y年%m月%d日')
2017-10-20
-- 當前日期current_date()
select current_date();
2017-06-23
-- 當前時間current_time()
select current_time();
21:21:55
-- 當前日期時間now()
select now();
2017-06-23 21:21:41
create table t1(
id int,
birthday date
);
insert into t1 values(1,'2017-10-20');
insert into t1 values(2,'2017/10/20');
insert into t1 values(3,str_to_date('2017年10月21日','%Y年%m月%d日'));
insert into t1 values('4','2017/10/20');
select * from t1;
/*日期-->字符串*/
select date_format('2017-10-20','%Y年%m月%d日')
/*字符串-->日期*/
select str_to_date('2017年10月20日','%Y年%m月%d日')
select current_date(),now();
4.時間與字符串的相互轉換
import time
import datetime
stime1 = '2015年10月20日'
#字符串--->時間time.struct_time
time1 = time.strptime(stime1,'%Y年%m月%d日')
print(time1)
結果:
time.struct_time(tm_year=2015, tm_mon=10, tm_mday=20, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=293, tm_isdst=-1)
#時間time.struct_time--->字符串
stime1 = time.strftime('%Y-%m-%d',time1)
print(stime1)
結果:
2015-10-20
dt = datetime.datetime.now()
print(dt)
結果:
2017-06-24 14:59:09.948008
dt = datetime.date(2017,6,24)
print(str(dt))
print(type(dt))
結果:
2017-06-24
<class 'datetime.date'>
dt = datetime.datetime(2017,6,24,14,23,45)
print(dt)
結果:
2017-06-24 14:23:45
dt = datetime.date(2017,6,24)
print(dt.timetuple())
結果:
time.struct_time(tm_year=2017, tm_mon=6, tm_mday=24, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=175, tm_isdst=-1)
dt = datetime.date(2017,6,24)
s = time.strftime('%Y/%m/%d',dt.timetuple())
print(s)
結果:
2017/06/24