一、基本语法
创建数据库
(test为我们创建数据库的名称)
create database test;
查看数据库
show databases;
选择数据库
use test;
创建表
create table if not exists mytable (
id int unsigned primary key auto_increment,
title varchar(100) not null,
author varchar(40) not null,
submission_date date
) default charset=utf8;
列出所有表
show tables;
查看某一个表的结构
desc/describe mytable;
mysql> desc mytable;
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(100) | NO | | NULL | |
| author | varchar(40) | NO | | NULL | |
| submission_date | date | YES | | NULL | |
+-----------------+------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
删除表(数据)
drop table mytable; # 直接删除表数据以及表
truncate table mytable; # truncate(截断),只删除表数据,不删除表
delete from mytable [where ...]; # 按照条件对表中的数据进行删除
插入数据(增)
insert mytable(title, author, submission_date) values("MySQL学习", "jing.wang", NOW())
...
mysql> select * from mytable;
+----+------------+-----------+-----------------+
| id | title | author | submission_date |
+----+------------+-----------+-----------------+
| 1 | MySQL学习 | jing.wang | 2019-07-26 |
| 2 | 计算机网络 | pei.yang | 2019-07-26 |
| 3 | 数据结构 | jing.wang | 2019-07-26 |
+----+------------+-----------+-----------------+
删除数据(删)
delete from mytable where author='author_name';
修改数据(改)
update mytable set title='test_titile' where title='MySQL学习';
LIKE子句
mysql> select * from mytable where author like '%wang';
+----+-----------+-----------+-----------------+
| id | title | author | submission_date |
+----+-----------+-----------+-----------------+
| 1 | MySQL学习 | jing.wang | 2019-07-26 |
| 3 | 数据结构 | jing.wang | 2019-07-26 |
+----+-----------+-----------+-----------------+
2 rows in set (0.00 sec)
'%a' //以a结尾的数据
'a%' //以a开头的数据
'%a%' //含有a的数据
'_a_' //三位且中间字母是a的
'_a' //两位且结尾字母是a的
'a_' //两位且开头字母是a的
排序
mysql> select * from mytable order by author;
+----+------------+-----------+-----------------+
| id | title | author | submission_date |
+----+------------+-----------+-----------------+
| 1 | MySQL学习 | jing.wang | 2019-07-26 |
| 3 | 数据结构 | jing.wang | 2019-07-26 |
| 2 | 计算机网络 | pei.yang | 2019-07-26 |
+----+------------+-----------+-----------------+
分组
mysql> select author,count(*) from mytable group by author;
+-----------+----------+
| author | count(*) |
+-----------+----------+
| jing.wang | 2 |
| pei.yang | 1 |
+-----------+----------+
2 rows in set (0.00 sec)
某员工表staff如下所示:
id name dept salary edlevel hiredate
1 张三 开发部 2000 3 2009-10-11
2 李四 开发部 2500 3 2009-10-01
3 王五 设计部 2600 5 2010-10-02
4 王六 设计部 2300 4 2010-10-03
5 马七 设计部 2100 4 2010-10-06
6 赵八 销售部 3000 5 2010-10-05
7 钱九 销售部 3100 7 2010-10-07
8 孙十 销售部 3500 7 2010-10-06
列出每个部门最高薪水的结果,sql语句如下:
select dept, max(salary) as MAXIUM from staff group by dept;
查询结果如下:
dept MAXIMUM
开发部 4500
设计部 2600
销售部 3500
将where子句与group by子句一起使用
分组查询可以在形成组和计算列函数之前具有消除非限定行的标准where子句。必须在group by子句之前指定where子句
查询公司2010年入职的各个部门每个级别里的最高薪水
select dept, edlevel, max(salary)
from staff
where hiredate > ' 2010-01-01 '
group by dept, edlevel;
查询结果如下:
dept edlevel MAXIMUM
设计部 4 2300
设计部 5 2600
销售部 5 3000
销售部 7 3500
GROUP BY子句之后使用Having子句
可应用限定条件进行分组,以便系统仅对满足条件的组返回结果。因此,在GROUP BY子句后面包含了一个HAVING子句。HAVING类似于WHERE(唯一的差别是WHERE过滤行,HAVING过滤组)AVING支持所有WHERE操作符。
例如,查找雇员数超过2个的部门的最高和最低薪水:
select dept, max(salary), min(salary)
from staff
group by dept
having count(*) > 2
order by dept;
查询结果如下:
dept MAXIMUM MINIMUM
设计部 2600 2100
销售部 3500 3000
查找雇员平均工资大于3000的部门的最高薪水和最低薪水:
select dept, max(salary), min(salary)
from staff
group by dept
having avg(salary) > 3000
order by dept;
查询结果如下:
dept MAXIMUM MINIMUM
销售部 3500 3000
在使用group by的过程中必须注意的一点
在select指定的字段要么就要包含在Group By语句的后面,作为分组的依据;要么就要被包含在聚合函数中。
select dept, name, max(salary) as MAXIUM from staff group by dept; (错误的)
其中name不属于group by分组的条件,也不属于聚合函数max等的参数,因此select不能使用name这个属性
Having与Where的区别
where 子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,where条件中不能包含聚组函数,使用where条件过滤出特定的行。
having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚组函数,使用having 条件过滤出特定的组,也可以使用多个分组标准进行分组。
join用法
JOIN 按照功能大致分为如下三类:
INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录。[默认的join]
LEFT JOIN(左连接):获取左表所有记录,即使右表没有对应匹配的记录。
RIGHT JOIN(右连接): 与 LEFT JOIN 相反,用于获取右表所有记录,即使左表没有对应匹配的记录。
当前有两张表:
mysql> use RUNOOB;
Database changed
mysql> SELECT * FROM tcount_tbl;
+---------------+--------------+
| runoob_author | runoob_count |
+---------------+--------------+
| 菜鸟教程 | 10 |
| RUNOOB.COM | 20 |
| Google | 22 |
+---------------+--------------+
3 rows in set (0.01 sec)
mysql> SELECT * from runoob_tbl;
+-----------+---------------+---------------+-----------------+
| runoob_id | runoob_title | runoob_author | submission_date |
+-----------+---------------+---------------+-----------------+
| 1 | 学习 PHP | 菜鸟教程 | 2017-04-12 |
| 2 | 学习 MySQL | 菜鸟教程 | 2017-04-12 |
| 3 | 学习 Java | RUNOOB.COM | 2015-05-01 |
| 4 | 学习 Python | RUNOOB.COM | 2016-03-06 |
| 5 | 学习 C | FK | 2017-04-05 |
+-----------+---------------+---------------+-----------------+
5 rows in set (0.01 sec)
INNER JOIN
mysql> SELECT a.runoob_id, a.runoob_author, b.runoob_count
FROM runoob_tbl a INNER JOIN tcount_tbl b ON a.runoob_author = b.runoob_author;
+-------------+-----------------+----------------+
| a.runoob_id | a.runoob_author | b.runoob_count |
+-------------+-----------------+----------------+
| 1 | 菜鸟教程 | 10 |
| 2 | 菜鸟教程 | 10 |
| 3 | RUNOOB.COM | 20 |
| 4 | RUNOOB.COM | 20 |
+-------------+-----------------+----------------+
4 rows in set (0.00 sec)
LEFT JOIN
mysql> SELECT a.runoob_id, a.runoob_author, b.runoob_count
FROM runoob_tbl a LEFT JOIN tcount_tbl b ON a.runoob_author = b.runoob_author;
+-------------+-----------------+----------------+
| a.runoob_id | a.runoob_author | b.runoob_count |
+-------------+-----------------+----------------+
| 1 | 菜鸟教程 | 10 |
| 2 | 菜鸟教程 | 10 |
| 3 | RUNOOB.COM | 20 |
| 4 | RUNOOB.COM | 20 |
| 5 | FK | NULL |
+-------------+-----------------+----------------+
5 rows in set (0.01 sec)
RIGHT JOIN
mysql> SELECT a.runoob_id, a.runoob_author, b.runoob_count FROM runoob_tbl a RIGHT JOIN tcount_tbl b ON a.runoob_author = b.runoob_author;
+-------------+-----------------+----------------+
| a.runoob_id | a.runoob_author | b.runoob_count |
+-------------+-----------------+----------------+
| 1 | 菜鸟教程 | 10 |
| 2 | 菜鸟教程 | 10 |
| 3 | RUNOOB.COM | 20 |
| 4 | RUNOOB.COM | 20 |
| NULL | NULL | 22 |
+-------------+-----------------+----------------+
5 rows in set (0.01 sec)
二、SQL语句50道题目练习
https://blog.csdn.net/fashion2014/article/details/78826299/
--建表
--学生表
CREATE TABLE `Student`(
`s_id` VARCHAR(20),
`s_name` VARCHAR(20) NOT NULL DEFAULT '',
`s_birth` VARCHAR(20) NOT NULL DEFAULT '',
`s_sex` VARCHAR(10) NOT NULL DEFAULT '',
PRIMARY KEY(`s_id`)
);
--课程表
CREATE TABLE `Course`(
`c_id` VARCHAR(20),
`c_name` VARCHAR(20) NOT NULL DEFAULT '',
`t_id` VARCHAR(20) NOT NULL,
PRIMARY KEY(`c_id`)
);
--教师表
CREATE TABLE `Teacher`(
`t_id` VARCHAR(20),
`t_name` VARCHAR(20) NOT NULL DEFAULT '',
PRIMARY KEY(`t_id`)
);
--成绩表
CREATE TABLE `Score`(
`s_id` VARCHAR(20),
`c_id` VARCHAR(20),
`s_score` INT(3),
PRIMARY KEY(`s_id`,`c_id`)
);
--插入学生表测试数据
insert into Student values('01' , '赵雷' , '1990-01-01' , '男');
insert into Student values('02' , '钱电' , '1990-12-21' , '男');
insert into Student values('03' , '孙风' , '1990-05-20' , '男');
insert into Student values('04' , '李云' , '1990-08-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吴兰' , '1992-03-01' , '女');
insert into Student values('07' , '郑竹' , '1989-07-01' , '女');
insert into Student values('08' , '王菊' , '1990-01-20' , '女');
--课程表测试数据
insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');
--教师表测试数据
insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
--成绩表测试数据
insert into Score values('01' , '01' , 80);
insert into Score values('01' , '02' , 90);
insert into Score values('01' , '03' , 99);
insert into Score values('02' , '01' , 70);
insert into Score values('02' , '02' , 60);
insert into Score values('02' , '03' , 80);
insert into Score values('03' , '01' , 80);
insert into Score values('03' , '02' , 80);
insert into Score values('03' , '03' , 80);
insert into Score values('04' , '01' , 50);
insert into Score values('04' , '02' , 30);
insert into Score values('04' , '03' , 20);
insert into Score values('05' , '01' , 76);
insert into Score values('05' , '02' , 87);
insert into Score values('06' , '01' , 31);
insert into Score values('06' , '03' , 34);
insert into Score values('07' , '02' , 89);
insert into Score values('07' , '03' , 98);
- 1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数
方式1:
select a.*, b.s_score as 01_score, c.s_score as 02_score from
student a , score b, score c
where a.s_id = b.s_id
and a.s_id = c.s_id
and b.c_id = '01'
and c.c_id = '02'
and b.s_score > c.s_score;
方式2:(join on)
select a.*, b.s_score as 01_score, c.s_score as 02_score from
student a
join score b on a.s_id = b.s_id and b.c_id = '01'
join score c on a.s_id = c.s_id and c.c_id = '02'
where b.s_score > c.s_score;
- 2、查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
select a.s_id, a.s_name, avg(s_score) as avg_score
from student a, score b
where a.s_id = b.s_id
group by a.s_id, a.s_name
having avg(s_score) >= 60;
- 3、查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩 (包括有成绩的和无成绩的)
select a.s_id, a.s_name, avg(b.s_score)
from student a
left join score b
on a.s_id = b.s_id
group by s_id, s_name
having avg(b.s_score) < 60
union
select a.s_id, a.s_name, 0
from student a
where a.s_id not in (select distinct s_id from score);
- 4、查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(*)
// 错误的写法,因为这里强调了是所有的学生,所以要包含那些没有成绩的学生
select a.s_id, a.s_name, count(b.c_id), sum(s_score)
from student a, score b
where a.s_id = b.s_id
group by a.s_id, s.s_name;
// 正确写法
select a.s_id, a.s_name, count(b.c_id), sum(s_score)
from student a
left join score b on a.s_id = b.s_id
group by a.s_id;
- 5、查询"李"姓老师的数量
select count(*) from teacher where t_name like '李%';
- 6、查询学过"张三"老师授课的同学的信息
// 需要找到张三老师上过课的id,如果那个学生上课的id有前者id集合中,则表示该学生上过张三老师的课
select a.* from student a
join score b on a.s_id = b.s_id where b.c_id in
(select c_id from course c
join teacher d on c.t_id = d.t_id
where d.t_name = '张三'
);
- 7、查询没学过"张三"老师授课的同学的信息 (和上一题类似)
// 先筛选出上个张三老师课程的学生的s_id统计出来,最后只需要将s_id不在前者s_id集合内的学生列举出来信息即可
select a.* from
student a where a.s_id not in (
select a.s_id from student a
join score b on a.s_id = b.s_id where b.c_id in
(select c_id from course c
join teacher d on c.t_id = d.t_id
where d.t_name = '张三'
)
);
- 8、查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息(*)
select a.* from student a, score s1, score s2
where a.s_id = s1.s_id and a.s_id = s2.s_id and s1.c_id = '01' and s2.c_id = '02';
- 9、查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息(*)
select a.* from student a
where a.s_id in (select s_id from score where c_id = '01')
and a.s_id not in (select s_id from score where c_id = '02');
- 10、查询没有学全所有课程的同学的信息 (*)
select a.* from
student a
join score b on a.s_id = b.s_id
group by b.s_id having count(*) < (select count(c_id) from course);
只关心了参加考试的学生,但是存在有学生没有参加考试;
select a.* from
student a
left join score b on a.s_id = b.s_id
group by b.s_id having count(*) < (select count(c_id) from course);
- 11、查询至少有一门课与学号为"01"的同学所学相同的同学的信息
select distinct a.* from
student a join score b on a.s_id = b.s_id
where b.c_id in (
select c.c_id from score c where c.s_id = '01'
);
- 12、查询和"01"号的同学学习的课程完全相同的其他同学的信息 (*)
select a.* from student a
where
a.s_id in (
# 找到与01同学所学课程数相同的s_id的学生
select s_id from score group by s_id
having count(c_id) = (select count(c_id) from score where s_id = '01')
)
and
a.s_id not in (
# 排除01同学学习了但是有一些同学没有学习
select distinct s_id from score where c_id not in (
select c_id from score where s_id = '01'
)
)
and
# 排除自身
a.s_id != '01';
- 13、查询没学过"张三"老师讲授的任一门课程的学生姓名
select a.s_name from student a
where a.s_id not in (
# 学过"张三"老师的课
select distinct s_id from score
where c_id in (select c_id from course where t_id = (select t_id from teacher where t_name = '张三'))
);
- 14、查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩 (*)
select a.s_id,a.s_name,ROUND(AVG(b.s_score)) from
student a
join score b on a.s_id = b.s_id
where a.s_id in(
select s_id from score where s_score<60 GROUP BY s_id having count(s_id)>=2
)
GROUP BY a.s_id
- 15.检索"01"课程分数小于60,按分数降序排列的学生信息
select a.* , b.s_score from student a , score b
where a.s_id = b.s_id and b.s_score < 60 and b.c_id = '01'
order by b.s_score desc;
递增是asc