好久没有复习SQL语句了,今天简单温习一下。
SQL语句执行顺序
语法顺序:select–from–where–group by–having–order by
执行顺序:from–where–group by–having–select–order by
(select的顺序与语法顺序稍微不一样)
from: 从哪个数据表检索数据
where: 过滤表中数据的条件
group by: 如何将上面过滤出的数据分组
having: 对上面group by已经分组的数据进行过滤的条件
select: 查看结果集中的哪个列,或列的计算结果
order by :按照什么样的顺序来查看返回的数据
以下是祖传的数据练习样例,想学习的可以尝试写一写
简单的数据库使用情景
数据库对象
- 用SQL命令创建三张表:Sailors、Boats、Reserves
具体信息如下:
Sailors(sid char(10),sname char(20),rating int,age int),
其中sid是主关键字,sid表示水手的编号,sname表示水手的姓名,rating表示水手的级别,age表示水手的年龄。
CREATE TABLE `sailors` (
`sid` char(10) NOT NULL,
`sname` char(20) NOT NULL,
`rating` int(11) NOT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`sid`)
)
Boats(bid char(10),bname char(20),color char(10)),其中bid表示船的编号是主关键字,bname是船的名字,color是船的颜色
CREATE TABLE `boats` (
`bid` char(10) NOT NULL,
`bname` char(20) NOT NULL,
`color` char(10) NOT NULL,
PRIMARY KEY (`bid`)
)
Reserves(sid char(10),bid char(10),rdate date),
Reserves中记录水手在哪天定了那只船,其中sid是指向Sailors的外关键字,bid是指向Boats的外关键字,(sid,bid,rdate)合起来构成Reserves的主关键字。当sailors或Boats中的相关记录被删除时要求Reservers中的记录也被联带删除。
CREATE TABLE `reserves` (
`sid` char(10) NOT NULL,
`rdate` date NOT NULL,
`bid` char(20) NOT NULL,
PRIMARY KEY (`sid`,`rdate`,`bid`),
KEY `bid_idx` (`bid`),
CONSTRAINT `bid` FOREIGN KEY (`bid`) REFERENCES `boats` (`bid`) ON DELETE CASCADE,
CONSTRAINT `sid` FOREIGN KEY (`sid`) REFERENCES `sailors` (`sid`) ON DELETE CASCADE
)
/*constraint 外键名 foreign key 外键字段 references 主表名(关联字段) [主表记录删除时的动作] [主表记录更新时的动作]
ON DELETE、ON UPDATE表示事件触发限制,可设参数:
RESTRICT(限制外表中的外键改动,默认值)
CASCADE(跟随外键改动,同删/同更新)
SET NULL(设空值)
SET DEFAULT(设默认值)
NO ACTION(无动作,默认的)
*/
- 在以上三表中插入数据,这里给出我的插入:
INSERT INTO 语句
INSERT INTO 语句用于向表格中插入新的行。
语法
INSERT INTO 表名称 VALUES (值1, 值2,…)
指定所要插入数据的列:
INSERT INTO table_name (列1, 列2,…) VALUES (值1, 值2,…)
//sailors 表
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("22","dustin",7,45);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("58","rusty",10,35);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("29","brustus",1,33);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("64","horatio",7,35);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("31","lubber",8,56);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("71","zorba",10,35);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("32","andy",8,26);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("74","horatio",9,35);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("85","art",3,26);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("96","frodo",3,26);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("86","john",1,17);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("98","tom",3,17);
INSERT INTO Sailors(sid ,sname,rating,age)
VALUES("95","bob",3,64);
//Boats 表
INSERT INTO Boats(bid,bname,color)
VALUES("101","A","red");
INSERT INTO Boats(bid,bname,color)
VALUES("105","E","red");
INSERT INTO Boats(bid,bname,color)
VALUES("102","B","green");
INSERT INTO Boats(bid,bname,color)
VALUES("106","F","blue");
INSERT INTO Boats(bid,bname,color)
VALUES("103","C","blue");
INSERT INTO Boats(bid,bname,color)
VALUES("107","G","green");
INSERT INTO Boats(bid,bname,color)
VALUES("104","D","white");
//Reserves 表
INSERT INTO Reserves(sid,bid,rdate)
VALUES("22","101","2010-01-08");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("22","101","2010-04-07");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("22","102","2010-01-09");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("22","105","2010-05-01");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("29","103","2010-01-09");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("22","106","2010-06-18");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("31","102","2010-02-11");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("22","107","2010-07-09");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("22","104","2010-03-08");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("31","106","2010-08-06");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("22","103","2010-03-10");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("32","105","2010-08-06");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("32","105","2010-03-11");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("29","104","2010-08-07");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("32","106","2010-03-18");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("64","103","2010-09-05");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("32","102","2010-03-19");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("58","102","2010-09-09");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("58","104","2010-03-20");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("64","104","2010-11-03");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("64","105","2010-03-20");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("64","105","2010-11-04");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("95","101","2010-04-02");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("31","106","2010-12-06");
INSERT INTO Reserves(sid,bid,rdate)
VALUES("85","102","2010-04-05");*/
一些简单CURD操作(Create Update Retrieve Delete)
- 查找定了103号船的水手
SELECT s.*,r.bid
FROM reserves r,sailors s
WHERE r.bid = 103 AND s.sid = r.sid
//简单使用WHERE过滤即可
- 查找定了红色船水手的姓名
SELECT DISTINCT S.sname
FROM sailors S ,reserves R,boats B
WHERE S.sid=R.sid AND R.bid=B.bid AND B.color="red"
//注:distinct 意思是将两条完全相同的纪录变为一条
-
将年龄小于30的水手级别增加1.
更新操作:
UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值注:where用来限制更新哪些行,set后面用,分隔可以更新多列
varchar等字符串的拼接更新不用+,而用concat
CONCAT(str1,str2,…) 返回结果为连接参数产生的字符串
// update
UPDATE SAILORS S
SET S.rating = S.rating + 1
WHERE S.age < 30 ;
/*
若遇到以下错误:
Error Code: 1175 You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column”
Workbench的安全设置不允许我们在没有修改主键的情况下修改table,
我们通过设置就可以进行处理。具体操作是在workbench的菜单栏点击“edit-->Preferences”,
然后会弹出对话框“workbench preferences“,
在“workbench”左边栏点击“SQL Editor”,
会看到最后一行是“Safe Updates……”是打钩的,
我们只要缺消打钩应用即可
*/
- 删除名字叫lubber的水手的定船信息.
删除语法:
DELETE FROM 表名称 WHERE 列名称 = 值
delete
from reserves
where sid = (select sid from sailors where sname ="lubber")
/*
from 后面接一个table
初学者可以使用delete时会类比select的写法,可能写成以下形式
delete
from reserves r,sailor r
where r.sid = s.sid and s.name = "lubbe";
这样是一个语法错误!
*/
一些较复杂CURD操作
- 查找定过船而没有定过红色船的水手信息
简单的思路:
先找到订过红色船的水手,然后在所有订了船的水手中取not除掉前者,剩余的即为所求。
(最外面的select是为了获取水手的信息,其实sid在第二个select已经都拿到了)
select *
from sailors S
where S.sid in( select R.sid
from reserves R
where R.sid not in(select R.sid
from reserves R,boats B
where R.bid = B.bid and B.color="red") )
这里涉及到了in操作:
其过程为,首先查询子查询的表,然后将内表和外表做一个笛卡尔积,然后按照条件进行筛选。由于其放弃了索引,改为笛卡尔积+扫描,在内、外表特别大的时候不推荐使用。
select * 打印多余信息,工程上尽量少用
-
查找定过所有船的水手姓名和编号
exists:指定一个子查询,检测行的存在。遍历循环外表,然后看外表中的记录有没有和内表的数据一样,匹配上就将结果放入结果集中,其每次查询外表值是否在内表存在,会尝试使用内表的索引。
相较于in,in会把B表放在内存里遍历比较,exists会查询数据库索引。通常来说exists性能更优,但是表小的时候in可能效果更佳,具体还是要看应用情况。
select S.sname,S.sid
from sailors S
where not exists(select * /*不存在有船没被sid定*/
from boats B
where not exists(select distinct R.bid /*某个水手其订的所有船*/
from reserves R
where R.sid = S.sid and R.bid = B.bid) )
- 查找年龄最大的水手姓名和年龄
MAX() 函数
MAX 函数返回一列中的最大值。NULL 值不包括在计算中。
select S.sname,S.age
from sailors S
where S.age = (select max(S.age)
from sailors S)
-
统计水手表中每个级别组的平均年龄和级别组
AVG 函数返回数值列的平均值。NULL 值不包括在计算中。
select avg(S.age) as 平均年龄,S.rating as 级别组
from sailors S
group by S.rating
//avg这个对group以后的分组数据取平均值,as的别名依据需求设置
-
统计水手表中每个人数不少于2人的级别组中年满18岁水手的平均年龄和级别组
分析:对组有要求用having 注意语句执行顺序,先where再group
count() 函数返回匹配指定条件的行数。
count()(column_name) 函数返回指定列的值的数目(NULL 不计入):
count(*)—包括所有列,返回表中的记录数,相当于统计表的行数,在统计结果的时候,记录NULL的记录。
count(DISTINCT column_name) 函数返回指定列的不同值的数目
select avg(S.age) as 平均年龄,S.rating as 级别组
from sailors S
where S.sid in(select S1.sid
from sailors S1
where S1.age > 18)
group by S.rating
having count(1) >= 2
- 统计水手表中人数最少的级别组及人数
首先得找到分组的数据表用count(),然后用min()取人数最少
from 中用temp做临时表
select temp.ranks,temp.people
from (select S.rating as ranks,count(*) as people
from sailors S
group by S.rating) as temp
where temp.people = (select min(temp.people)
from (select S.rating as ranks,count(*) as people
from sailors S
group by S.rating) as temp);
补充一点:
当我们需要从数据源上 直接判断数据显示代表的含义的时候 ,就可以在SQL语句中使用 Case When这个函数;
MySQL 的 case when 的语法:
简单函数
CASE [col_name] WHEN [value1] THEN [result1]…ELSE [default] END
搜索函数
CASE WHEN [expr] THEN [result1]…ELSE [default] END
简单例子:
查询男生、女生的人数;
select
count(case when student.gender = "男" then 1 end) as "男生人数" ,
count(case when student.gender = "女" then 1 end) as "女生人数"
from student
按各科平均成绩从低到高和及格率的百分数从高到低顺序;
select score.Course_id as 课程id , avg(score.number) as 平均成绩,
100 * sum(case when score.number >= 60 then 1 else 0 end) / count(*) as 及格率
from score
group by 课程id
order by 平均成绩 asc,
及格率 desc;