MySQL数据库基本操作(四)
1. 单表查询
2. 子查询
3. 联表查询
4. 事务
五张关系表的创建:
#创建并进入数据库: mysql> CREATE DATABASE `info`; Query OK, 1 row affected (0.00 sec) mysql> USE `info`; Database changed #创建学院表: CREATE TABLE `department`( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(20) NOT NULL ); #创建学生表: CREATE TABLE `student`( `s_id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(20) NOT NULL, `dept_id` INT, FOREIGN KEY(`dept_id`) REFERENCES `department` (`id`) ); #创建学生的详细信息表: CREATE TABLE `stu_details`( `s_id` INT PRIMARY KEY, `age` INT, `sex` CHAR(1), FOREIGN KEY(`s_id`) REFERENCES `student` (`s_id`) ); #创建课程表: CREATE TABLE `course`( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(20) NOT NULL ); #创建中间表: CREATE TABLE `select`( `s_id` INT, `c_id` INT, PRIMARY KEY (`s_id`,`c_id`), FOREIGN KEY (`s_id`) REFERENCES `student`(`s_id`), FOREIGN KEY (`c_id`) REFERENCES `course`(`id`) ); #查看当前存在的表: mysql> SHOW TABLES;
#往学院表中添加数据: mysql> INSERT INTO `department`(`name`) -> VALUES(\'外国语\'),(\'艺术\'),(\'计算机\'),(\'化工\'); #往学生表中添加数据: mysql> INSERT INTO `student`(`name`,`dept_id`) -> VALUES(\'小明\',1),(\'小红\',3),(\'小花\',3),(\'小新\',4),(\'张三\',2),(\'刘三\',3); #往学生详细信息表中添加数据: mysql> INSERT INTO stu_details -> VALUES(1,18,\'男\'),(4,20,\'女\'),(3,16,\'女\'),(2,19,\'男\'); #往课程表中添加数据: mysql> INSERT INTO `course`(`name`) -> VALUES (\'心理学\'),(\'佛学\'),(\'近代史\'), (\'音乐鉴赏\'); #查看中间表的结构: (select是关键字,要加反引号) mysql> DESC `select`; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | s_id | int(11) | NO | PRI | NULL | | | c_id | int(11) | NO | PRI | NULL | | +-------+---------+------+-----+---------+-------+ 2 rows in set (0.03 sec) #往中间表中添加数据 mysql> INSERT INTO `select` -> VALUES(1,2),(1,4),(2,1),(2,4),(4,1),(4,2),(4,4);
查询所有记录
SELECT * FROM tb_name;
SELECT * FROM `department`;
SELECT * FROM `student`;
SELECT * FROM `stu_details`;
SELECT * FROM `course`;
SELECT * FROM `select`;
查询选中列记录
SELECT col_name1,col_name2 FROM tb_name;
查询指定条件下的记录
SELECT col_name FROM tb_name WHERE 条件
查询后为列取别名
SELECT col_name AS new_name FROM tab_name
模糊查询
#查询所有记录: mysql> SELECT * FROM `student`; #查询选中列记录 mysql> SELECT name,dept_id FROM student; #查询指定条件下的记录 mysql> SELECT * FROM student WHERE `name`=\'小红\'; #查询后为列取别名 SELECT name AS `姓名` ,dept_id AS 学院id FROM student WHERE s_id>=2; SELECT name ,dept_id FROM student WHERE s_id>=2; SELECT name `姓名` ,dept_id 学院id FROM student WHERE s_id>=2; #模糊查询 * mysql> select * from student where name like \'小%\'; mysql> select * from student where name like \'小_\'; mysql> select * from student where name like \'%小%\'; % 多个字(任意个)* _ 一个字 #逻辑运算符 or and # or select * from student where name like \'小%\' or name like \'张%\'; # and select * from student where name like \'小%\' and s_id >2; # 判断为null,不用 = ,只能用 is is not select * from student where dept_id is null; select * from student where dept_id is not null;
排序ORDER BY
ASC
升序(默认) DESC
降序
#查询学生的选修表(中间表) mysql> SELECT * FROM `select`; #按学生学号升序输出 mysql> SELECT * FROM `select` ORDER BY `s_id`; select s_id 学生,c_id 课程 from `select` order by s_id asc; #按课程id降序输出: mysql> SELECT * FROM `select` ORDER BY `c_id` DESC;
限制显示数据的数量LIMIT
#按学生学号升序输出的前4条数据 mysql> SELECT * FROM `select` ORDER BY `s_id` LIMIT 4; # (0,4) 从 索引为0, 往后面拿4条 #指定的返回的数据的位置和数量 mysql> SELECT * FROM `select` ORDER BY `s_id` LIMIT 4,4; # (4,4) 从 索引为4, 往后面拿4条
分组查询GROUP BY
## 一般跟聚合函数 #对学生表中学院栏进行分组,并统计学院的学生人数: mysql> SELECT dept_id AS 学院id,count(dept_id) AS 学生个数 FROM student GROUP BY `dept_id` ; +----------+--------------+ | 学院id | 学生个数 | +----------+--------------+ | 1 | 1 | | 3 | 2 | | 4 | 1 | +----------+--------------+ 3 rows in set (0.00 sec) select * from student order by dept_id; ## 不能这么写 # select s_id , age ,sex from stu_details group by sex # group by 只能跟聚合函数一起用, 一般用 做统计 select sex , MAX(age) from stu_details group by sex # 装B select dept_id,group_concat(s_id,name separator \',\') from student group by `dept_id`; 3 | 2小红,3小花,6刘三 select dept_id,group_concat(s_id,\' \',name separator \',\') from student group by `dept_id`; HAVING分组条件 HAVING 后的字段必须是SELECT后出现过的 mysql> SELECT dept_id AS 学院id,count(dept_id) AS 学生个数 FROM student GROUP BY `dept_id` HAVING 学生个数=1; +----------+--------------+ | 学院id | 学生个数 | +----------+--------------+ | 1 | 1 | | 4 | 1 | +----------+--------------+ 2 rows in set (0.01 sec) 区别: where 带着条件 去表里面,删选内容, (table) having :select 出来了结果,在进行一次删选。
出现在其他SQL语句内的SELECT字句。
1)嵌套在查询内部
2)必须始终出现在圆括号内
3)可以包含多个关键字或条件
### 把别人的结果,当成数据,直接拿过来用。 # 求出学生的平均年龄 SELECT AVG(`age`) FROM `stu_details`; #查找出大于平均年龄的数据 mysql> SELECT * FROM `stu_details` WHERE `age`>18.25; #将平均数的SQL语句作为子查询放入上一条语句中 mysql> SELECT * FROM `stu_details` WHERE `age`>(SELECT AVG(`age`) FROM `stu_details`); ##需求: 要查找,计算机和外国语 的学生 select id from department where name in (\'计算机\',\'外国语\'); select * from student where dept_id in (select id from department where name in (\'计算机\',\'外国语\') ); # in , not in select * from student where dept_id not in (1,3); select * from student where dept_id in (1,3);
联表查询
内连接[INNER| CROSS] JOIN
无条件内连接:无条件内连接,又名交叉连接/笛卡尔连接
第一张表种的每一项会和另一张表的每一项依次组合
有条件内连接:在无条件的内连接基础上,加上一个ON子句
当连接的时候,筛选出那些有实际意义的记录行来进行拼接
在写条件时注意两张表的列名是否一样,如果时一样的则要在前面加上表名,tb_name.colname这种形式存在
#无条件内连接: mysql> SELECT * FROM `student` INNER JOIN `department`; +------+--------+------+----+-----------+ | s_id | name | dept_id | id | name | +------+--------+------+----+-----------+ | 1 | 小明 | 1 | 1 | 外国语 | | 2 | 小红 | 3 | 1 | 外国语 | | 3 | 小花 | 3 | 1 | 外国语 | | 4 | 小新 | 4 | 1 | 外国语 | | 1 | 小明 | 1 | 2 | 艺术 | | 2 | 小红 | 3 | 2 | 艺术 | | 3 | 小花 | 3 | 2 | 艺术 | | 4 | 小新 | 4 | 2 | 艺术 | | 1 | 小明 | 1 | 3 | 计算机 | | 2 | 小红 | 3 | 3 | 计算机 | | 3 | 小花 | 3 | 3 | 计算机 | | 4 | 小新 | 4 | 3 | 计算机 | | 1 | 小明 | 1 | 4 | 化工 | | 2 | 小红 | 3 | 4 | 化工 | | 3 | 小花 | 3 | 4 | 化工 | | 4 | 小新 | 4 | 4 | 化工 | +------+--------+------+----+-----------+ 16 rows in set (0.04 sec) #有条件内连接: mysql> SELECT * FROM `student` INNER JOIN `department` -> ON dept_id=id; +------+--------+------+----+-----------+ | s_id | name | dept_id | id | name | +------+--------+------+----+-----------+ | 1 | 小明 | 1 | 1 | 外国语 | | 2 | 小红 | 3 | 3 | 计算机 | | 3 | 小花 | 3 | 3 | 计算机 | | 4 | 小新 | 4 | 4 | 化工 | +------+--------+------+----+-----------+ 4 rows in set (0.03 sec) #需求: 查询出 学生姓名,和对应学院名 mysql> SELECT s.name 姓名, d.name 学院 FROM `student` s -> INNER JOIN `department` d -> ON dept_id=id;
外连接{ LEFT| RIGHT } [OUTER] JOIN
{ LEFT| RIGHT } [OUTER] JOIN
左外连接: (以左表为基准)两张表做连接的时候,在连接条件不匹配的时候留下左表中的数据,而右表中的数据以NULL填充
右外连接: (以右表为基准)对两张表做连接的时候,在连接条件不匹配的时候留下右表中的数据,而左表中的数据以NULL填充
#往学生表中添加数据,只添加名字 mysql> INSERT INTO student(name) -> VALUES(\'xixi\'); Query OK, 1 row affected (0.11 sec) #查看所有学生表数据 mysql> SELECT * FROM student; +------+--------+------+ | s_id | name | dept_id | +------+--------+------+ | 1 | 小明 | 1 | | 2 | 小红 | 3 | | 3 | 小花 | 3 | | 4 | 小新 | 4 | | 5 | xixi | NULL | +------+--------+------+ 5 rows in set (0.00 sec) #使用内连接加条件只能看到有分配好学院的学生的信息; mysql> SELECT * FROM student INNER JOIN department -> ON dept_id=id; +------+--------+------+----+-----------+ | s_id | name | dept_id | id | name | +------+--------+------+----+-----------+ | 1 | 小明 | 1 | 1 | 外国语 | | 2 | 小红 | 3 | 3 | 计算机 | | 3 | 小花 | 3 | 3 | 计算机 | | 4 | 小新 | 4 | 4 | 化工 | +------+--------+------+----+-----------+ 4 rows in set (0.02 sec) #使用左连接把学生的数据全取出来,该学生没有学院信息的用NULL填充 mysql> SELECT * FROM student LEFT JOIN department -> ON dept_id=id; +------+--------+------+------+-----------+ | s_id | name | dept_id | id | name | +------+--------+------+------+-----------+ | 1 | 小明 | 1 | 1 | 外国语 | | 2 | 小红 | 3 | 3 | 计算机 | | 3 | 小花 | 3 | 3 | 计算机 | | 4 | 小新 | 4 | 4 | 化工 | | 5 | xixi | NULL | NULL | NULL | +------+--------+------+------+-----------+ 5 rows in set (0.00 sec) #使用右外连接把目前还没有学生的学院的数据也显示出来 mysql> SELECT * FROM student RIGHT JOIN department -> ON dept_id=id; +------+--------+------+----+-----------+ | s_id | name | dept_id | id | name | +------+--------+------+----+-----------+ | 1 | 小明 | 1 | 1 | 外国语 | | 2 | 小红 | 3 | 3 | 计算机 | | 3 | 小花 | 3 | 3 | 计算机 | | 4 | 小新 | 4 | 4 | 化工 | | NULL | NULL | NULL | 2 | 艺术 | +------+--------+------+----+-----------+ 5 rows in set (0.00 sec) mysql>
# 需求: 作为班主任,我想看到,学生的 ( 姓名,选的课程名,所属学院 ) select s.name, c.name,d.name from `student` s left join `select` se on se.s_id = s.s_id left join course c on se.c_id = c.id left join department d on s.dept_id = d.id; ##1. select s.name,d.name from student s left join department d on s.dept_id=d.id; ##2.学生选的课(名称) select se.s_id ,c.name from `select` se left join course c on se.c_id = c.id; select s.name, d.name, c.name from student s left join department d on s.dept_id = d.id left join `select` se on s.s_id = se.s_id left join course c on se.c_id = c.id; select s.name ,GROUP_CONCAT(c.name SEPARATOR \',\') 课程,d.name from `student` s left join `select` se on s.s_id = se.s_id left join `course` c on se.c_id = c.id left join `department` d on s.dept_id = d.id group by s.name,d.name ; +--------+-------------------------------+-----------+ | name | 课程 | name | +--------+-------------------------------+-----------+ | xixi | NULL | NULL | | 小新 | 心理学,佛学,音乐鉴赏 | 化工 | | 小明 | 佛学,音乐鉴赏 | 外国语 | | 小红 | 音乐鉴赏,心理学 | 计算机 | | 小花 | NULL | 计算机 | +--------+-------------------------------+-----------+ #需求: 作为宿管, 学生的 ( 姓名, 年龄,性别,所属学院) select s.name, stu.age,stu.sex,d.name from student s left join `stu_details` stu on s.s_id = stu.s_id left join `department` d on s.dept_id = d.id; +--------+------+------+-----------+ | name | age | sex | name | +--------+------+------+-----------+ | 小明 | 18 | 男 | 外国语 | | 小红 | 19 | 男 | 计算机 | | 小花 | 16 | 女 | 计算机 | | 小新 | 20 | 女 | 化工 | | xixi | NULL | NULL | NULL | +--------+------+------+-----------+
事务: 是数据库运行中的一个逻辑工作单位。 #原子性 事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。 #一致性 事务在完成时,必须使所有的数据都保持一致状态。 #隔离性 由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。
为了保证数据库记录的更新从一个一致性状态变更为另一个一致性状态使用事务来处理是非常必要。
例: 创建一张银行账户的表 mysql> CREATE TABLE `account`( -> `id` INT PRIMARY KEY AUTO_INCREMENT, -> `name` VARCHAR(20) NOT NULL, -> `balance` INT -> ); Query OK, 0 rows affected (0.52 sec) 添加两个用户及用户的存款的信息 mysql> INSERT INTO `account`(`name`,`balance`) -> VALUES(\'张三\',10000), -> (\'小明\',2000) -> ; Query OK, 2 rows affected (0.09 sec) Records: 2 Duplicates: 0 Warnings: 0 假设现在用户小明在商店买了500元东西,现在要转账给商店,那么就需要从小明的账户上减去500,然后在商店的用户上加上500,但是如果在减500的过程中出现了系统故障,再重新启动后发现小明的钱扣了,但商店却没有收到,这时候就会出现数据变动不一致。对于这种数据的修改我们需要的就是要么同时修改成功,要么同时修改失败,所以这就需要用事务来进行出来。 START TRANSACTION:开始一个新的事务 COMMIT:提交当前事务,做出永久改变 ROLLBACK:回滚当前事务,放弃修改 mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> UPDATE `account` -> SET `balance`= `balance`-500 -> WHERE `name` =\'小明\' -> ; Query OK, 1 row affected (0.04 sec) Rows matched: 1 Changed: 1 Warnings: 0 使用ROLLBACK;使数据的修改不生效,回到事务前的状态: mysql> ROLLBACK; Query OK, 0 rows affected (0.06 sec) 做一次正确的操作: mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> UPDATE `account` -> SET `balance`=`balance`-500 -> WHERE `name`=\'小明\' -> ; Query OK, 1 row affected (0.03 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> UPDATE `account` -> SET `balance`=`balance`+500 -> WHERE `name`=\'张三\' -> ; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> SELECT * FROM `account`; mysql> COMMIT; Query OK, 0 rows affected (0.07 sec) 当COMMIT后,数据修改成功,ROLLBACK也没法回到之前了。 mysql> ROLLBACK; Query OK, 0 rows affected (0.00 sec)