PS:Mysql不区分大小写
一、如何使用终端操作数据库
1.如何登陆数据库服务器
mysql -uroot -p123456
2.如何查询数据库服务器中所有的数据库
show databases;
3.如何选中某一个数据库进行操作
use XXX;(某小数据库名称)
select * from XXX(该数据库里表的名称); //查询语句
select * from XXX where ID=1; //选中该表里的ID(字段)=1的记录
4.如何退出数据库服务器
exit;
5.如何在数据库服务器中创建我们的数据库
create database XXX;
6.如何查看某个数据库中的所有数据表
show tables; //显示该数据库里的表
7.如何创建一个数据表
CREATE TABLE pet(
name VARCHAR(20),
owner VARCHAR(20),
species VARCHAR(20),
sex CHAR(1),
birth DATE,
death DATE);
8.如何查看数据表的具体结构
describe XXX;
desc XXX; //简写版
(增删查改开始)
9.查看数据表中的记录
select * from XXX(表名);
10.如何向数据表中添加数据记录
INSERT INTO pet VALUES('Puff','Daniel','hamster','f','1999-03-23',NULL);
//最好是要给出明确的列的列表,如:
INSERT INTO pet(name,owner,species,sex,birth,death) VALUES('Puff','Daniel','hamster','f','1999-03-23',NULL);
//ps:可以在insert into中间添加low_priority来降低插入语句的优先级,以此来提高系统处理数据的性能
11.如何删除数据表中的数据记录
delete from pet where name='Puff';
12.如何修改数据库中的数据记录
update pet set name='Cuff' where owner='Daniel'; //相当于通过ID来修改
13.mysql 常用数据类型
大致分为三类:数值、日期/时间、字符串(字符)
具体可见链接
INT FLOAT DOUBLE DATE TIME CHAR VARCHAR TEXT
ps:日期的选择按照格式
数值和字符(串)的选择按照范围大小
14.MySQL建表约束:主键约束、自增约束、外键约束、唯一约束、非空约束、默认约束
主键约束:能够唯一确定一张表中的一条记录,也就是我们通过给某个字段添加约束,就可以使得该字段不重复且不为空
create table user(
ID int primary key,
name varchar(20)
); //primary key是关键字
insert into user values(1,'Jeff');
insert into user values(1,'Jeff'); //这时会报错,因为ID值已经被主键约束了,它不能重复
insert into user values(NULL,'Jeff'); //这时也会报错,因为ID值已经被主键约束了,它不能为空
联合主键:只要不全一样就行
如何在一张表创建多个主键约束
create table user2(
ID int,
name varchar(20),
password varchar(20),
primary key(ID,name) //一次性创建多个主键约束
);
insert into user2 values(1,'Joe',123);
insert into user2 values(2,'Joe',123); //可以
insert into user2 values(1,'Rem',123); //也可以
insert into user2 values(NULL,'Joe',123); //不行,主键约束的字段不能为空
自增约束(关键字auto_increment ,常与主键约束结合起来使用)
create table user3(
id int primary key auto_increment,
name varchar(20)
);
insert into user3 (name) values('Oliver'); //指定name字段插入值
insert into user3 (name) values('Biff');
select * from user3;
+----+--------+
| id | name |
+----+--------+
| 1 | Oliver |
| 2 | Biff |
+----+--------+
2 rows in set (0.00 sec) //结果id自己自动增加
在创建表时忘记创建主键约束了,如何补上(add)
alter table user4 add primary key(id);
如何删除删除全部字段的主键约束(drop)
alter table user4 drop primary key; //但是经过补删之后这个字段变得不能为空了,而最开始建表的时候是可以为空的
//疑问?如何删除某一个主键约束呢
如何在已创表上修改某一个字段添加主键约束(modify)
alter table user4 modify id int primary key;
唯一约束:约束修饰的字段的值不能重复(但可以为空)
三种方法添加约束:
alter table user5 add unique(name);
//或者
create table user6(
id int,
name varchar(20) unique
);
//或者
create table user6(
id int,
name varchar(20),
unique(id,name) //这种情况只要添加的字段值不全一样也可以,类似联合主键
desc user6;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | YES | MUL | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
);
//或者用modify添加
alter table user6 modify name varchar(20) unique;
如何删除唯一约束
alter table user6 drop index id;
非空约束:修饰的字段不能为NULL
create table user7(
id int,
name varchar(20) not null //(这里用大写小写空都可以)
);
默认约束:当我们插入字段值的时候,如果没有传值,就会使用默认值
create table user8(
id int,
name varchar(20),
age int default 10
);
外键约束:涉及到两个表:父表+子表或者主表+副表
create table classes(
id int primary key,
name varchar(20)
);
create table students(
id int primary key,
name varchar(20),
class_id int,
foreign key(class_id) references classes(id)
);
insert into classes values(1,'一班');
insert into classes values(2,'二班');
insert into classes values(3,'三班');
insert into classes values(4,'四班');
//还可以这样用一条insert语句一次性插入,比多条insert语句性能高,速度快
insert into classes(id,name) values(1,'一班'),(2,'二班'),(3,'三班'),(4,'四班');
insert into students values(1001,'张三',1);
insert into students values(1002,'李四',2);
insert into students values(1001,'王五',2);
insert into students values(1001,'赵六',5); //报错,因为classes中没有5这个id
//ps:主表中的记录被副表引用之后,是不可以被删除的,如下
delete from classes where id=2; //报错
15.三大范式
第一范式:1NF
数据表中的所有字段都是不可分割的原子值
如地址字段‘中国四川成都市武侯区武侯大道100号’可以分为‘中国’,‘四川’,‘成都市’,‘武侯区’,‘武侯大道100号’,故它不满足第一范式
PS:范式设计的越详细,对某些操作可能会起到很好的效果,但对某些操作也会产生不好的效果,具体还是要看实际需求。
第二范式:2NF(1NF+除主键外的每一列都必须完全依赖于主键)如果出现不完全依赖的现象,只可能发生在联合主键的情况下
create myorder(
product_id int,
product_name varchar(20),
customer_id int,
customer_name varchar(20),
primary key(product_id,customer_id)
); //显然product_name依赖于product_id,而与customer_id无关联,customer_name同理,故不满足第二范式,要想满足可以对其拆分,又称拆表,如下所示
create table myorder(
order_id int primary key,
product_id int,
customer_id int
);
create table product(
id int primary key,
name varchar(20)
);
create table customer(
id int primary key,
name varchar(20)
);
//分成三个表后,满足第二范式的设计
第三范式:3NF(2NF+除开主键列的其它列之间不能有传递依赖关系)
create table myorder(
order_id int primary key,
product_id int,
customer_id int,
customer_phone varchar(15) //既依赖于customer_id,又依赖于myorder_id,故不满足第三范式
);
16.MySQL查询练习
数据准备:
学生表(student):学号、姓名、性别、出生年月日、所在班级
课程表(course):课程号、课程名称、教师编号
教师表(teacher):编号、名字、性别、出生年月日、职称、所在部门
成绩表(score):学生学号、成绩、课程号
create table students(
s_id varchar(10) primary key,
s_name varchar(10) not null,
s_sex varchar(10) not null,
s_birhday datetime,
class varchar(20)
);
create table teachers(
t_id varchar(20) primary key,
t_name varchar(10) not null,
t_sex varchar(10) not null,
t_birthday datetime,
t_pro varchar(10) not null,
t_depart varchar(20) not null
);
create table courses(
c_id varchar(20) primary key,
c_name varchar(20) not null,
t_id varchar(10) not null,
foreign key(t_id) refenrences teachers(t_id)
);
create table scores(
s_id varchar(10) not null,
c_id varchar(20) not null,
points decimal,
foreign key(s_id) references students(s_id),
foreign key(c_id) references courses(c_id),
primary key(s_id,c_id) //注意!应该设为联合主键,否则一个学生一门课可以出现两个不同的成绩,违背了常理
);
//接下来往学生表里添加数据
insert into students values('101','xz','M','1991-10-02','1班');
insert into students values('103','web','M','1997-04-23','4班');
insert into students values('100','zly','F','1998-05-13','3班');
insert into students values('119','ym','F','2001-01-20','1班');
insert into students values('105','zdy','F','2000-06-21','2班');
insert into students values('123','zyl','M','1996-05-26','4班');
insert into students values('134','zzt','M','1998-10-26','2班');
insert into students values('108','cyq','F','1995-09-21','1班');
select * from students;
+------+--------+-------+---------------------+-------+
| s_id | s_name | s_sex | s_birhday | class |
+------+--------+-------+---------------------+-------+
| 100 | zly | F | 1998-05-13 00:00:00 | 3班 |
| 101 | xz | M | 1991-10-02 00:00:00 | 1班 |
| 103 | web | M | 1997-04-23 00:00:00 | 4班 |
| 105 | zdy | F | 2000-06-21 00:00:00 | 2班 |
| 108 | cyq | F | 1995-09-21 00:00:00 | 1班 |
| 119 | ym | F | 2001-01-20 00:00:00 | 1班 |
| 123 | zyl | M | 1996-05-26 00:00:00 | 4班 |
| 134 | zzt | M | 1998-10-26 00:00:00 | 2班 |
+------+--------+-------+---------------------+-------+
8 rows in set (0.00 sec)
//接下来往教师表里添加数据
insert into teachers values('803','张三','M','1958-10-09','副教授','计算机系');
insert into teachers values('810','李四','M','1964-11-09','副教授','电子工程系');
insert into teachers values('910','王可','F','1987-09-12','讲师','电子工程系');
insert into teachers values('924','沈川','M','1989-01-01','讲师','计算机系');
select * from teachers;
+------+--------+-------+---------------------+--------+------------+
| t_id | t_name | t_sex | t_birthday | t_pro | t_depart |
+------+--------+-------+---------------------+--------+------------+
| 803 | 张三 | M | 1958-10-09 00:00:00 | 副教授 | 计算机系 |
| 810 | 李四 | M | 1964-11-09 00:00:00 | 副教授 | 电子工程系 |
| 910 | 王可 | F | 1987-09-12 00:00:00 | 讲师 | 电子工程系 |
| 924 | 沈川 | M | 1989-01-01 00:00:00 | 讲师 | 计算机系 |
+------+--------+-------+---------------------+--------+------------+
4 rows in set (0.00 sec)
//接下来往课程表里添加数据
insert into courses values('001','计算机网络','924');
insert into courses values('002','数据库原理','803');
insert into courses values('004','面向对象程序设计','910');
insert into courses values('003','单片机技术','810');
select * from courses;
+------+------------------+------+
| c_id | c_name | t_id |
+------+------------------+------+
| 001 | 计算机网络 | 924 |
| 002 | 数据库原理 | 803 |
| 003 | 单片机技术 | 810 |
| 004 | 面向对象程序设计 | 910 |
+------+------------------+------+
4 rows in set (0.00 sec)
//接下来往成绩表里添加数据
insert into scores values('100','001','98');
insert into scores values('119','002','89');
insert into scores values('134','003','97');
insert into scores values('105','004','86');
insert into scores values('103','003','76');
insert into scores values('101','002','100');
insert into scores values('103','001','99');
insert into scores values('105','001','68');
insert into scores values('134','004','72');
insert into scores values('108','003','66');
select * from scores;
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 100 | 001 | 98 |
| 101 | 002 | 100 |
| 103 | 001 | 99 |
| 103 | 003 | 76 |
| 105 | 001 | 68 |
| 105 | 004 | 86 |
| 108 | 003 | 66 |
| 119 | 002 | 89 |
| 134 | 003 | 97 |
| 134 | 004 | 72 |
+------+------+--------+
10 rows in set (0.00 sec)
开始查询练习:
1.查询students表的所有记录
select * from students; //*代表的就是这个表里的所有字段
+------+--------+-------+---------------------+-------+
| s_id | s_name | s_sex | s_birhday | class |
+------+--------+-------+---------------------+-------+
| 100 | zly | F | 1998-05-13 00:00:00 | 3班 |
| 101 | xz | M | 1991-10-02 00:00:00 | 1班 |
| 103 | web | M | 1997-04-23 00:00:00 | 4班 |
| 105 | zdy | F | 2000-06-21 00:00:00 | 2班 |
| 108 | cyq | F | 1995-09-21 00:00:00 | 1班 |
| 119 | ym | F | 2001-01-20 00:00:00 | 1班 |
| 123 | zyl | M | 1996-05-26 00:00:00 | 4班 |
| 134 | zzt | M | 1998-10-26 00:00:00 | 2班 |
+------+--------+-------+---------------------+-------+
8 rows in set (0.00 sec)
2.查询students表中所有记录的s_name,s_sex,class列 //指定某些字段查询
select s_name,s_sex,class from students;
+--------+-------+-------+
| s_name | s_sex | class |
+--------+-------+-------+
| zly | F | 3班 |
| xz | M | 1班 |
| web | M | 4班 |
| zdy | F | 2班 |
| cyq | F | 1班 |
| ym | F | 1班 |
| zyl | M | 4班 |
| zzt | M | 2班 |
+--------+-------+-------+
8 rows in set (0.00 sec)
3.查询教师所有的单位即不重复的depart列
select distinct t_depart from teachers; //distinct关键字 排除重复
+------------+
| t_depart |
+------------+
| 计算机系 |
| 电子工程系 |
+------------+
2 rows in set (0.00 sec)
4.查询scores表中成绩在60-80之间的记录(查询区间 between…and…)
select * from scores where points between 60 and 80;
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 103 | 003 | 76 |
| 105 | 001 | 68 |
| 108 | 003 | 66 |
| 134 | 004 | 72 |
+------+------+--------+
4 rows in set (0.00 sec)
//法二:直接使用运算符来比较
select * from scores where points > 60 and points < 80;
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 103 | 003 | 76 |
| 105 | 001 | 68 |
| 108 | 003 | 66 |
| 134 | 004 | 72 |
+------+------+--------+
4 rows in set (0.00 sec)
5.查询scores表中成绩为89,99或100的记录
法一:(in)
select * from scores where points in(89,99,100);
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 101 | 002 | 100 |
| 103 | 001 | 99 |
| 119 | 002 | 89 |
+------+------+--------+
3 rows in set (0.00 sec)
法二:(or关键字)
select * from scores where points = 89 or points = 99 or points = 100;
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 101 | 002 | 100 |
| 103 | 001 | 99 |
| 119 | 002 | 89 |
+------+------+--------+
3 rows in set (0.00 sec)
6.查询students中‘1班’或性别为女的同学的记录(or关键字)
select * from students where class='1班' or s_sex='F';
+------+--------+-------+---------------------+-------+
| s_id | s_name | s_sex | s_birhday | class |
+------+--------+-------+---------------------+-------+
| 100 | zly | F | 1998-05-13 00:00:00 | 3班 |
| 101 | xz | M | 1991-10-02 00:00:00 | 1班 |
| 105 | zdy | F | 2000-06-21 00:00:00 | 2班 |
| 108 | cyq | F | 1995-09-21 00:00:00 | 1班 |
| 119 | ym | F | 2001-01-20 00:00:00 | 1班 |
+------+--------+-------+---------------------+-------+
5 rows in set (0.00 sec)
7.以class降序查询student表中的所有记录(升序asc关键字,降序desc关键字) 来自于ascend上升,descend下降
select * from students order by class desc;
+------+--------+-------+---------------------+-------+
| s_id | s_name | s_sex | s_birhday | class |
+------+--------+-------+---------------------+-------+
| 103 | web | M | 1997-04-23 00:00:00 | 4班 |
| 123 | zyl | M | 1996-05-26 00:00:00 | 4班 |
| 100 | zly | F | 1998-05-13 00:00:00 | 3班 |
| 105 | zdy | F | 2000-06-21 00:00:00 | 2班 |
| 134 | zzt | M | 1998-10-26 00:00:00 | 2班 |
| 101 | xz | M | 1991-10-02 00:00:00 | 1班 |
| 108 | cyq | F | 1995-09-21 00:00:00 | 1班 |
| 119 | ym | F | 2001-01-20 00:00:00 | 1班 |
+------+--------+-------+---------------------+-------+
8 rows in set (0.00 sec)
ps:一般不写的话默认是升序
8.先以c_id升序、再以points降序查询scores表中的所有记录
select * from scores order by c_id asc,points desc; //谁写在前面就先以谁为标准
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 103 | 001 | 99 |
| 100 | 001 | 98 |
| 105 | 001 | 68 |
| 101 | 002 | 100 |
| 119 | 002 | 89 |
| 134 | 003 | 97 |
| 103 | 003 | 76 |
| 108 | 003 | 66 |
| 105 | 004 | 86 |
| 134 | 004 | 72 |
+------+------+--------+
10 rows in set (0.00 sec)
9.查询‘1班’的人数(count关键字)
select count(*) from students where class='1班';
+----------+
| count(*) |
+----------+
| 3 |
+----------+
1 row in set (0.00 sec)
10.查询score表中的最高分的学生的学号和课程号
select s_id,c_id from scores order by points desc limit 0,1; //limit第一个数字表示从多少开始(注意我们看到的第一个实际上是第0个),第二个数字表示查多少条记录
+------+------+
| s_id | c_id |
+------+------+
| 101 | 002 |
+------+------+
1 row in set (0.00 sec)
或者
select s_id,c_id from scores where points=(select max(points) from scores); //子查询,复合语句,嵌套语句
+------+------+
| s_id | c_id |
+------+------+
| 101 | 002 |
+------+------+
1 row in set (0.00 sec)
11.查询每门课的平均成绩(avg方法)
select * from courses;
+------+------------------+------+
| c_id | c_name | t_id |
+------+------------------+------+
| 001 | 计算机网络 | 924 |
| 002 | 数据库原理 | 803 |
| 003 | 单片机技术 | 810 |
| 004 | 面向对象程序设计 | 910 |
+------+------------------+------+
4 rows in set (0.00 sec)
select avg(points) from scores where c_id='001';
+-------------+
| avg(points) |
+-------------+
| 88.3333 |
+-------------+
1 row in set (0.00 sec)
如何一次性打印出来(用group by 分组)
select c_id,avg(points) from scores group by c_id;
12.查询scores表中至少有两名学生选修的并以0开头的课程的平均分数
(关键字having 分组条件,常见于group by之后)(关键字like 模糊查询)
having和where相似,区别是where筛选分组之前的,having筛选分组之后的
select c_id,avg(points) from scores group by c_id having count(c_id>=2) and c_id like '0%';
+------+-------------+
| c_id | avg(points) |
+------+-------------+
| 001 | 88.3333 |
| 002 | 94.5000 |
| 003 | 79.6667 |
| 004 | 79.0000 |
+------+-------------+
4 rows in set (0.02 sec)
13.查询分数大于70,小于90的s_id列
select s_id,points from scores where points>70 and points<90;
+------+--------+
| s_id | points |
+------+--------+
| 103 | 76 |
| 105 | 86 |
| 119 | 89 |
| 134 | 72 |
+------+--------+
4 rows in set (0.00 sec)
14.查询所有学生的s_name,c_id,points列(多表查询)
步骤:先一个一个表查,再找出每个表中的共同字段,利用这个字段建立起关系
select s_name,c_id,points from students,scores where students.s_id=scores.s_id; //利用一个桥梁将两张表合成一张
+--------+------+--------+
| s_name | c_id | points |
+--------+------+--------+
| zly | 001 | 98 |
| xz | 002 | 100 |
| web | 001 | 99 |
| web | 003 | 76 |
| zdy | 001 | 68 |
| zdy | 004 | 86 |
| cyq | 003 | 66 |
| ym | 002 | 89 |
| zzt | 003 | 97 |
| zzt | 004 | 72 |
+--------+------+--------+
10 rows in set (0.01 sec)
再如查询所有学生的s_id,c_name,points列
select s_id,c_name,points from courses,scores where courses.c_id=scores.c_id;
+------+------------------+--------+
| s_id | c_name | points |
+------+------------------+--------+
| 100 | 计算机网络 | 98 |
| 103 | 计算机网络 | 99 |
| 105 | 计算机网络 | 68 |
| 101 | 数据库原理 | 100 |
| 119 | 数据库原理 | 89 |
| 103 | 单片机技术 | 76 |
| 108 | 单片机技术 | 66 |
| 134 | 单片机技术 | 97 |
| 105 | 面向对象程序设计 | 86 |
| 134 | 面向对象程序设计 | 72 |
+------+------------------+--------+
10 rows in set (0.00 sec)
再如查询所有学生的s_name,c_name,points列(三表关联查询)
select s_name,c_name,points from students,courses,scores where students.s_id=scores.s_id and courses.c_id=scores.c_id; //通过各表中相同的字段来进行连接
+--------+------------------+--------+
| s_name | c_name | points |
+--------+------------------+--------+
| zly | 计算机网络 | 98 |
| web | 计算机网络 | 99 |
| zdy | 计算机网络 | 68 |
| xz | 数据库原理 | 100 |
| ym | 数据库原理 | 89 |
| web | 单片机技术 | 76 |
| cyq | 单片机技术 | 66 |
| zzt | 单片机技术 | 97 |
| zdy | 面向对象程序设计 | 86 |
| zzt | 面向对象程序设计 | 72 |
+--------+------------------+--------+
10 rows in set (0.00 sec)
select s_name,c_name,points,students.s_id as snu, //临时给字段取别名
courses.c_id as cnu from //注意要指明是谁的s_id,是谁的c_id
students,courses,scores
where students.s_id=scores.s_id
and courses.c_id=scores.c_id;
+--------+------------------+--------+-----+-----+
| s_name | c_name | points | snu | cnu |
+--------+------------------+--------+-----+-----+
| zly | 计算机网络 | 98 | 100 | 001 |
| xz | 数据库原理 | 100 | 101 | 002 |
| web | 计算机网络 | 99 | 103 | 001 |
| web | 单片机技术 | 76 | 103 | 003 |
| zdy | 计算机网络 | 68 | 105 | 001 |
| zdy | 面向对象程序设计 | 86 | 105 | 004 |
| cyq | 单片机技术 | 66 | 108 | 003 |
| ym | 数据库原理 | 89 | 119 | 002 |
| zzt | 单片机技术 | 97 | 134 | 003 |
| zzt | 面向对象程序设计 | 72 | 134 | 004 |
+--------+----------------
15.查询“1班”学生每门课的平均分(子查询加分组求平均分)
//分3步走,像是写英语长句?哈哈哈
select * from students where class='1班';
+------+--------+-------+---------------------+-------+
| s_id | s_name | s_sex | s_birhday | class |
+------+--------+-------+---------------------+-------+
| 101 | xz | M | 1991-10-02 00:00:00 | 1班 |
| 108 | cyq | F | 1995-09-21 00:00:00 | 1班 |
| 119 | ym | F | 2001-01-20 00:00:00 | 1班 |
+------+--------+-------+---------------------+-------+
3 rows in set (0.00 sec)
select * from scores where s_id in(select s_id from students where class='1班');
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 101 | 002 | 100 |
| 108 | 003 | 66 |
| 119 | 002 | 89 |
+------+------+--------+
3 rows in set (0.01 sec)
select c_id,avg(points) from scores where s_id in(select s_id from students where class='1班') group by c_id;
+------+-------------+
| c_id | avg(points) |
+------+-------------+
| 002 | 94.5000 |
| 003 | 66.0000 |
+------+-------------+
2 rows in set (0.00 sec)
16.查询选修“003”课程的成绩高于‘108’号同学“003”成绩的所有同学的记录
select * from scores where points>(select points from scores where s_id=108 and c_id=003) and c_id=003;
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 103 | 003 | 76 |
| 134 | 003 | 97 |
+------+------+--------+
2 rows in set (0.00 sec)
查询成绩高于学号为‘108’,课程号为‘003’的成绩的所有记录
select * from scores where points>(select points from scores where s_id=108 and c_id=003);
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 100 | 001 | 98 |
| 101 | 002 | 100 |
| 103 | 001 | 99 |
| 103 | 003 | 76 |
| 105 | 001 | 68 |
| 105 | 004 | 86 |
| 119 | 002 | 89 |
| 134 | 003 | 97 |
| 134 | 004 | 72 |
+------+------+--------+
9 rows in set (0.00 sec)
17.查询和学号为108,100的同学同年出生的所有学生的s_id,s_name,s_birthday列 (year函数截取年份)
select year(s_birthday) from students where s_id in(100,108);
+-----------------+
| year(s_birhday) |
+-----------------+
| 1998 |
| 1995 |
+-----------------+
2 rows in set (0.00 sec)
select * from students where year(s_birhday)
in(select year(s_birhday) from students where s_id in(100,108));
+------+--------+-------+---------------------+-------+
| s_id | s_name | s_sex | s_birhday | class |
+------+--------+-------+---------------------+-------+
| 100 | zly | F | 1998-05-13 00:00:00 | 3班 |
| 108 | cyq | F | 1995-09-21 00:00:00 | 1班 |
| 134 | zzt | M | 1998-10-26 00:00:00 | 2班 |
+------+--------+-------+---------------------+-------+
3 rows in set (0.00 sec)
18.查询沈川教师任课的学生成绩(多层嵌套子查询)
select * from scores where c_id=(select c_id from courses where t_id=(select t_id from teachers where t_name='沈 川'));
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 100 | 001 | 98 |
| 103 | 001 | 99 |
| 105 | 001 | 68 |
+------+------+--------+
3 rows in set (0.00 sec)
查询出计算机系教师所教课程的成绩表
select * from scores where c_id in(select c_id from courses where t_id in(select t_id from teachers where t_depart='计算机系'));
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 101 | 002 | 100 |
| 119 | 002 | 89 |
| 100 | 001 | 98 |
| 103 | 001 | 99 |
| 105 | 001 | 68 |
+------+------+--------+
5 rows in set (0.00 sec)
19.查询选修某课程的同学人数多于2人的教师姓名(分组后条件查询+嵌套查询)
select c_id from scores group by c_id having count(*)>2;
+------+
| c_id |
+------+
| 001 |
| 003 |
+------+
2 rows in set (0.00 sec)
select t_name from teachers
where t_id in(select t_id from courses where c_id
in(select c_id from scores group by c_id having count(*)>2));
+--------+
| t_name |
+--------+
| 李四 |
| 沈川 |
+--------+
2 rows in set (0.00 sec)
20.查询教师表中不同职称的教师的t_name和t_pro
21.查询选修编号为‘001’课程且成绩至少高于选修编号为‘002’课程的成绩的同学的c_id,s_id,points,并按points从高到低排序 (any关键字)
select * from scores where c_id=001
and points>any(select points from scores where c_id=002)
order by points desc;
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 103 | 001 | 99 |
| 100 | 001 | 98 |
+------+------+--------+
2 rows in set (0.00 sec)
查询选修编号为‘002’且成绩高于选修编号为‘001’课程的同学的c_id,s_id,points列(all关键字)
select * from scores where c_id=002
and points>all(select points from scores where c_id=001);
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 101 | 002 | 100 |
+------+------+--------+
1 row in set (0.00 sec)
22.查询所有教师和同学的name,sex,birthday(as改别名,union求并集)
ps:这里as可用空格替代,也就是说select s_name name,s_sex sex,s_birthday birthday from students union select t_name,t_sex,t_birthday from teachers;也是可以的
select s_name as name,s_sex as sex,s_birthday as birthday from students
union
select t_name,t_sex,t_birthday from teachers;
+------+-----+---------------------+
| name | sex | birthday |
+------+-----+---------------------+
| zly | F | 1998-05-13 00:00:00 |
| xz | M | 1991-10-02 00:00:00 |
| web | M | 1997-04-23 00:00:00 |
| zdy | F | 2000-06-21 00:00:00 |
| cyq | F | 1995-09-21 00:00:00 |
| ym | F | 2001-01-20 00:00:00 |
| zyl | M | 1996-05-26 00:00:00 |
| zzt | M | 1998-10-26 00:00:00 |
| 张三 | M | 1958-10-09 00:00:00 |
| 李四 | M | 1964-11-09 00:00:00 |
| 王可 | F | 1987-09-12 00:00:00 |
| 沈川 | M | 1989-01-01 00:00:00 |
+------+-----+---------------------+
12 rows in set (0.00 sec)
//ps:若有重复记录,用union关键字会默认去除重复的多条记录,只保留一条,若用union all关键字就不会去除重复的记录,而是有多少显现多少
23.如何改变表中的某一字段名
alter table students change s_birhday s_birthday datetime;
24.查询成绩比该课程平均成绩低的同学的成绩表
select c_id,avg(points) from scores group by c_id;
+------+-------------+
| c_id | avg(points) |
+------+-------------+
| 001 | 88.3333 |
| 002 | 94.5000 |
| 003 | 79.6667 |
| 004 | 79.0000 |
+------+-------------+
4 rows in set (0.00 sec)
select * from scores a where points<(select avg(points) from scores b where a.c_id=b.c_id);
+------+------+--------+
| s_id | c_id | points |
+------+------+--------+
| 103 | 003 | 76 |
| 105 | 001 | 68 |
| 108 | 003 | 66 |
| 119 | 002 | 89 |
| 134 | 004 | 72 |
+------+------+--------+
5 rows in set (0.00 sec)
25.查询至少有2名男生的班号
select class from students where s_sex='M' group by class having count(*)>1;
+-------+
| class |
+-------+
| 4班 |
+-------+
1 row in set (0.00 sec)
26.查询students表中不姓z的同学记录(not like关键字 模糊查询取反)
select * from students where s_name not like 'z%';
+------+--------+-------+---------------------+-------+
| s_id | s_name | s_sex | s_birthday | class |
+------+--------+-------+---------------------+-------+
| 101 | xz | M | 1991-10-02 00:00:00 | 1班 |
| 103 | web | M | 1997-04-23 00:00:00 | 4班 |
| 108 | cyq | F | 1995-09-21 00:00:00 | 1班 |
| 119 | ym | F | 2001-01-20 00:00:00 | 1班 |
+------+--------+-------+---------------------+-------+
4 rows in set (0.00 sec)
27.查询students表中每个学生的姓名和年龄
select year(now()); //当前年份
+-------------+
| year(now()) |
+-------------+
| 2020 |
+-------------+
1 row in set (0.00 sec)
select s_name,year(now())-year(s_birthday) as '年龄' from students;
+--------+------+
| s_name | 年龄 |
+--------+------+
| zly | 22 |
| xz | 29 |
| web | 23 |
| zdy | 20 |
| cyq | 25 |
| ym | 19 |
| zyl | 24 |
| zzt | 22 |
+--------+------+
8 rows in set (0.00 sec)
28.查询students表中最大和最小的s_birthday日期值
select max(s_birthday) as '最大日期',min(s_birthday) as '最小日期' from students;
+---------------------+---------------------+
| 最大日期 | 最小日期 |
+---------------------+---------------------+
| 2001-01-20 00:00:00 | 1991-10-02 00:00:00 |
+---------------------+---------------------+
1 row in set (0.00 sec)
29.以班号和年龄从大到小查询students表中的全部记录
select * from students order by class desc,s_birthday;
+------+--------+-------+---------------------+-------+
| s_id | s_name | s_sex | s_birthday | class |
+------+--------+-------+---------------------+-------+
| 123 | zyl | M | 1996-05-26 00:00:00 | 4班 |
| 103 | web | M | 1997-04-23 00:00:00 | 4班 |
| 100 | zly | F | 1998-05-13 00:00:00 | 3班 |
| 134 | zzt | M | 1998-10-26 00:00:00 | 2班 |
| 105 | zdy | F | 2000-06-21 00:00:00 | 2班 |
| 101 | xz | M | 1991-10-02 00:00:00 | 1班 |
| 108 | cyq | F | 1995-09-21 00:00:00 | 1班 |
| 119 | ym | F | 2001-01-20 00:00:00 | 1班 |
+------+--------+-------+---------------------+-------+
8 rows in set (0.00 sec)
30.按等级查询
假设使用以下命令建立了一个grade表,现查询所有同学的s_id,c_id,grade列
create table grade(low int(3),up int(3),grade char(1));
insert into grade values(90,100,'A');
insert into grade values(80,89,'B');
insert into grade values(70,79,'C');
insert into grade values(60,69,'D');
insert into grade values(0,59,'E');
select s_id,c_id,grade from scores,grade where points between low and up;
+------+------+-------+
| s_id | c_id | grade |
+------+------+-------+
| 100 | 001 | A |
| 101 | 002 | A |
| 103 | 001 | A |
| 103 | 003 | C |
| 105 | 001 | D |
| 105 | 004 | B |
| 108 | 003 | D |
| 119 | 002 | B |
| 134 | 003 | A |
| 134 | 004 | C |
+------+------+-------+
10 rows in set (0.01 sec)
31.SQL的四种连接查询
内连接inner join 或者join
外连接:
左连接left join或者left outer join
右连接right join或者right outer join
完全外连接full join 或者full outer join
现创建两个表:person表:id,name,cardID
card表:id,name
create table card(id int,name varchar(20));
create table person(id int,name varchar(20),cardID int);
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,'工商卡');
select * from card;
+------+--------+
| id | name |
+------+--------+
| 1 | 饭卡 |
| 2 | 邮政卡 |
| 3 | 建行卡 |
| 4 | 农行卡 |
| 5 | 工商卡 |
+------+--------+
insert into person values(1,'沈泽',1);
insert into person values(2,'费悬',1);
insert into person values(3,'骆洲',2);
insert into person values(4,'魏通',5);
insert into person values(5,'蓝章',6);
select * from person;
+------+------+--------+
| id | name | cardID |
+------+------+--------+
| 1 | 沈泽 | 1 |
| 2 | 费悬 | 1 |
| 3 | 骆洲 | 2 |
| 4 | 魏通 | 5 |
| 5 | 蓝章 | 6 |
+------+------+--------+
可以看到因为没有创建外键约束,因而即使卡号是6也可以插入到person表中
inner join 查询(内联查询,其实就是两张表中的数据通过某个字段相等,查询出相关记录数据)
select * from person inner join card on person.cardID=card.id;
+------+------+--------+------+--------+
| id | name | cardID | id | name |
+------+------+--------+------+--------+
| 1 | 沈泽 | 1 | 1 | 饭卡 |
| 2 | 费悬 | 1 | 1 | 饭卡 |
| 3 | 骆洲 | 2 | 2 | 邮政卡 |
| 4 | 魏通 | 5 | 5 | 工商卡 |
+------+------+--------+------+--------+
4 rows in set (0.00 sec)
//找到了cardID=card.id的记录,把6号id扔了
left join(左外连接,会把左边表里面的所有数据取出来,而右边表中的数据如果有相等的就显示出来,如果没有就会补上NULL)
select * from person left join card on person.cardID=card.id;
+------+------+--------+------+--------+
| id | name | cardID | id | name |
+------+------+--------+------+--------+
| 1 | 沈泽 | 1 | 1 | 饭卡 |
| 2 | 费悬 | 1 | 1 | 饭卡 |
| 3 | 骆洲 | 2 | 2 | 邮政卡 |
| 4 | 魏通 | 5 | 5 | 工商卡 |
| 5 | 蓝章 | 6 | NULL | NULL |
+------+------+--------+------+--------+
5 rows in set (0.00 sec)
right join(右外连接,会把右边表里面的所有数据取出来,而左边表中的数据如果有相等的就显示出来,如果没有就会补上NULL)
select * from person right join card on person.cardID=card.id;
+------+------+--------+------+--------+
| id | name | cardID | id | name |
+------+------+--------+------+--------+
| 1 | 沈泽 | 1 | 1 | 饭卡 |
| 2 | 费悬 | 1 | 1 | 饭卡 |
| 3 | 骆洲 | 2 | 2 | 邮政卡 |
| NULL | NULL | NULL | 3 | 建行卡 |
| NULL | NULL | NULL | 4 | 农行卡 |
| 4 | 魏通 | 5 | 5 | 工商卡 |
+------+------+--------+------+--------+
6 rows in set (0.00 sec)
full join(全外连接)
select * from person full join card on person.cardID=card.id;
ERROR 1054 (42S22): Unknown column 'person.cardID' in 'on clause' //报错,因为mysql有时不支持full join,但其实效果等同于以下语句
select * from person left join card on person.cardID=card.id
union
select * from person right join card on person.cardID=card.id;
+------+------+--------+------+--------+
| id | name | cardID | id | name |
+------+------+--------+------+--------+
| 1 | 沈泽 | 1 | 1 | 饭卡 |
| 2 | 费悬 | 1 | 1 | 饭卡 |
| 3 | 骆洲 | 2 | 2 | 邮政卡 |
| 4 | 魏通 | 5 | 5 | 工商卡 |
| 5 | 蓝章 | 6 | NULL | NULL |
| NULL | NULL | NULL | 3 | 建行卡 |
| NULL | NULL | NULL | 4 | 农行卡 |
+------+------+--------+------+--------+
7 rows in set (0.00 sec)
ps:我们还可以对表取别名,这样可以缩短sql语句,或者允许在单条select语句中多次使用相同的表
select * from scores as sc,students as st where sc.s_id=st.s_id;
+------+------+--------+------+--------+-------+---------------------+-------+
| s_id | c_id | points | s_id | s_name | s_sex | s_birthday | class |
+------+------+--------+------+--------+-------+---------------------+-------+
| 100 | 001 | 98 | 100 | zly | F | 1998-05-13 00:00:00 | 3班 |
| 101 | 002 | 100 | 101 | xz | M | 1991-10-02 00:00:00 | 1班 |
| 103 | 001 | 99 | 103 | web | M | 1997-04-23 00:00:00 | 4班 |
| 103 | 003 | 76 | 103 | web | M | 1997-04-23 00:00:00 | 4班 |
| 105 | 001 | 68 | 105 | zdy | F | 2000-06-21 00:00:00 | 2班 |
| 105 | 004 | 86 | 105 | zdy | F | 2000-06-21 00:00:00 | 2班 |
| 108 | 003 | 66 | 108 | cyq | F | 1995-09-21 00:00:00 | 1班 |
| 119 | 002 | 89 | 119 | ym | F | 2001-01-20 00:00:00 | 1班 |
| 134 | 003 | 97 | 134 | zzt | M | 1998-10-26 00:00:00 | 2班 |
| 134 | 004 | 72 | 134 | zzt | M | 1998-10-26 00:00:00 | 2班 |
+------+------+--------+------+--------+-------+---------------------+-------+
//避免s_id字段重复可这样自然联结表:
select st.*,sc.c_id,sc.points from scores as sc,students as st where sc.s_id=st.s_id;
+------+--------+-------+---------------------+-------+------+--------+
| s_id | s_name | s_sex | s_birthday | class | c_id | points |
+------+--------+-------+---------------------+-------+------+--------+
| 100 | zly | F | 1998-05-13 00:00:00 | 3班 | 001 | 98 |
| 101 | xz | M | 1991-10-02 00:00:00 | 1班 | 002 | 100 |
| 103 | web | M | 1997-04-23 00:00:00 | 4班 | 001 | 99 |
| 103 | web | M | 1997-04-23 00:00:00 | 4班 | 003 | 76 |
| 105 | zdy | F | 2000-06-21 00:00:00 | 2班 | 001 | 68 |
| 105 | zdy | F | 2000-06-21 00:00:00 | 2班 | 004 | 86 |
| 108 | cyq | F | 1995-09-21 00:00:00 | 1班 | 003 | 66 |
| 119 | ym | F | 2001-01-20 00:00:00 | 1班 | 002 | 89 |
| 134 | zzt | M | 1998-10-26 00:00:00 | 2班 | 003 | 97 |
| 134 | zzt | M | 1998-10-26 00:00:00 | 2班 | 004 | 72 |
+------+--------+-------+---------------------+-------+------+--------+
32.MySQL中,事务其实是一个最小的不可分割的工作单元。事务能够保证一个业务的完整性。
举例:比如银行转账
a->-100
update user set money=money-100 where name=‘a’;
b->+100
update user set money=money+100 where name=‘b’;
实际的程序中,如果只有一条语句执行成功,那就会出现数据前后不一致的情况,这就破坏了业务的完整性
MySQL中如何控制事务?
MySQL默认是开启事务的(自动提交)
select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)
默认事务开启的作用是:当我们去执行一个sql语句的时候,效果会立即体现出来,且不能回滚(rollback:即撤销sql语句执行效果)。
如何回滚?设置mysql自动提交为false
set autocommit=0;
如果此时又想提交该语句?(手动提交)
commit;
此时再看银行转账:
create table user(id int primary key,name varchar(20),money int);
insert user values(1,'a',1000);
insert user values(2,'b',1000);
select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | a | 1000 |
| 2 | b | 1000 |
+----+------+-------+
update user set money=money-100 where id=1;
update user set money=money+100 where id=2;
select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | a | 900 |
| 2 | b | 1100 |
+----+------+-------+
2 rows in set (0.00 sec)
rollback; //并没有回滚,因为此时autocommit还是默认为1
select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | a | 900 |
| 2 | b | 1100 |
+----+------+-------+
2 rows in set (0.00 sec)
set autocommit=0;
update user set money=money-100 where id=1;
update user set money=money+100 where id=2;
select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | a | 800 |
| 2 | b | 1200 |
+----+------+-------+
2 rows in set (0.00 sec)
rollback; //回滚奏效了,事务给我们提供了一个返回的机会
select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | a | 900 |
| 2 | b | 1100 |
+----+------+-------+
2 rows in set (0.00 sec)
commit; //此时再提交rollback对该语句就不会奏效了
begin;或者start transaction;都可以帮我们手动开启一个事务(但一旦commit;之后就结束事务了,也就不能回滚了)
begin;
update user set money=money-100 where id=1;
update user set money=money+100 where id=2;
select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | a | 900 |
| 2 | b | 1100 |
+----+------+-------+
2 rows in set (0.00 sec)
rollback; //回滚奏效了
select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | a | 1000 |
| 2 | b | 1000 |
+----+------+-------+
2 rows in set (0.01 sec)
33.事务的四大特征(ACID)
A:原子性:事务是最小的单位,不可以再分割
C:一致性:同一事务中的sql语句,必须保证同时成功或者同时失败(类似银行转账那样)。
I:隔离性:事务1和事务2之间是具有隔离性的
D:持久性:事务一旦结束,就不可返回
34.事务的隔离性:
read uncommitted; 读未提交的
如果有事务a,b,其中a事务对数据进行操作,在操作的过程中事务没有被提交,但是b可以看见a操作的结果,就可能会出现脏读
如何查看数据库的隔离级别?
select @@transaction_isolation;//会话级别的
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ | //此为mysql默认的隔离级别
+-------------------------+
1 row in set (0.00 sec)
select @@global.transaction_isolation; //系统级别的
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| REPEATABLE-READ |
+--------------------------------+
1 row in set (0.00 sec)
如何修改隔离级别?
set global transaction isolation level read uncommitted;
select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| READ-UNCOMMITTED |
+--------------------------------+
1 row in set (0.00 sec)
脏读:一个事务读到了另外一个事务没有提交的数据。实际开发中是不允许的
read committed; 读已经提交的
读取同一个表的数据发现前后不一致 出现不可重复度现象(不能同时被两个人或多人共同读取)
repeatable read; 可以重复读
幻读:事务a和事务b同时操作一张表,事务a提交的数据不能被事务b读到,就可能造成幻读
serializable; 串行化
当user表被一个事务操作的时候,其它事务里面的写操作是不可以进行的,会被卡住进入排队状态(串行化),直到那个事务结束(commit;)之后,这边的写入操作才可以继续
串行化问题:性能特别差
性能比较:read uncommitted>read committed>repeatable read>serializable
也就是说隔离级别越高,性能越差
二、
如何使用可视化工具操作数据库