数据库的设计范式数据库的设计范式
-
要求:每一个分量必须是不可分的数据项。
特点:
1)有主键,且主键不能为空。
2)字段不能再分。
2.第二范式(2NF)
要求:在范式一的基础上,且每一个非主属性完全函数依赖于主键。
特点:
1)满足第一范式。
2)表中的每一个非主属性,必须完全依赖于本表主键。
3)只有当一个表中,主键由两个或以上的属性组成的时候,才会出现不符合第二范式的情况。(如果出现不完全依赖那么只能发生在联合主键的情况下。
3.第三范式(3NF)
要求:在第二范式的基础上,且消除传递依赖性1)满足第二范式
2)所有的非主键列依赖于主键列
注:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余,但是没有数据冗余的数据库并不一定是最好的数据库,所以有没有冗余的设计,要综合来考虑
-----mysql的查询语句练习
学生表 student 学号 姓名 性别 出生年月日 所在班级
create table student(
sno varchar(20) primary key,
sname varchar(20) not null,
ssex varchar(12) not null,
sbirthday datetime,
cla int(12)
);
insert into student values("101","曾华","男","1977-09-01","95033");
insert into student values("102","匡明","男","1975-10-02","95031");
insert into student values("103","王丽","女","1976-01-23","95033");
insert into student values("105","匡yi明","男","1975-10-02","95031");
insert into student values("104","王er丽","女","1976-01-23","95033");
insert into student values("106","陆君","男","1974-06-03","95031");
--课程表 course 课程号 课程名称 教师编号
表的约束--外键约束 foreign key reference
1 外键约束
一个表中某字段的值,受另一张表中某个字段的限制
主表(父表):提供数据的表
从表(子表):外键所在的表(引用主表中唯一性字段(主健,唯一)的值)
外键的值只能是主表中对应字段的值或者为null
foreign key references 主表(字段) --无名
constraint 约束名 foreign key references 主表(字段) -- 有名
foreign key references 主表(字段)
constraint 约束名 foreign key references 主表(字段)
---------------------------------------
create table course(
cno varchar(20) primary key,
cname varchar(20) not null,
tno varchar(20) not null,
foreign key(tno) references teacher(tno)
);
insert into course values("3-105","计算机导论","825");
insert into course values("6-166","数字电路","856");
insert into course values("9-888","高等数学","831");
教师表 teacher 教师编号 教师名字 教师性别 出生年月日 职称所在部门
create table teacher(
tno varchar(20) primary key,
tname varchar(20) not null,
tsex varchar(10) not null,
tbirthday datetime,
prof varchar(20) not null,
depart varchar(20) not null
);
insert into teacher values("804","李诚","男","1958-12-02","副教授","计算机系");
insert into teacher values("856","张旭","男","1969-03-12","讲师","电子工程系");
insert into teacher values("825","王萍","女","1972-05-05","助教","计算机系");
insert into teacher values("831","刘冰","女","1977-08-14","副教授","电子工程系");
– 成绩表
– Score
– 学号
– 课程号
– 成绩
-----------drop table score;
create table score(
sno varchar(20) not null,
cno varchar(20) not null,
grade decimal,
foreign key(sno) references student(sno),
foreign key(cno) references course(cno),
primary key(sno,cno)
);
insert into score values("103","3-105","92");
insert into score values("103","6-166","85");
insert into score values("103","9-888","86");
insert into score values("105","3-105","88");
insert into score values("105","6-166","79");
insert into score values("105","9-888","75");
insert into score values("106","3-105","76");
insert into score values("106","6-166","81");
insert into score values("106","9-888","68");
sql 查询语句
select * from student; 查询student中的所有数据
select sname from student; 查询student中的sname字段的值
select distinct depart from teacher; 查询教师所有的单位既不重复的depart的值 -- distinct 去重
-- 查询score表中的成绩在60-80的所有记录。
-- 查询区间 between...and
select * from score where 60<grade<80;
select * from score where grade between 60 and 80;
-- 查询 score 表中成绩为85,86或88的纪录。
-- 表示或者的关系查询 in
select * from score where grade in(85,86,88);
mysql> select * from score where grade in(85,86,88);
+-----+-------+-------+
| sno | cno | grade |
+-----+-------+-------+
| 103 | 6-166 | 85 |
| 103 | 9-888 | 86 |
| 105 | 3-105 | 88 |
+-----+-------+-------+
3 rows in set (0.00 sec)
-- 查询student表中'96031'班或性别为女的同学纪录
-- or表示或者
select * from student where class='95031' or ssex='女';
-- 以cla降序查询student表中的所有记录。
-- 升序order by asc 降序 order by desc
select * from student order by cla desc;
-- 以cno升序,degree降序查询score 表中的所有记录
select * from score order by cno asc,grade desc;
mysql> select * from score order by cno asc,grade desc;
+-----+-------+-------+
| sno | cno | grade |
+-----+-------+-------+
| 103 | 3-105 | 92 |
| 105 | 3-105 | 88 |
| 106 | 3-105 | 76 |
| 103 | 6-166 | 85 |
| 106 | 6-166 | 81 |
| 105 | 6-166 | 79 |
| 103 | 9-888 | 86 |
| 105 | 9-888 | 75 |
| 106 | 9-888 | 68 |
+-----+-------+-------+
9 rows in set (0.00 sec)
-- 查询'95031'班的学生人数。
-- 统计count
select count(*) from student where cla='95031';
mysql> select count(*) from student where cla='95031';
+----------+
| count(*) |
+----------+
| 3 |
+----------+
1 row in set (0.00 sec)
-- 查询score表中的最高分的学生学号和课程号。(子查询或者排序)
-- 分析:找到最高分 select max(grade) from score;
-- 找到最高分的sno,cno
select sno,cno from score where grade=(select max(grade) from score);
-- 排序分析:limit 0,1 0表示开始索引,1表示取几个
-- select sno,cno,grade from score order by grade;
-- select sno,cno,grade from score order by grade desc limit 0,1;
mysql> select sno,cno from score where grade=(select max(grade) from score);
+-----+-------+
| sno | cno |
+-----+-------+
| 103 | 3-105 |
+-----+-------+
1 row in set (0.00 sec)
-- 查询每门课的平均成绩
-- avg(grade)
select avg(grade) from score where cno='9-888';
mysql> select avg(grade) from score where cno='9-888';
+------------+
| avg(grade) |
+------------+
| 76.3333 |
+------------+
1 row in set (0.00 sec)
-- 查询每门课
-- group by 分组
select cno,avg(grade) from score group by cno;
mysql> select cno,avg(grade) from score group by cno;
+-------+------------+
| cno | avg(grade) |
+-------+------------+
| 3-105 | 85.3333 |
| 6-166 | 81.6667 |
| 9-888 | 76.3333 |
+-------+------------+
3 rows in set (0.00 sec)
-- 查询score表中至少有2名学生选修的并以3开头的平均分数
-- where、聚合函数、having 在from后面的执行顺序:
-- where>聚合函数(sum,min,max,avg,count)>having
-- having条件 若须引入聚合函数来对group by 结果进行过滤 则只能用having
-- like 模糊查询 类似正则
-- 分析:先分组 select cno,avg(grade) from score group by cno
-- 第二步 having count(2)>=2
-- 第三步 and cno like '3%';
select cno,avg(grade),count(*) from score group by cno having count(cno)>=2 and cno like '3%';
注意:
1、where 后不能跟聚合函数,因为where执行顺序大于聚合函数。
2、where 子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使用where条件显示特定的行。
3、having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚组函数,使用having 条件显示特定的组,也可以使用多个分组标准进行分组。
-- 查询分数大于70,小于90的sno列。
select sno grade from score where 70<grade<90;
select sno grade from score where grade between 70 and 90;
-- 查询所有学生的sname,cno 和grade列
select sname,cno,grade from student as st,score as sc where st.sno=sc.sno;
mysql> select sname,cno,grade from student as st,score as sc where st.sno=sc.sno;
+--------+-------+-------+
| sname | cno | grade |
+--------+-------+-------+
| 王丽 | 3-105 | 92 |
| 王丽 | 6-166 | 85 |
| 王丽 | 9-888 | 86 |
| 匡yi明 | 3-105 | 88 |
| 匡yi明 | 6-166 | 79 |
| 匡yi明 | 9-888 | 75 |
| 陆君 | 3-105 | 76 |
| 陆君 | 6-166 | 81 |
| 陆君 | 9-888 | 68 |
+--------+-------+-------+
9 rows in set (0.00 sec)
-- 查询所有学生的sno,cname和grade列 course cname score sno and grade
select sno,cname,grade from course as c,score as s where c.cno=s.cno;
mysql> select sno,cname,grade from course as c,score as s where c.cno=s.cno;
+-----+------------+-------+
| sno | cname | grade |
+-----+------------+-------+
| 103 | 计算机导论 | 92 |
| 103 | 数字电路 | 85 |
| 103 | 高等数学 | 86 |
| 105 | 计算机导论 | 88 |
| 105 | 数字电路 | 79 |
| 105 | 高等数学 | 75 |
| 106 | 计算机导论 | 76 |
| 106 | 数字电路 | 81 |
| 106 | 高等数学 | 68 |
+-----+------------+-------+
9 rows in set (0.00 sec)
-- 查询所有学生的sname,cname和grade列
-- sname--student cname--course grade--score
select sname,cname,grade from student as st,course as c,score as sc where c.cno=sc.cno and st.sno=sc.sno;
mysql> select sname,cname,grade from student as st,course as c,s
c.cno=sc.cno and st.sno=sc.sno;
+--------+------------+-------+
| sname | cname | grade |
+--------+------------+-------+
| 王丽 | 计算机导论 | 92 |
| 王丽 | 数字电路 | 85 |
| 王丽 | 高等数学 | 86 |
| 匡yi明 | 计算机导论 | 88 |
| 匡yi明 | 数字电路 | 79 |
| 匡yi明 | 高等数学 | 75 |
| 陆君 | 计算机导论 | 76 |
| 陆君 | 数字电路 | 81 |
| 陆君 | 高等数学 | 68 |
+--------+------------+-------+
9 rows in set (0.00 sec)
-- 查询95031班的学生每门课的平均分数 avg()平均分时
-- in 表示或的关系
-- cla-95031--student表 grade--score表 课程名称 cname--course
select avg(grade),cno from score where sno in (select sno from student where cla='95031') group by cno;
select cla,avg(grade),cname from student as st,course as co,score as sc where st.sno=sc.sno and co.cno=sc.cno;
-- 查询选修3-105课程的成绩高于106号同学3-105成绩的所有同学的记录
select grade from score where sno='106' and cno='3-105';
select * from score where cno='3-105' and grade>(select grade from score where sno='106' and cno='3-105');
mysql> select * from score where cno='3-105' and grade>(select grade from score
where sno='106' and cno='3-105');
+-----+-------+-------+
| sno | cno | grade |
+-----+-------+-------+
| 103 | 3-105 | 92 |
| 105 | 3-105 | 88 |
+-----+-------+-------+
2 rows in set (0.00 sec)
-- 查询成绩高于学号106课程为3-105的成绩的所有记录
select * from score where grade>(select grade from score where sno='106' and cno='3-105');
-- 查询学号为108,101的同学同年出生的所有学生的sno,sname和sbirthday列。
-- 只要查年份 year(sbirthday)
select * from student where year(sbirthday) in (select year(sbirthday) from student where sno in (101,103));
-- 查询张旭教师任课的学生成绩。
select * from teacher where tname ='张旭';
select cno from course where tno=(select * from teacher where tname ='张旭');
-- 查询选修某课程的同学人数多于3人的教师姓名
select cno from score group by cno having count(*)>2;
select tname from teacher where tno=(select tno from course where cno=(select cno from score group by cno having count(*)>3));
-- 查询95033班和95031班的全体学生的记录
select * from student where cla in ('95033','95031');
-- 查询存在有85分以上成绩的课程cno.
select cno from score where grade>85;
-- 查询出计算机系教师所教课程的成绩表。
select * from score where cno in (select cno from course where tno in (select tno from teacher where depart="计算机系"));
-- 查询计算机系和电子工程系不同职称的教师的tname和prof。
-- union 求并集
select prof from teacher where depart='电子工程系';
select * from teacher where depart='计算机系' and prof not in(select prof from teacher where depart='电子工程系')
union
select * from teacher where depart='电子工程系' and prof not in(select prof from teacher where depart='计算机系');
mysql> select * from teacher where depart='计算机系' and prof not in(select pro
from teacher where depart='电子工程系')
-> union
-> select * from teacher where depart='电子工程系' and prof not in(select
rof from teacher where depart='计算机系');
+-----+-------+------+---------------------+------+------------+
| tno | tname | tsex | tbirthday | prof | depart |
+-----+-------+------+---------------------+------+------------+
| 825 | 王萍 | 女 | 1972-05-05 00:00:00 | 助教 | 计算机系 |
| 856 | 张旭 | 男 | 1969-03-12 00:00:00 | 讲师 | 电子工程系
|
+-----+-------+------+---------------------+------+------------+
2 rows in set (0.00 sec)
-- 查询选修编号为3-105课程且成绩至少高于选修编号为3-166的同学的cno,sno和grade,且成绩从高到低次序排列。
-- any 大于其中至少一个
select * from score where cno='6-166';
select * from score where cno='3-105';
select * from score where cno='3-105' and grade>any(select grade from score where cno='6-166')
order by grade desc;
-- 查询选修编号为3-105课程且成绩至少高于选修编号为3-166的同学的cno,sno和grade
-- all 表示所有
select * from score where cno='6-166';
select * from score where cno='3-105';
select * from score where cno='3-105' and grade>all(select grade from score where cno='6-166');
-- 查询所有教师和同学的name,sex和birthday.
select tname,tsex,tbirthday from teacher
union
select sname,ssex,sbirthday from student;
-- 查询所有女教师和女同学的name,sex和birthday
select tname,tsex,tbirthday from teacher where tsex='女'
union
select sname,ssex,sbirthday from student where ssex='女';
-- 查询成绩比该课程平均成绩低的同学的成绩表。
-- 复制表score为表a和表b
select con,avg(grade) from score group by cno;
select * from score a where grade<(select avg(grade) from score b where a.cno = b.cno);
mysql> select * from score a where grade<(select avg(grade) from score b where
a.cno = b.cno);
+-----+-------+-------+
| sno | cno | grade |
+-----+-------+-------+
| 105 | 6-166 | 79 |
| 105 | 9-888 | 75 |
| 106 | 3-105 | 76 |
| 106 | 6-166 | 81 |
| 106 | 9-888 | 68 |
+-----+-------+-------+
5 rows in set (0.00 sec)
-- 查询所有任课教师的tname和depart
select tname,depart from teacher where tno in (select tno from course);
-- 查询至少有俩名男生的班号。
select cla from student where ssex='男' group by cla having count(*)>1;
-- 查询student表中不性王的同学记录。
select * from student;
select * from student where sname not like '王%';
-- 查询student表中每个学生的姓名和年龄
-- year(now()) 查看当前年份
select sname,year(now())-year(sbirthday) from student;
-- 查询student表中最大值和最小的birthday的日期值
select max(sbirthday) as '最大值',min(sbirthday) as '最小值' from student;
mysql> select max(sbirthday) as '最大值',min(sbirthday) as '最小值' from student
;
+---------------------+---------------------+
| 最大值 | 最小值 |
+---------------------+---------------------+
| 1977-09-01 00:00:00 | 1974-06-03 00:00:00 |
+---------------------+---------------------+
1 row in set (0.00 sec)
-- 以班号和年龄从大到小的顺序查询studente表中的全部记录。
select * from student order by cla desc,sbirthday;
-- 查询男教师及其所上的课程
select * from course where tno in (select tno from teacher where tsex='男');
-- 查询最高分同学的sno,cno,和grade.
select * from score where grade=(select max(grade) from score);
-- 查询和王丽同性别的所有同学的sname
select ssex from student where sname='王丽';
select sname from student where ssex=(select ssex from student where sname='王丽');
-- 查询和王丽同性别并在同班的同学sname
select ssex from student where sname='王丽';
select sname from student where ssex=(select ssex from student where sname='王丽') and cla=(select cla from student where sname='王丽');
-- 查询所有选修计算机导论课程的男同学的成绩表。
select * from student where ssex='男';
select * from course where cname='计算机导论';
select * from score where cno=(select cno from course where cname='计算机导论') and sno in (select sno from student where ssex='男');
-- 假设用如下命令建立了一个grade表
create table gradeq(
low int(3),
upp int(3),
gradet char(1)
);
insert into gradeq values(90,100,'A');
insert into gradeq values(80,90,'B');
insert into gradeq values(70,80,'C');
insert into gradeq values(60,70,'D');
insert into gradeq values(50,60,'E');
-- 先查询所有学生的sno cno 和 gradet列
select sno,cno,gradet from score,gradeq where grade between low and upp;
mysql> select sno,cno,gradet from score,gradeq where grade between low and upp;
+-----+-------+--------+
| sno | cno | gradet |
+-----+-------+--------+
| 101 | 3-105 | A |
| 103 | 3-105 | A |
| 103 | 6-166 | B |
| 103 | 9-888 | B |
| 105 | 3-105 | B |
| 105 | 6-166 | C |
| 105 | 9-888 | C |
| 106 | 3-105 | C |
| 106 | 6-166 | B |
| 106 | 9-888 | D |
+-----+-------+--------+
10 rows in set (0.00 sec)
sql 的四种连接查询
-- 内连接 inner join 或者 join
-- 外连接
-- 左连接 left join 或者 left outer join
-- 有连接 right join 或者 right outer join
-- 完全外连接 full 或者 full outer join
创建俩个表
person表 id,name,cardId
create table person(
id int,
name varchar(20),
cardId int
);
insert into person values(1,'张三',1);
insert into person values(2,'李四',3);
insert into person values(3,'王五',6);
insert into person values(4,'马六',9);
card表 id,name
create table card(
id int,
name varchar(20)
);
insert into card values(1,'饭卡');
insert into card values(2,'中国卡');
insert into card values(3,'交通卡');
insert into card values(4,'招商卡');
insert into card values(5,'平安卡');
-- 并没有创建外键
-- inner join 查询(内连接) 或者可以使用join
-- 代码解析:俩张表连接以后使得cardId=id使用inner join 来连接
-- join 左右是我们关联的表 后跟on 后面的是条件
select * from person inner join card on person.cardId=card.id;
mysql> select * from person inner join card on person.cardId=card.id;
+------+------+--------+------+--------+
| id | name | cardId | id | name |
+------+------+--------+------+--------+
| 1 | 张三 | 1 | 1 | 饭卡 |
| 2 | 李四 | 3 | 3 | 交通卡 |
+------+------+--------+------+--------+
2 rows in set (0.00 sec)
-- left join 外连接(左连接)或者 left outer join
select * from person left join card on person.cardId=card.id;
mysql> select * from person left join card on person.cardId=card.id;
+------+------+--------+------+--------+
| id | name | cardId | id | name |
+------+------+--------+------+--------+
| 1 | 张三 | 1 | 1 | 饭卡 |
| 2 | 李四 | 3 | 3 | 交通卡 |
| 3 | 王五 | 6 | NULL | NULL |
| 4 | 马六 | 9 | NULL | NULL |
+------+------+--------+------+--------+
4 rows in set (0.00 sec)
-- 左外连接,会把左面的数据全都拿出来,而又变得数据条件相等的拿,不等的补NULL
-- right join 外连接(右链接) 或者 right outer join
select * from person right join card on person.cardId=card.id;
mysql> select * from person right join card on person.cardId=card.id;
+------+------+--------+------+--------+
| id | name | cardId | id | name |
+------+------+--------+------+--------+
| 1 | 张三 | 1 | 1 | 饭卡 |
| NULL | NULL | NULL | 2 | 中国卡 |
| 2 | 李四 | 3 | 3 | 交通卡 |
| NULL | NULL | NULL | 4 | 招商卡 |
| NULL | NULL | NULL | 5 | 平安卡 |
+------+------+--------+------+--------+
5 rows in set (0.00 sec)
-- 右外连接,会把右面的数据全都拿出来,而又变得数据条件相等的拿,不等的补NULL
-- full join 全外连接
----------- mysql 不支持 full join 外连接 ---------
select * from person full join card on person.cardId=card.id;
-- 所以mysql如果需要实现全外连接就需要用左连接union有链接即可
select * from person right join card on person.cardId=card.id
union
select * from person left join card on person.cardId=card.id;
mysql> select * from person right join card on person.cardId=card.id
-> union
-> select * from person left join card on person.cardId=card.id;
+------+------+--------+------+--------+
| id | name | cardId | id | name |
+------+------+--------+------+--------+
| 1 | 张三 | 1 | 1 | 饭卡 |
| NULL | NULL | NULL | 2 | 中国卡 |
| 2 | 李四 | 3 | 3 | 交通卡 |
| NULL | NULL | NULL | 4 | 招商卡 |
| NULL | NULL | NULL | 5 | 平安卡 |
| 3 | 王五 | 6 | NULL | NULL |
| 4 | 马六 | 9 | NULL | NULL |
+------+------+--------+------+--------+
7 rows in set (0.00 sec)
数据库的设计范式
-
要求:每一个分量必须是不可分的数据项。
特点:
1)有主键,且主键不能为空。
2)字段不能再分。
2.第二范式(2NF)
要求:在范式一的基础上,且每一个非主属性完全函数依赖于主键。
特点:
1)满足第一范式。
2)表中的每一个非主属性,必须完全依赖于本表主键。
3)只有当一个表中,主键由两个或以上的属性组成的时候,才会出现不符合第二范式的情况。(如果出现不完全依赖那么只能发生在联合主键的情况下。
3.第三范式(3NF)
要求:在第二范式的基础上,且消除传递依赖性1)满足第二范式
2)所有的非主键列依赖于主键列
注:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余,但是没有数据冗余的数据库并不一定是最好的数据库,所以有没有冗余的设计,要综合来考虑
-----mysql的查询语句练习
学生表 student 学号 姓名 性别 出生年月日 所在班级
create table student(
sno varchar(20) primary key,
sname varchar(20) not null,
ssex varchar(12) not null,
sbirthday datetime,
cla int(12)
);
insert into student values("101","曾华","男","1977-09-01","95033");
insert into student values("102","匡明","男","1975-10-02","95031");
insert into student values("103","王丽","女","1976-01-23","95033");
insert into student values("105","匡yi明","男","1975-10-02","95031");
insert into student values("104","王er丽","女","1976-01-23","95033");
insert into student values("106","陆君","男","1974-06-03","95031");
--课程表 course 课程号 课程名称 教师编号
表的约束--外键约束 foreign key reference
1 外键约束
一个表中某字段的值,受另一张表中某个字段的限制
主表(父表):提供数据的表
从表(子表):外键所在的表(引用主表中唯一性字段(主健,唯一)的值)
外键的值只能是主表中对应字段的值或者为null
foreign key references 主表(字段) --无名
constraint 约束名 foreign key references 主表(字段) -- 有名
foreign key references 主表(字段)
constraint 约束名 foreign key references 主表(字段)
---------------------------------------
create table course(
cno varchar(20) primary key,
cname varchar(20) not null,
tno varchar(20) not null,
foreign key(tno) references teacher(tno)
);
insert into course values("3-105","计算机导论","825");
insert into course values("6-166","数字电路","856");
insert into course values("9-888","高等数学","831");
教师表 teacher 教师编号 教师名字 教师性别 出生年月日 职称所在部门
create table teacher(
tno varchar(20) primary key,
tname varchar(20) not null,
tsex varchar(10) not null,
tbirthday datetime,
prof varchar(20) not null,
depart varchar(20) not null
);
insert into teacher values("804","李诚","男","1958-12-02","副教授","计算机系");
insert into teacher values("856","张旭","男","1969-03-12","讲师","电子工程系");
insert into teacher values("825","王萍","女","1972-05-05","助教","计算机系");
insert into teacher values("831","刘冰","女","1977-08-14","副教授","电子工程系");
– 成绩表
– Score
– 学号
– 课程号
– 成绩
-----------drop table score;
create table score(
sno varchar(20) not null,
cno varchar(20) not null,
grade decimal,
foreign key(sno) references student(sno),
foreign key(cno) references course(cno),
primary key(sno,cno)
);
insert into score values("103","3-105","92");
insert into score values("103","6-166","85");
insert into score values("103","9-888","86");
insert into score values("105","3-105","88");
insert into score values("105","6-166","79");
insert into score values("105","9-888","75");
insert into score values("106","3-105","76");
insert into score values("106","6-166","81");
insert into score values("106","9-888","68");
sql 查询语句
select * from student; 查询student中的所有数据
select sname from student; 查询student中的sname字段的值
select distinct depart from teacher; 查询教师所有的单位既不重复的depart的值 -- distinct 去重
-- 查询score表中的成绩在60-80的所有记录。
-- 查询区间 between...and
select * from score where 60<grade<80;
select * from score where grade between 60 and 80;
-- 查询 score 表中成绩为85,86或88的纪录。
-- 表示或者的关系查询 in
select * from score where grade in(85,86,88);
mysql> select * from score where grade in(85,86,88);
+-----+-------+-------+
| sno | cno | grade |
+-----+-------+-------+
| 103 | 6-166 | 85 |
| 103 | 9-888 | 86 |
| 105 | 3-105 | 88 |
+-----+-------+-------+
3 rows in set (0.00 sec)
-- 查询student表中'96031'班或性别为女的同学纪录
-- or表示或者
select * from student where class='95031' or ssex='女';
-- 以cla降序查询student表中的所有记录。
-- 升序order by asc 降序 order by desc
select * from student order by cla desc;
-- 以cno升序,degree降序查询score 表中的所有记录
select * from score order by cno asc,grade desc;
mysql> select * from score order by cno asc,grade desc;
+-----+-------+-------+
| sno | cno | grade |
+-----+-------+-------+
| 103 | 3-105 | 92 |
| 105 | 3-105 | 88 |
| 106 | 3-105 | 76 |
| 103 | 6-166 | 85 |
| 106 | 6-166 | 81 |
| 105 | 6-166 | 79 |
| 103 | 9-888 | 86 |
| 105 | 9-888 | 75 |
| 106 | 9-888 | 68 |
+-----+-------+-------+
9 rows in set (0.00 sec)
-- 查询'95031'班的学生人数。
-- 统计count
select count(*) from student where cla='95031';
mysql> select count(*) from student where cla='95031';
+----------+
| count(*) |
+----------+
| 3 |
+----------+
1 row in set (0.00 sec)
-- 查询score表中的最高分的学生学号和课程号。(子查询或者排序)
-- 分析:找到最高分 select max(grade) from score;
-- 找到最高分的sno,cno
select sno,cno from score where grade=(select max(grade) from score);
-- 排序分析:limit 0,1 0表示开始索引,1表示取几个
-- select sno,cno,grade from score order by grade;
-- select sno,cno,grade from score order by grade desc limit 0,1;
mysql> select sno,cno from score where grade=(select max(grade) from score);
+-----+-------+
| sno | cno |
+-----+-------+
| 103 | 3-105 |
+-----+-------+
1 row in set (0.00 sec)
-- 查询每门课的平均成绩
-- avg(grade)
select avg(grade) from score where cno='9-888';
mysql> select avg(grade) from score where cno='9-888';
+------------+
| avg(grade) |
+------------+
| 76.3333 |
+------------+
1 row in set (0.00 sec)
-- 查询每门课
-- group by 分组
select cno,avg(grade) from score group by cno;
mysql> select cno,avg(grade) from score group by cno;
+-------+------------+
| cno | avg(grade) |
+-------+------------+
| 3-105 | 85.3333 |
| 6-166 | 81.6667 |
| 9-888 | 76.3333 |
+-------+------------+
3 rows in set (0.00 sec)
-- 查询score表中至少有2名学生选修的并以3开头的平均分数
-- where、聚合函数、having 在from后面的执行顺序:
-- where>聚合函数(sum,min,max,avg,count)>having
-- having条件 若须引入聚合函数来对group by 结果进行过滤 则只能用having
-- like 模糊查询 类似正则
-- 分析:先分组 select cno,avg(grade) from score group by cno
-- 第二步 having count(2)>=2
-- 第三步 and cno like '3%';
select cno,avg(grade),count(*) from score group by cno having count(cno)>=2 and cno like '3%';
注意:
1、where 后不能跟聚合函数,因为where执行顺序大于聚合函数。
2、where 子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使用where条件显示特定的行。
3、having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚组函数,使用having 条件显示特定的组,也可以使用多个分组标准进行分组。
-- 查询分数大于70,小于90的sno列。
select sno grade from score where 70<grade<90;
select sno grade from score where grade between 70 and 90;
-- 查询所有学生的sname,cno 和grade列
select sname,cno,grade from student as st,score as sc where st.sno=sc.sno;
mysql> select sname,cno,grade from student as st,score as sc where st.sno=sc.sno;
+--------+-------+-------+
| sname | cno | grade |
+--------+-------+-------+
| 王丽 | 3-105 | 92 |
| 王丽 | 6-166 | 85 |
| 王丽 | 9-888 | 86 |
| 匡yi明 | 3-105 | 88 |
| 匡yi明 | 6-166 | 79 |
| 匡yi明 | 9-888 | 75 |
| 陆君 | 3-105 | 76 |
| 陆君 | 6-166 | 81 |
| 陆君 | 9-888 | 68 |
+--------+-------+-------+
9 rows in set (0.00 sec)
-- 查询所有学生的sno,cname和grade列 course cname score sno and grade
select sno,cname,grade from course as c,score as s where c.cno=s.cno;
mysql> select sno,cname,grade from course as c,score as s where c.cno=s.cno;
+-----+------------+-------+
| sno | cname | grade |
+-----+------------+-------+
| 103 | 计算机导论 | 92 |
| 103 | 数字电路 | 85 |
| 103 | 高等数学 | 86 |
| 105 | 计算机导论 | 88 |
| 105 | 数字电路 | 79 |
| 105 | 高等数学 | 75 |
| 106 | 计算机导论 | 76 |
| 106 | 数字电路 | 81 |
| 106 | 高等数学 | 68 |
+-----+------------+-------+
9 rows in set (0.00 sec)
-- 查询所有学生的sname,cname和grade列
-- sname--student cname--course grade--score
select sname,cname,grade from student as st,course as c,score as sc where c.cno=sc.cno and st.sno=sc.sno;
mysql> select sname,cname,grade from student as st,course as c,s
c.cno=sc.cno and st.sno=sc.sno;
+--------+------------+-------+
| sname | cname | grade |
+--------+------------+-------+
| 王丽 | 计算机导论 | 92 |
| 王丽 | 数字电路 | 85 |
| 王丽 | 高等数学 | 86 |
| 匡yi明 | 计算机导论 | 88 |
| 匡yi明 | 数字电路 | 79 |
| 匡yi明 | 高等数学 | 75 |
| 陆君 | 计算机导论 | 76 |
| 陆君 | 数字电路 | 81 |
| 陆君 | 高等数学 | 68 |
+--------+------------+-------+
9 rows in set (0.00 sec)
-- 查询95031班的学生每门课的平均分数 avg()平均分时
-- in 表示或的关系
-- cla-95031--student表 grade--score表 课程名称 cname--course
select avg(grade),cno from score where sno in (select sno from student where cla='95031') group by cno;
select cla,avg(grade),cname from student as st,course as co,score as sc where st.sno=sc.sno and co.cno=sc.cno;
-- 查询选修3-105课程的成绩高于106号同学3-105成绩的所有同学的记录
select grade from score where sno='106' and cno='3-105';
select * from score where cno='3-105' and grade>(select grade from score where sno='106' and cno='3-105');
mysql> select * from score where cno='3-105' and grade>(select grade from score
where sno='106' and cno='3-105');
+-----+-------+-------+
| sno | cno | grade |
+-----+-------+-------+
| 103 | 3-105 | 92 |
| 105 | 3-105 | 88 |
+-----+-------+-------+
2 rows in set (0.00 sec)
-- 查询成绩高于学号106课程为3-105的成绩的所有记录
select * from score where grade>(select grade from score where sno='106' and cno='3-105');
-- 查询学号为108,101的同学同年出生的所有学生的sno,sname和sbirthday列。
-- 只要查年份 year(sbirthday)
select * from student where year(sbirthday) in (select year(sbirthday) from student where sno in (101,103));
-- 查询张旭教师任课的学生成绩。
select * from teacher where tname ='张旭';
select cno from course where tno=(select * from teacher where tname ='张旭');
-- 查询选修某课程的同学人数多于3人的教师姓名
select cno from score group by cno having count(*)>2;
select tname from teacher where tno=(select tno from course where cno=(select cno from score group by cno having count(*)>3));
-- 查询95033班和95031班的全体学生的记录
select * from student where cla in ('95033','95031');
-- 查询存在有85分以上成绩的课程cno.
select cno from score where grade>85;
-- 查询出计算机系教师所教课程的成绩表。
select * from score where cno in (select cno from course where tno in (select tno from teacher where depart="计算机系"));
-- 查询计算机系和电子工程系不同职称的教师的tname和prof。
-- union 求并集
select prof from teacher where depart='电子工程系';
select * from teacher where depart='计算机系' and prof not in(select prof from teacher where depart='电子工程系')
union
select * from teacher where depart='电子工程系' and prof not in(select prof from teacher where depart='计算机系');
mysql> select * from teacher where depart='计算机系' and prof not in(select pro
from teacher where depart='电子工程系')
-> union
-> select * from teacher where depart='电子工程系' and prof not in(select
rof from teacher where depart='计算机系');
+-----+-------+------+---------------------+------+------------+
| tno | tname | tsex | tbirthday | prof | depart |
+-----+-------+------+---------------------+------+------------+
| 825 | 王萍 | 女 | 1972-05-05 00:00:00 | 助教 | 计算机系 |
| 856 | 张旭 | 男 | 1969-03-12 00:00:00 | 讲师 | 电子工程系
|
+-----+-------+------+---------------------+------+------------+
2 rows in set (0.00 sec)
-- 查询选修编号为3-105课程且成绩至少高于选修编号为3-166的同学的cno,sno和grade,且成绩从高到低次序排列。
-- any 大于其中至少一个
select * from score where cno='6-166';
select * from score where cno='3-105';
select * from score where cno='3-105' and grade>any(select grade from score where cno='6-166')
order by grade desc;
-- 查询选修编号为3-105课程且成绩至少高于选修编号为3-166的同学的cno,sno和grade
-- all 表示所有
select * from score where cno='6-166';
select * from score where cno='3-105';
select * from score where cno='3-105' and grade>all(select grade from score where cno='6-166');
-- 查询所有教师和同学的name,sex和birthday.
select tname,tsex,tbirthday from teacher
union
select sname,ssex,sbirthday from student;
-- 查询所有女教师和女同学的name,sex和birthday
select tname,tsex,tbirthday from teacher where tsex='女'
union
select sname,ssex,sbirthday from student where ssex='女';
-- 查询成绩比该课程平均成绩低的同学的成绩表。
-- 复制表score为表a和表b
select con,avg(grade) from score group by cno;
select * from score a where grade<(select avg(grade) from score b where a.cno = b.cno);
mysql> select * from score a where grade<(select avg(grade) from score b where
a.cno = b.cno);
+-----+-------+-------+
| sno | cno | grade |
+-----+-------+-------+
| 105 | 6-166 | 79 |
| 105 | 9-888 | 75 |
| 106 | 3-105 | 76 |
| 106 | 6-166 | 81 |
| 106 | 9-888 | 68 |
+-----+-------+-------+
5 rows in set (0.00 sec)
-- 查询所有任课教师的tname和depart
select tname,depart from teacher where tno in (select tno from course);
-- 查询至少有俩名男生的班号。
select cla from student where ssex='男' group by cla having count(*)>1;
-- 查询student表中不性王的同学记录。
select * from student;
select * from student where sname not like '王%';
-- 查询student表中每个学生的姓名和年龄
-- year(now()) 查看当前年份
select sname,year(now())-year(sbirthday) from student;
-- 查询student表中最大值和最小的birthday的日期值
select max(sbirthday) as '最大值',min(sbirthday) as '最小值' from student;
mysql> select max(sbirthday) as '最大值',min(sbirthday) as '最小值' from student
;
+---------------------+---------------------+
| 最大值 | 最小值 |
+---------------------+---------------------+
| 1977-09-01 00:00:00 | 1974-06-03 00:00:00 |
+---------------------+---------------------+
1 row in set (0.00 sec)
-- 以班号和年龄从大到小的顺序查询studente表中的全部记录。
select * from student order by cla desc,sbirthday;
-- 查询男教师及其所上的课程
select * from course where tno in (select tno from teacher where tsex='男');
-- 查询最高分同学的sno,cno,和grade.
select * from score where grade=(select max(grade) from score);
-- 查询和王丽同性别的所有同学的sname
select ssex from student where sname='王丽';
select sname from student where ssex=(select ssex from student where sname='王丽');
-- 查询和王丽同性别并在同班的同学sname
select ssex from student where sname='王丽';
select sname from student where ssex=(select ssex from student where sname='王丽') and cla=(select cla from student where sname='王丽');
-- 查询所有选修计算机导论课程的男同学的成绩表。
select * from student where ssex='男';
select * from course where cname='计算机导论';
select * from score where cno=(select cno from course where cname='计算机导论') and sno in (select sno from student where ssex='男');
-- 假设用如下命令建立了一个grade表
create table gradeq(
low int(3),
upp int(3),
gradet char(1)
);
insert into gradeq values(90,100,'A');
insert into gradeq values(80,90,'B');
insert into gradeq values(70,80,'C');
insert into gradeq values(60,70,'D');
insert into gradeq values(50,60,'E');
-- 先查询所有学生的sno cno 和 gradet列
select sno,cno,gradet from score,gradeq where grade between low and upp;
mysql> select sno,cno,gradet from score,gradeq where grade between low and upp;
+-----+-------+--------+
| sno | cno | gradet |
+-----+-------+--------+
| 101 | 3-105 | A |
| 103 | 3-105 | A |
| 103 | 6-166 | B |
| 103 | 9-888 | B |
| 105 | 3-105 | B |
| 105 | 6-166 | C |
| 105 | 9-888 | C |
| 106 | 3-105 | C |
| 106 | 6-166 | B |
| 106 | 9-888 | D |
+-----+-------+--------+
10 rows in set (0.00 sec)
sql 的四种连接查询
-- 内连接 inner join 或者 join
-- 外连接
-- 左连接 left join 或者 left outer join
-- 有连接 right join 或者 right outer join
-- 完全外连接 full 或者 full outer join
创建俩个表
person表 id,name,cardId
create table person(
id int,
name varchar(20),
cardId int
);
insert into person values(1,'张三',1);
insert into person values(2,'李四',3);
insert into person values(3,'王五',6);
insert into person values(4,'马六',9);
card表 id,name
create table card(
id int,
name varchar(20)
);
insert into card values(1,'饭卡');
insert into card values(2,'中国卡');
insert into card values(3,'交通卡');
insert into card values(4,'招商卡');
insert into card values(5,'平安卡');
-- 并没有创建外键
-- inner join 查询(内连接) 或者可以使用join
-- 代码解析:俩张表连接以后使得cardId=id使用inner join 来连接
-- join 左右是我们关联的表 后跟on 后面的是条件
select * from person inner join card on person.cardId=card.id;
mysql> select * from person inner join card on person.cardId=card.id;
+------+------+--------+------+--------+
| id | name | cardId | id | name |
+------+------+--------+------+--------+
| 1 | 张三 | 1 | 1 | 饭卡 |
| 2 | 李四 | 3 | 3 | 交通卡 |
+------+------+--------+------+--------+
2 rows in set (0.00 sec)
-- left join 外连接(左连接)或者 left outer join
select * from person left join card on person.cardId=card.id;
mysql> select * from person left join card on person.cardId=card.id;
+------+------+--------+------+--------+
| id | name | cardId | id | name |
+------+------+--------+------+--------+
| 1 | 张三 | 1 | 1 | 饭卡 |
| 2 | 李四 | 3 | 3 | 交通卡 |
| 3 | 王五 | 6 | NULL | NULL |
| 4 | 马六 | 9 | NULL | NULL |
+------+------+--------+------+--------+
4 rows in set (0.00 sec)
-- 左外连接,会把左面的数据全都拿出来,而又变得数据条件相等的拿,不等的补NULL
-- right join 外连接(右链接) 或者 right outer join
select * from person right join card on person.cardId=card.id;
mysql> select * from person right join card on person.cardId=card.id;
+------+------+--------+------+--------+
| id | name | cardId | id | name |
+------+------+--------+------+--------+
| 1 | 张三 | 1 | 1 | 饭卡 |
| NULL | NULL | NULL | 2 | 中国卡 |
| 2 | 李四 | 3 | 3 | 交通卡 |
| NULL | NULL | NULL | 4 | 招商卡 |
| NULL | NULL | NULL | 5 | 平安卡 |
+------+------+--------+------+--------+
5 rows in set (0.00 sec)
-- 右外连接,会把右面的数据全都拿出来,而又变得数据条件相等的拿,不等的补NULL
-- full join 全外连接
----------- mysql 不支持 full join 外连接 ---------
select * from person full join card on person.cardId=card.id;
-- 所以mysql如果需要实现全外连接就需要用左连接union有链接即可
select * from person right join card on person.cardId=card.id
union
select * from person left join card on person.cardId=card.id;
mysql> select * from person right join card on person.cardId=card.id
-> union
-> select * from person left join card on person.cardId=card.id;
+------+------+--------+------+--------+
| id | name | cardId | id | name |
+------+------+--------+------+--------+
| 1 | 张三 | 1 | 1 | 饭卡 |
| NULL | NULL | NULL | 2 | 中国卡 |
| 2 | 李四 | 3 | 3 | 交通卡 |
| NULL | NULL | NULL | 4 | 招商卡 |
| NULL | NULL | NULL | 5 | 平安卡 |
| 3 | 王五 | 6 | NULL | NULL |
| 4 | 马六 | 9 | NULL | NULL |
+------+------+--------+------+--------+
7 rows in set (0.00 sec)