mysql数据库查询操作

Wesley13
• 阅读 822

### mysql数据库

#### 知识要点:

1. 单表查询
2. 子查询
3. 联表查询
4. 事务

在进行查询之前,我们要先建好关系表,并往数据表中插入些数据。为查询操作做好准备。

##### 五张关系表的创建:

```mysql
#创建并进入数据库:
mysql> CREATE DATABASE `info`;
Query OK, 1 row affected (0.00 sec)
mysql> USE `info`;
Database changed

#创建学院表:
mysql> CREATE TABLE `department`(
-> `id` INT PRIMARY KEY AUTO_INCREMENT,
-> `name` VARCHAR(20) NOT NULL
-> );
Query OK, 0 rows affected (0.69 sec)
#创建学生表:
mysql> CREATE TABLE `students`(
-> `s_id` INT PRIMARY KEY AUTO_INCREMENT,
-> `name` VARCHAR(20) NOT NULL,
-> `d_id` INT,
-> FOREIGN KEY(`d_id`) REFERENCES `department` (`id`)
-> );
Query OK, 0 rows affected (0.65 sec)
#创建学生的详细信息表:
mysql> CREATE TABLE `stu_details`(
-> `s_id` INT PRIMARY KEY,
-> `age` INT,
-> `gender` CHAR(1)
-> ,
-> FOREIGN KEY(`s_id`) REFERENCES `students` (`s_id`)
-> );
Query OK, 0 rows affected (0.55 sec)
#创建课程表:
mysql> CREATE TABLE `course`(
-> `id` INT PRIMARY KEY AUTO_INCREMENT,
-> `name` VARCHAR(20) NOT NULL
-> );
Query OK, 0 rows affected (0.50 sec)
#创建中间表:
mysql> CREATE TABLE `select`(
-> `s_id` INT,
-> `c_id` INT,
-> PRIMARY KEY (`s_id`,`c_id`),
-> FOREIGN KEY (`s_id`) REFERENCES `students`(`s_id`),
-> FOREIGN KEY (`c_id`) REFERENCES `course`(`id`)
-> );
Query OK, 0 rows affected (0.84 sec)
#查看当前存在的表:
mysql> SHOW TABLES;
+----------------+
| Tables_in_info |
+----------------+
| course |
| department |
| select |
| stu_details |
| students |
+----------------+
5 rows in set (0.00 sec)
```

##### 往数据表中添加数据

```mysql
#往学院表中添加数据:
mysql> INSERT INTO `department`(`name`)
-> VALUES('外国语'),
-> ('艺术'),
-> ('计算机'),
-> ('化工')
-> ;
Query OK, 4 rows affected (0.11 sec)
Records: 4 Duplicates: 0 Warnings: 0
#往学生表中添加数据:
mysql> INSERT INTO `students`(`name`,`d_id`)
-> VALUES('小明',1),
-> ('小红',3),
-> ('小花',3),
-> ('小新',4)
-> ;
Query OK, 4 rows affected (0.09 sec)
Records: 4 Duplicates: 0 Warnings: 0
#往学生详细信息表中添加数据:
mysql> INSERT INTO stu_details
-> VALUES(1,18,'m'),
-> (4,20,'m'),
-> (3,16,'f'),
-> (2,19,'f')
-> ;
Query OK, 4 rows affected (0.11 sec)
Records: 4 Duplicates: 0 Warnings: 0
#往课程表中添加数据:
mysql> INSERT INTO `course`
-> (`name`)VALUES
-> ('心理学'),
-> ('佛学'),
-> ('近代史'),
-> ('音乐鉴赏')
-> ;
Query OK, 4 rows affected (0.08 sec)
Records: 4 Duplicates: 0 Warnings: 0
#查看中间表的结构:
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)
-> ;
Query OK, 7 rows affected (0.06 sec)
Records: 7 Duplicates: 0 Warnings: 0
```

### 查询

##### 查询所有记录

`SELECT * FROM tb_name;`

##### 查询选中列记录

`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
#查询所有记录:
mysql> SELECT * FROM `students`;
+------+--------+------+
| s_id | name | d_id |
+------+--------+------+
| 1 | 小明 | 1 |
| 2 | 小红 | 3 |
| 3 | 小花 | 3 |
| 4 | 小新 | 4 |
+------+--------+------+
4 rows in set (0.00 sec)

#查询选中列记录
mysql> SELECT name,d_id FROM students;
+--------+------+
| name | d_id |
+--------+------+
| 小明 | 1 |
| 小红 | 3 |
| 小花 | 3 |
| 小新 | 4 |
+--------+------+
4 rows in set (0.00 sec)

#查询指定条件下的记录
mysql> SELECT * FROM students WHERE `name`='小红';
+------+--------+------+
| s_id | name | d_id |
+------+--------+------+
| 2 | 小红 | 3 |
+------+--------+------+
1 row in set (0.00 sec)

#查询后为列取别名
mysql> SELECT name AS `姓名` ,d_id AS 学院id FROM students WHERE s_id>=2;
+--------+----------+
| 姓名 | 学院id |
+--------+----------+
| 小红 | 3 |
| 小花 | 3 |
| 小新 | 4 |
+--------+----------+
3 rows in set (0.00 sec)
```

##### 排序`ORDER BY`

`ASC`升序(默认) `DESC`降序

```mysql
#查询学生的选修表(中间表)
mysql> SELECT * FROM `select`;
+------+------+
| s_id | c_id |
+------+------+
| 2 | 1 |
| 4 | 1 |
| 1 | 2 |
| 4 | 2 |
| 1 | 4 |
| 2 | 4 |
| 4 | 4 |
+------+------+
7 rows in set (0.00 sec)

#按学生学号升序输出
mysql> SELECT * FROM `select` ORDER BY `s_id`;
+------+------+
| s_id | c_id |
+------+------+
| 1 | 2 |
| 1 | 4 |
| 2 | 1 |
| 2 | 4 |
| 4 | 1 |
| 4 | 2 |
| 4 | 4 |
+------+------+
7 rows in set (0.00 sec)

#按课程id降序输出:
mysql> SELECT * FROM `select` ORDER BY `c_id` DESC;
+------+------+
| s_id | c_id |
+------+------+
| 4 | 4 |
| 2 | 4 |
| 1 | 4 |
| 4 | 2 |
| 1 | 2 |
| 4 | 1 |
| 2 | 1 |
+------+------+
7 rows in set (0.00 sec)
```

##### 限制显示数据的数量`LIMIT`

```mysql
#按学生学号升序输出的前4条数据
mysql> SELECT * FROM `select` ORDER BY `s_id` LIMIT 4;
+------+------+
| s_id | c_id |
+------+------+
| 1 | 2 |
| 1 | 4 |
| 2 | 1 |
| 2 | 4 |
+------+------+
4 rows in set (0.00 sec)
#指定的返回的数据的位置和数量
mysql> SELECT * FROM `select` ORDER BY `s_id` LIMIT 4,2;
+------+------+
| s_id | c_id |
+------+------+
| 4 | 1 |
| 4 | 2 |
+------+------+
2 rows in set (0.00 sec)
```

##### 分组查询`GROUP BY`

```
例:
对学生表中学院栏进行分组,并统计学院的学生人数:
mysql> SELECT d_id AS 学院id,count(d_id) AS 学生个数 FROM students GROUP BY `d_id`;
+----------+--------------+
| 学院id | 学生个数 |
+----------+--------------+
| 1 | 1 |
| 3 | 2 |
| 4 | 1 |
+----------+--------------+
3 rows in set (0.00 sec)

HAVING分组条件
HAVING 后的字段必须是SELECT后出现过的
mysql> SELECT d_id AS 学院id,count(d_id) AS 学生个数 FROM students GROUP BY `d_id`HAVING 学生个数=1;
+----------+--------------+
| 学院id | 学生个数 |
+----------+--------------+
| 1 | 1 |
| 4 | 1 |
+----------+--------------+
2 rows in set (0.01 sec)
```

###### 查询中一些较为常见的函数

```mysql
#求最大年龄
mysql> SELECT MAX(`age`) FROM `stu_details`;
+------------+
| MAX(`age`) |
+------------+
| 20 |
+------------+
1 row in set (0.03 sec)
#求最小年龄
mysql> SELECT MIN(`age`) FROM `stu_details`;
+------------+
| MIN(`age`) |
+------------+
| 16 |
+------------+
1 row in set (0.00 sec)
#求和
mysql> SELECT SUM(`age`) FROM `stu_details`;
+------------+
| SUM(`age`) |
+------------+
| 73 |
+------------+
1 row in set (0.05 sec)
#求平均数
mysql> SELECT AVG(`age`) FROM `stu_details`;
+------------+
| AVG(`age`) |
+------------+
| 18.2500 |
+------------+
1 row in set (0.00 sec)
```

##### 子查询

出现在其他SQL语句内的SELECT字句。

1)嵌套在查询内部
2)必须始终出现在圆括号内
3)可以包含多个关键字或条件

```mysql
#查找出大于平均年龄的数据
mysql> SELECT * FROM `stu_details` WHERE `age`>18.25;
+------+------+--------+
| s_id | age | gender |
+------+------+--------+
| 2 | 19 | f |
| 4 | 20 | m |
+------+------+--------+
2 rows in set (0.00 sec)
#将平均数的SQL语句作为子查询放入上一条语句中
mysql> SELECT * FROM `stu_details` WHERE `age`>(SELECT AVG(`age`) FROM `stu_details`);
+------+------+--------+
| s_id | age | gender |
+------+------+--------+
| 2 | 19 | f |
| 4 | 20 | m |
+------+------+--------+
2 rows in set (0.10 sec)
```

#### 联表查询

##### 内连接`[INNER| CROSS] JOIN`

无条件内连接:
无条件内连接,又名交叉连接/笛卡尔连接
第一张表种的每一向会和另一张表的每一项依次组合

有条件内连接
在无条件的内连接基础上,加上一个ON子句
当连接的时候,筛选出那些有实际意义的记录行来进行拼接

在写条件时注意两张表的列名是否一样,
如果时一样的则要在前面加上表名,tb_name.colname这种形式存在

```mysql
#无条件内连接:
mysql> SELECT * FROM `students` INNER JOIN `department`;
+------+--------+------+----+-----------+
| s_id | name | d_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 `students` INNER JOIN `department`
-> ON d_id=id;
+------+--------+------+----+-----------+
| s_id | name | d_id | id | name |
+------+--------+------+----+-----------+
| 1 | 小明 | 1 | 1 | 外国语 |
| 2 | 小红 | 3 | 3 | 计算机 |
| 3 | 小花 | 3 | 3 | 计算机 |
| 4 | 小新 | 4 | 4 | 化工 |
+------+--------+------+----+-----------+
4 rows in set (0.03 sec)
```

有条件的外连接:
{ LEFT| RIGHT } [OUTER] JOIN

左外连接:
两张表做连接的时候,在连接条件不匹配的时候
留下左表中的数据,而右表中的数据以NULL填充

右外连接
对两张表做连接的时候,在连接条件不匹配的时候
留下右表中的数据,而左表中的数据以NULL填充

```mysql
#往学生表中添加数据,只添加名字
mysql> INSERT INTO students(name)
-> VALUES('xixi');
Query OK, 1 row affected (0.11 sec)
#查看所有学生表数据
mysql> SELECT * FROM studentS;
+------+--------+------+
| s_id | name | d_id |
+------+--------+------+
| 1 | 小明 | 1 |
| 2 | 小红 | 3 |
| 3 | 小花 | 3 |
| 4 | 小新 | 4 |
| 5 | xixi | NULL |
+------+--------+------+
5 rows in set (0.00 sec)
#使用内连接加条件只能看到有分配好学院的学生的信息;
mysql> SELECT * FROM students INNER JOIN department
-> ON d_id=id;
+------+--------+------+----+-----------+
| s_id | name | d_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 students LEFT JOIN department
-> ON d_id=id;
+------+--------+------+------+-----------+
| s_id | name | d_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 students RIGHT JOIN department
-> ON d_id=id;
+------+--------+------+----+-----------+
| s_id | name | d_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>
```

##### 查询SQL的优化

MySQL的执行顺序

```mysql
1.FROM: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1

2.ON: 对虚表VT1进行ON筛选,只有那些符合的行才会被记录在虚表VT2中。

3.JOIN: 如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚拟表VT3, rug from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止。

4.WHERE: 对虚拟表VT3进行WHERE条件过滤。只有符合的记录才会被插入到虚拟表VT4中。

5.GROUP BY: 根据group by子句中的列,对VT4中的记录进行分组操作,产生VT5.

6.CUBE | ROLLUP: 对表VT5进行cube或者rollup操作,产生表VT6.

7.HAVING: 对虚拟表VT6应用having过滤,只有符合的记录才会被 插入到虚拟表VT7中。

8.SELECT: 执行select操作,选择指定的列,插入到虚拟表VT8中。

9.DISTINCT: 对VT8中的记录进行去重。产生虚拟表VT9.

10.ORDER BY: 将虚拟表VT9中的记录按照<order_by_list>进行排序操作,产生虚拟表VT10.

11.LIMIT:取出指定行的记录,产生虚拟表VT11, 并将结果返回。
```

通过上面的执行顺序不难想到,要想SQL执行更快,就必须把筛选条件尽量的往前面放。如下:

```mysql
SELECT
s.`name`,
e.`name`
FROM
`students` s
LEFT JOIN(
SELECT
se.`s_id`,
c.`name`
FROM
`select` se
JOIN `course` c ON se.`c_id` = c.`id`
) e ON s.`id`=e.`stu_id`

SELECT
*
FROM
`student` s
WHERE
s.`dep_id` = (
SELECT
`id`
FROM
`department` d
WHERE
d.`name` = '外国语学院'
)
```

在这两个例子中,第一个SQL中的子表只会被查询一次,但是在第二个SQL中,子表会被执行n次,这个n取决student表中的数据条数,如果子表的数据量很大的话,那么SQL的执行速度会十分慢。

这是典型的通过执行顺序来优化SQL,除此之外,要想SQL执行快一点,应该尽量避免模糊匹配,如:like,in,not in 等这些匹配条件。

还有几点建议给大家:

1.尽量避免整表扫描,如SELECT *

2.建立合适的索引

3.使用合适的存储引擎

4.在JOIN中,尽量用小表LEFT JOIN 大表

5.除非十分必要,尽量不要使用ORDER BY,GROUP BY 和 DISTINCT(去重),尽量用索引来代替

##### 事务

为了保证数据库记录的更新从一个一致性状态变更为另一个一致性状态
使用事务来处理是非常必要。

```
例:
创建一张银行账户的表
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('shangdian',10000),
-> ('xiaoming',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`-50
-> WHERE `name` ='xiaoming'
-> ;
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`-50
-> WHERE `name`='xiaoming'
-> ;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> UPDATE `account`
-> SET `balance`=`balance`+50
->
-> WHERE `name`='shangdian'
-> ;
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)
```

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
Python进阶_mysql_查询、事物(4)
在进行查询之前,我们要先建好关系表,并往数据表中插入些数据。为查询操作做好准备。五张关系表的创建:创建并进入数据库:mysqlCREATEDATABASEinfo;QueryOK,1rowaffected(0.00sec)mysqlUSEinfo;Data
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
mysql5.6 分页查询优化
mysql5.6分页查询优化场景:表结构:主键(非自增)contentCode(varchar),过滤条件列为updateTime(timeStamp),已经为timestamp建立索引。搜索sql为:SELECTFROMmy_hello_tableWHEREupdat
Wesley13 Wesley13
3年前
oracle查询表数据并重新插入到本表
oracle查询表数据并重新插入到本表CreateTime2018年5月17日10:30:10Author:Marydon1.情景描述查询表中数据SELECTFROMat_aut
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究