龙空技术网

MySQL数据库 第5章:单表操作

惊鸿若梦一书生 810

前言:

现在同学们对“mysql除法”大致比较着重,兄弟们都需要剖析一些“mysql除法”的相关内容。那么小编也在网络上网罗了一些对于“mysql除法””的相关文章,希望各位老铁们能喜欢,同学们快快来了解一下吧!

5.1 数据操作5.1.1 复制表结构和数据

1. 复制表结构

先思考一个问题,如何快速的创建与已有表结构相同的数据表?

根据前面章节的学习,有两种方式:

依据数据表,手动CREATE TABLE再次实现一个表的创建。SHOW CREATE TABLE,复制此查询结果、修改表名并执行创建语句。

但是,MySQL提供了一种更快捷的方式:复制表结构

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] 表名

{ LIKE 旧表名| (LIKE旧表名 ) };

作用是:从“旧表名”中复制一份相同的表结构,但不会复制表中保存的数据。

其中,“{}”表示语法在使用时可以任选其中一种,“|”表示或的意思。[]表示可选项

举例如下:

CREATE TABLE mydb.my_goods LIKE sh_goods;

作用:复制表shgoods的表结构 到 mydb.mygoods表中

2. 复制数据

上面讲了复制表结构,那如何将表中的已有数据快速的添加到指定表中?

根据前面章节的学习,只有一种方式:

通过INSERT…INTO手动编写添加的数据内容。

MySQL提供了一种快捷的方式:复制表数据

INSERT [INTO] 数据表名1 [(字段列表)] SELECT [(字段列表)] FROM 数据表名2;

数据表名1和数据表名2通常使用的是同一个表(如my_goods表)

可在短期内快速增加表的数据量,测试表的压力以及效率等。

举例:

从shgoods表中复制数据到mygoods表中:

INSERT INTO mydb.my_goods SELECT * FROM sh_goods;

结果可以正常执行,但如果我们再执行一遍就会出错:

mysql> INSERT INTO mydb.my_goods SELECT * FROM sh_goods;

ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

提示我们主键有个重复条目‘1’,这就是主键冲突,以上主键冲突的问题,数据复制时可以指定除id主键外的任意字段完成。

mysql> INSERT INTO mydb.my_goods (category_id, name, keyword, price,

-> content) SELECT category_id, name, keyword, price, content

-> FROM sh_goods;

Query OK, 10 rows affected (0.00 sec)

Records: 10 Duplicates: 0 Warnings: 0

5.1.1 节的测试代码如下,大家复制后一条条执行,看看效果:

-- create table goods(id int unsigned primary key auto_increment,name varchar(36))

-- create table new_goods like goods

-- insert into goods values(0,'book')

-- insert into mysql.new_goods select * from goods

-- insert into mysql.new_goods(name) select name from goods

扩展知识点:临时表

临时表就是当前会话中有效,重新连接数据库服务器后该表就不存在了。

临时表:是一种仅在当前会话中可见,并在当前会话关闭时自动删除的数据表。

作用:主要用于临时存储数据。

语法:只需在CREATE与TABLE关键中间添加TEMPORARY即可。

# 方式1:创建临时表

CREATE TEMPORARY TABLE mydb.tmp_table1 (id int);

# 方式2:创建临时表

CREATE TEMPORARY TABLE mydb.tmp_table2 SELECT id,name FROM shop.sh_goods;

建临时表时指定的数据库可以是MySQL服务器中存在的数据库也可以是不存在的数据库。

若数据库不存在,操作临时表时必须使用“数据库.临时表名”指定临时表所在的数据库。

临时表中数据的操作与普通表相同,都可以进行SELECT、INSERT、UPDATE和DELETE操作。

SHOW TABLES不能查看指定数据库下有哪些临时表.

临时表的表名必须使用ALTER TABLE修改,而不能使用RENAME TABLE…TO修改。

5.1.2 解决主键冲突提出问题:向一个表 插入数据时,如何解决主键冲突的问题?具体示例:mydb.my_goods表经过数据复制以后,再插入编号为20的商品信息(橡皮,文具类,用于修正书写错误)会发生主键冲突。

mysql> INSERT INTO mydb.my_goods(id, name, content, keyword)

-> VALUES (20, '橡皮', '修正书写错误', '文具');

ERROR 1062 (23000): Duplicate entry '20' for key 'PRIMARY'

解决主键冲突:

方式一:主键冲突更新

当插入数据的过程中若发生主键冲突,则插入数据操作利用更新的方式实现。

INSERT [INTO] 数据表名 [(字段列表)] {VALUES | VALUE} (字段列表)

ON DUPLICATE KEY UPDATE 字段名1 = 新值1[,字段名2 = 新值2] …;

举例:

mysql> INSERT INTO mydb.my_goods (id, name, content, keyword)

-> VALUES (20, '橡皮', '修正书写错误', '文具')

-> ON DUPLICATE KEY UPDATE name = '橡皮', content = '修正书写错误',

-> keyword = '文具';

Query OK, 2 rows affected (0.00 sec)

mysql> SELECT name, content, keyword FROM mydb.my_goods WHERE id = 20;

+------+------------+---------+

| name | content | keyword |

+------+------------+---------+

| | | |

+------+------------+---------+

1 row in set (0.00 sec)

方式二:主键冲突替换

当插入数据的过程中若发生主键冲突,则删除此条记录,并重新插入。

REPLACE [INTO] 数据表名 [(字段列表)]

{VALUES | VALUE} (值列表) [, (值列表)] …;

举例:

mysql> REPLACE INTO mydb.my_goods (id, name, content, keyword)

-> VALUES (20, '橡皮', '修正书写错误', '文具');

Query OK, 2 rows affected (0.00 sec)

mysql> SELECT name, content, keyword FROM mydb.my_goods WHERE id = 20;

+------+------------+---------+

| name | content | keyword |

+------+------------+---------+

| | | |

+------+------------+---------+

1 row in set (0.00 sec)

REPLACE语句与INSERT语句的使用类似,区别在于前者每执行一次就会发生两个操作(删除记录和插入记录)。

5.1.3 清空数据

TRUNCATE [TABLE] 表名

例如:

mysql> TRUNCATE TABLE mydb.my_goods;

Query OK, 0 rows affected (0.08 sec)

TRUNCATE操作与DELETE语句在本质上的区别:

实现方式不同:TRUNCATE本质上先执行删除(DROP)数据表的操作,然后再根据有效的表结构文件(.frm)重新创建数据表的方式来实现数据清空操作。而DELETE语句则是逐条的删除数据表中保存的记录。执行效率不同:在针对大型数据表(如千万级的数据记录)时,TRUNCATE清空数据的实现方式,决定了它比DELETE语句删除数据的方式执行效率更高。对AUTO_INCREMENT的字段影响不同:TRUNCATE清空数据后,再次向表中添加数据,自动增长字段会从默认的初始值重新开始,而使用DELETE语句删除表中的记录时,则不影响自动增长值。删除数据的范围不同:TRUNCATE语句只能用于清空表中的所有记录,而DELETE语句可通过WHERE指定删除满足条件的部分记录。返回值含义不同:TRUNCATE操作的返回值一般是无意义的,而DELETE语句则会返回符合条件被删除的记录数。所属SQL语言的不同组成部分:DELETE语句属于DML数据操作语句,而TRUNCATE通常被认为是DDL数据定义语句。

案例:

为my_goods插入10条记录后,使用TRUNCATE清空并重新插入数据。

mysql> TRUNCATE TABLE mydb.my_goods;

Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO mydb.my_goods (name, content, keyword)

-> VALUES ('苹果', '一种很有营养的水果', '水果');

Query OK, 1 row affected (0.00 sec)

mysql> SELECT id, name, content, keyword FROM mydb.my_goods;

+----+------+--------------------+------------+

| id | name | content | keyword |

+----+------+--------------------+------------+

| 1 | | | |

+----+------+--------------------+------------+

1 row in set (0.00 sec)

为my_goods插入10条记录后,使用DELETE删除并重新插入数据。

mysql> DELETE FROM mydb.my_goods;

Query OK, 10 rows affected (0.00 sec)

mysql> INSERT INTO mydb.my_goods (name, content, keyword)

-> VALUES ('苹果', '一种很有营养的水果', '水果');

Query OK, 1 row affected (0.00 sec)

mysql> SELECT id, name, content, keyword FROM mydb.my_goods;

+----+------+--------------------+------------+

| id | name | content | keyword |

+----+------+--------------------+------------+

| 11 | | | |

+----+------+--------------------+------------+

1 row in set (0.00 sec)

注意看主键的值不同,truncate后主键的值为1,delete主键的值为11

对比TRUNCATE操作与DELETE语句操作的区别:

DELETE的返回值表示有10条记录受影响,而TRUNCATE的返回值为0,明显无实际意义。删除数据后,再次新增一条记录后,查询到的商品id值明显不同,TRUNCATE后id字段从默认值1开始增长,而DELETE后id值则继续从10开始增长,因此最后结果为11。当删除的数据量很小时,DELETE的执行效率要比TRUNCATE高;只有删除的数据量很大时,才能看出TRUNCATE的执行效率比DELETE高。

例如,my_goods表含有20480条记录时,使用TRUNCATE清空数据的执行时间仍然为0.01秒,而DELETE语句的执行时间会大约增加到0.17秒左右。5.1.4 去除重复记录

实际应用中,出于对数据的分析需求,有时需要去除查询记录中重复的数据。

例如,查看商品表中共有几种分类,此时可以使用SELECT语句的选项。

SELECT select选项 字段列表 FROM 数据表;

select选项:默认值为All,表示保存所有查询到的记录。当设置为DISTINCT时,表示去除重复记录,只保留一条。当查询记录的字段有多个时,必须所有字段的值完全相同才被认为是重复记录。

未去除重复记录演示:

去除重复记录演示:

5.2 排序与限量5.2.1 排序

在项目开发时,为了使查询的数据结果满足用户的要求,通常会对查询出的数据进行上升或下降的排序。

MySQL提供了两种排序的方式,分别为单字段排序和多字段排序。

单字段排序:指的是查询时仅按照一个指定字段进行升序或降序排序。

SELECT *|{字段列表} FROM 数据表名

ORDER BY 字段名 [ASC | DESC];

ASC表示升序,DESC表示降序。ORDER BY默认值为ASC。

例如:

多字段排序:指的是查询时按照指定的多个字段进行升序或降序排序。

SELECT *|{字段列表} FROM 数据表名

ORDER BY 字段名1 [ASC | DESC] [, 字段名2 [ASC | DESC]]…;

多字段排序首先按照字段名1进行排序,当字段1的值相同时,再按照字段2进行排序,依次类推。

数据表的字符集是utf8,当排序的字段为中文时,默认不会按照中文拼音的顺序排序。

在不改变数据表结构的情况下,可以使用“CONVERT(字段名 USING gbk)”函数强制让指定的字段按中文排序。在按照指定字段进行升序排列时,如果某条记录的字段值为NULL,则系统会将NULL看作是最小的值,从而将其显示在查询结果中的第一条记录的位置。5.2.2 限量

对于一次性查询出的大量记录,不仅不便于阅读查看,还会浪费系统效率。

MySQL中提供了一个关键字LIMIT,可以限定记录的数量,也可以指定查询从哪一条记录开始(通常用于分页)。

SELECT [select 选项] 字段列表 FROM 数据表名

[WHERE 条件表达式] [ORDER BY 字段 ASC|DESC]

LIMIT [OFFSET,] 记录数;

记录数:表示限定获取的最大记录数量。仅含此参数时,表示从第1条记录开始获取。OFFSET:表示偏移量,用于设置从哪条记录开始,默认第1条记录的偏移量值为0,第2条记录的偏移量值为1,依次类推。

举例:

限制记录数:查询shgoods表中价格最贵的商品

![在这里插入图片描述]()获取指定区间的记录数:从第1条记录开始的5条商品记录:![在这里插入图片描述]()

排序后限量更新或删除数据

在MySQL中除了对查询记录进行排序和限量外,对数据表中记录的更新与删除操作也可以进行排序和限量。

# 数据更新的排序与限量

UPDATE 数据表名 SET 字段=新值, … [WHERE 条件表达式]

ORDER BY 字段 ASC|DESC LIMIT 记录数;

# 数据删除的排序与限量

DELETE FROM 数据表名 [WHERE 条件表达式]

ORDER BY 字段 ASC|DESC LIMIT 记录数;

UPDATE和DELETE操作中添加ORDER BY表示根据指定的字段,按顺序更新或删除符合条件的记录。如果UPDATE和DELETE操作没有添加WHERE条件,则可以使用LIMIT来限制更新和删除的数量。

例如:

把shgoods表中最便宜的两个商品的stock(库存)设置为500:

![在这里插入图片描述]()

5.3 分组与聚合函数5.3.1 分组分组操作的目的:就是为了统计。分组的关键字:GROUP BY。分组筛选:用HAVING进行条件筛选。常见的分组:分组统计、分组排序、多分组统计、回溯统计、统计筛选。

分组统计:查询时在WHERE条件后添加GROUP BY即可进行分组统计。

SELECT [select 选项] 字段列表 FROM 数据表名

[WHERE 条件表达式] GROUP BY 字段名;

在MySQL5.7中分组后,SELECT获取的字段列表只能是GROUP BY分组的字段,或使用了聚合函数的非分组字段。若在获取非分组字段时没有使用聚合函数,MySQL会报错误提示。

例如:

通过聚合函数MAX()获取每个分类下商品的最高价格。

mysql> SELECT category_id, MAX(price) FROM sh_goods GROUP BY category_id;

+-------------+------------+

| category_id | MAX(price) |

+-------------+------------+

| 3 | 15.00 |

| 6 | 1999.00 |

| 8 | 69.00 |

| 9 | 109.00 |

| 10 | 2000.00 |

| 12 | 5999.00 |

| 15 | 299.00 |

| 16 | 48.00 |

+-------------+------------+

8 rows in set (0.00 sec)

MySQL5.6等老版本中,分组后获取的字段列表,若非分组字段没有使用聚合函数,默认只保留每组中的第一条记录。但是此操作在MySQL5.7及以上版本中已被禁止。为避免项目开发MySQL版本升级带来的问题,推荐读者在编写分组SQL语句时按照MySQL5.7新版本更严格的方式进行设计。

分组排序:默认分组操作的字段提供按升序排序,因此在分组时可为指定的字段进行升序或降序排序。

SELECT [select 选项] 字段列表 FROM 数据表名

[WHERE 条件表达式] GROUP BY 字段名 [ASC | DESC];

GROUP BY分组排序的实现不需要使用ORDER BY,直接在分组字段后添加ASC(升序,默认值可省略)或DESC(降序)即可。

例如:根据shgoods表中的分类id进行分组降序操作

![在这里插入图片描述]()

GROUPCONCAT(id)的作用是将指定字段id的值连成一个字符串,比如最后一个categoryid=3时,id有3个,分别为1,2,3,所以,GROUPCONCAT(id)=1,2,3

多分组统计:按某个字段进行分组后,对已经分组的数据进行再次分组的操作。

SELECT [select 选项] 字段列表 FROM 数据表名

[WHERE 条件表达式]

GROUP BY 字段名1 [ASC | DESC], [, 字段名2 [ASC | DESC]]…;

查询出的数据首先按照字段1进行分组排序,再将字段1相同的结果按照字段2进行分组排序,依次类推。

例如:以评分score降序分组后,再以评论数commentcount升序排序

![在这里插入图片描述]()

回溯统计:在根据指定字段分组后,系统又自动对分组的字段向上进行了一次新的统计并产生一个新的统计数据,且该数据对应的分组字段值为NULL。

SELECT [select 选项] 字段列表 FROM 数据表名

[WHERE 条件表达式]

GROUP BY 字段名1 [ASC | DESC], [, 字段名2 [ASC | DESC]]… WITH ROLLUP;

单字段分组的回溯统计

mysql> SELECT category_id, COUNT(*)

-> FROM sh_goods GROUP BY category_id WITH ROLLUP;

+-------------+----------+

| category_id | COUNT(*) |

+-------------+----------+

| 3 | 3 |

| 6 | 1 |

| 8 | 1 |

| 9 | 1 |

| 10 | 1 |

| 12 | 1 |

| 15 | 1 |

| 16 | 1 |

| NULL | 10 |

+-------------+----------+

9 rows in set (0.00 sec)

多字段分组的回溯统计

mysql> SELECT score, comment_count, COUNT(*)

-> FROM sh_goods

-> GROUP BY score, comment_count WITH ROLLUP;

+-------+---------------+----------+

| score | comment_count | COUNT(*) |

+-------+---------------+----------+

| 2.50 | 200 | 1 |

| 2.50 | NULL | 1 |

| 3.90 | 500 | 2 |

| 3.90 | NULL | 2 |

| 4.50 | 1000 | 1 |

| 4.50 | NULL | 1 |

| 4.80 | 6000 | 1 |

| 4.80 | 98000 | 1 |

| 4.80 | NULL | 2 |

| 4.90 | 40000 | 2 |

| 4.90 | NULL | 2 |

| 5.00 | 98000 | 2 |

| 5.00 | NULL | 2 |

| NULL | NULL | 10 |

+-------+---------------+----------+

14 rows in set (0.00 sec)

虽然回溯统计对数据的分析很有帮助,但是MySQL的同一个查询语句中回溯统计(WITH ROLLUP)与排序(ORDER BY)仅能出现一个。

统计筛选:对查询的数据分组时,可以利用HAVING根据条件进行数据筛选,它与前面学习过的WHERE功能相同,但是在实际运用时两者有一定的区别。

WHERE操作是从数据表中获取数据,将数据从磁盘存储到内存中,而HAVING是对已存放到内存中的数据进行操作。HAVING位于GROUP BY子句后,而WHERE位于GROUP BY 子句之前。HAVING关键字后可以使用聚合函数,而WHERE则不可以。通常情况下,HAVING关键字与GROUP BY一起使用,对分组后的结果进行过滤。

SELECT [select 选项] 字段列表 FROM 数据表名

[WHERE 条件表达式]

GROUP BY 字段名 [ASC | DESC], …[WITH ROLLUP]

HAVING 条件表达式;

WHERE条件之后的所有语句都是对内存中的数据进行操作。HAVING则根据条件表达式对分组后的内容进行过滤。

获取评分和评分数不同的情况下,含有两件商品的对应商品id:

mysql> SELECT score, comment_count, GROUP_CONCAT(id)

-> FROM sh_goods

-> GROUP BY score, comment_count

-> HAVING COUNT(*) = 2;

+-------+---------------+------------------+

| score | comment_count | GROUP_CONCAT(id) |

+-------+---------------+------------------+

| 3.90 | 500 | 2,7 |

| 4.90 | 40000 | 1,9 |

| 5.00 | 98000 | 3,5 |

+-------+---------------+------------------+

3 rows in set (0.00 sec)

在查询中使用别名:

在MySQL中执行查询操作时,可以根据具体情况为获取的字段设置别名。

例如,通过设置别名来缩短字段的名称长度。

# 字段设置别名

SELECT 字段1 [AS] 别名1, 字段2 [AS] 别名2 [, …] FROM 表名

# 表设置别名

SELECT 表别名.字段 [, …] FROM 表名 [AS] 表别名

AS用于为其前面的字段、表达式、函数等设置别名,也可省略AS使用空格代替。例如,为categoryid设置别名cid,可以使用“categoryid AS cid”或“category_id cid”。

为字段设置别名,举例:

mysql> SELECT category_id cid, MAX(price) max_price FROM sh_goods

-> GROUP BY cid HAVING cid = 3 OR cid = 6;

+-----+-----------+

| cid | max_price |

+-----+-----------+

| 3 | 15.00 |

| 6 | 1999.00 |

+-----+-----------+

1 row in set (0.00 sec)

为表设置别名

SELECT g.category_id cid, MAX(g.price) max_price FROM sh_goods g

GROUP BY cid HAVING cid = 3 OR cid = 6;

字段与表设置别名后,在排序和分组中可以使用原来的字段名等,也可以使用别名。表的别名主要在多表查询中使用,具体会在后面章节讲解。5.3.2 聚合函数

通过前面的学习可知,在对数据进行分组统计时,经常需要结合MySQL提供的聚合函数才能够统计出具有价值的数据。

例如,获取每种商品分类下的商品数量、最高价格的商品、最低价格的商品等。

为此,MySQL中的聚合函数就可在查询数据时提供一些特殊的功能。

COUNT()、SUM()、AVG()、MAX()、MIN()和GROUP_CONCAT()函数中可以在参数前添加DISTINCT,表示对不重复的记录进行相关操作。COUNT()的参数设置为“*”时,表示统计符合条件的所有记录(包含NULL)。

单独使用聚合函数统计数据

mysql> SELECT MAX(price), MIN(price) FROM sh_goods;

+------------+------------+

| MIN(price) | MAX(price) |

+------------+------------+

| 5999.00 | 0.50 |

+------------+------------+

1 row in set (0.00 sec)

聚合函数与分组结合使用统计数据

mysql> SELECT category_id, MAX(price), MIN(price)

-> FROM sh_goods GROUP BY category_id HAVING COUNT(*) > 2;

+-------------+------------+------------+

| category_id | MAX(price) | MIN(price) |

+-------------+------------+------------+

| 3 | 15.00 | 0.50 |

+-------------+------------+------------+

1 row in set (0.00 sec)

MySQL5.7.22中新增函数JSONARRAYAGG()和JSONOBJECTAGG()

5.4 运算符5.4.1 算术运算符

算术运算符适用于数值类型的数据,通常应用在SELECT查询结果的字段中使用,在WHERE条件表达式中应用较少。

运算符两端的数据可以是真实的数据(如5),或数据表中的字段(如price)。参与运算的数据一般称之为操作数,操作数与运算符组合在一起统称为表达式(如5+2)。在MySQL中可以直接利用SELECT查看数据的运算结果。

注意事项:

运算符+、-和*的操作数都是无符号整型,则运算结果也是无符号整型。

mysql> SELECT id, id+1, id-1, id*2 FROM sh_goods LIMIT 5;

+----+------+------+------+

| id | id+1 | id-1 | id*2 |

+----+------+------+------+

| 1 | 2 | 0 | 2 |

| 2 | 3 | 1 | 4 |

| 3 | 4 | 2 | 6 |

| 4 | 5 | 3 | 8 |

| 5 | 6 | 4 | 10 |

+----+------+------+------+

5 rows in set (0.00 sec)

提出问题:默认运算符-的操作数若都为无符号整型,则结果一定是无符号的整型,若操作数的差值为负数,那么系统就会报错。

解决办法:使用CAST(... AS SIGNED)将无符号数据强制转换为有符号的数据。

默认无符号整型的减法运算

mysql> SELECT id-3 FROM sh_goods LIMIT 5;

ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(`shop`.`sh_goods`.`id` - 3)'

有负数所以报错了,解决办法:

有符号的减法运算结果:

mysql> SELECT CAST(id AS SIGNED)-3 FROM sh_goods LIMIT 5;

+----------------------+

| CAST(id AS sIGNED)-3 |

+----------------------+

| -2 |

| -1 |

| 0 |

| 1 |

| 2 |

+----------------------+

5 rows in set (0.00 sec)

浮点数运算精度浮点数进行加减运算时,运算结果中的精度(小数点后的位数)等于参与运算的操作数的最大精度。 例如1.2+1.400,1.400的精度最大为3,则运算结果的精度就为3。对浮点数进行乘法运算时,运算结果中的精度,以参与运算的操作数的精度和为准。 例如1.2*1.400,1.2的精度为1,1.400的精度为3,则运算结果中的精度就为4。

mysql> SELECT name, price, stock, price*0.75, stock+850.00

-> FROM sh_goods WHERE score = 5;

+----------+---------+-------+------------+--------------+

| name | price | stock | price*0.75 | stock+850.00 |

+----------+---------+-------+------------+--------------+

| | 1.00 | 500 | 0.7500 | 1350.00 |

| | 1999.00 | 0 | 1499.2500 | 850.00 |

+----------+---------+-------+------------+--------------+

2 rows in set (0.00 sec)

运算符 / 在MySQL中用于除法操作,且运算结果使用浮点数表示。

浮点数的精度等于被除数的精度加上系统变量divprecisionincrement设置的除法精度增长值(默认值为4)。

mysql> SHOW VARIABLES LIKE 'div_precision_increment';

+-------------------------+-------+

| Variable_name | Value |

+-------------------------+-------+

| div_precision_increment | 4 |

+-------------------------+-------+

1 row in set, 1 warning (0.00 sec)

除法运算中除数如果为0,则系统显示的执行结果为NULL。

在算术运算中,NULL是一个特殊的值,它参与的算术运算结果均为NULL。

mysql> SELECT NULL+1, 3-NULL, 7*NULL, 2/NULL, NULL/3;

+--------+--------+--------+--------+--------+

| NULL+1 | 3-NULL | 7*NULL | 2/NULL | NULL/3 |

+--------+--------+--------+--------+--------+

| NULL | NULL | NULL | NULL | NULL |

+--------+--------+--------+--------+--------+

1 row in set (0.00 sec)

在MySQL中,运算符DIV与 / 都能实现除法运算,区别在于前者的除法运算结果会去掉小数部分,只返回整数部分。

mysql> SELECT 8/5, 8 DIV 5, 0.6/1.2, 0.6 DIV 1.2;

+--------+---------+---------+-------------+

| 8/5 | 8 DIV 5 | 0.6/1.2 | 0.6 DIV 1.2 |

+--------+---------+---------+-------------+

| 1.6000 | 1 | 0.50000 | 0 |

+--------+---------+---------+-------------+

1 row in set (0.00 sec)

MySQL中的运算符MOD与%功能相同,都用于取模运算。

mysql> SELECT 8 MOD 5, -8 MOD 5, 8 MOD -5, -8 MOD -5;

+---------+----------+----------+-----------+

| 8 MOD 5 | -8 MOD 5 | 8 MOD -5 | -8 MOD -5 |

+---------+----------+----------+-----------+

| 3 | -3 | 3 | -3 |

+---------+----------+----------+-----------+

1 row in set (0.00 sec)

关于算术运算,除了算术运算符外,MySQL还提供了很多进行数学运算的函数。

RAND()函数用于返回0到1之间的随机数。

若要获取指定区间(min≤num<max)内的随机数时,使用表达式FLOOR(min+ RAND() * (max − min))获取。

例如:获取大于等于1且小于10的任意一个随机整数

mysql> SELECT FLOOR(1+RAND()*(10-1));

+------------------------+

| FLOOR(1+RAND()*(10-1)) |

+------------------------+

| 7 |

+------------------------+

1 row in set (0.00 sec)

若要获取相同的随机数,可为RAND()函数添加整数参数:

mysql> SELECT RAND(4);

+---------------------+

| RAND(4) |

+---------------------+

| 0.15595286540310166 |

+---------------------+

1 row in set (0.00 sec)

mysql> SELECT RAND();

+--------------------+

| RAND() |

+--------------------+

| 0.9753922950247231 |

+--------------------+

1 row in set (0.00 sec)

mysql> SELECT RAND(4);

+---------------------+

| RAND(4) |

+---------------------+

| 0.15595286540310166 |

+---------------------+

1 row in set (0.00 sec

随机获取某一商品分类下的所有商品id

mysql> SELECT category_id, GROUP_CONCAT(id) FROM sh_goods

-> GROUP BY category_id ORDER BY RAND() LIMIT 1;

+-------------+------------------+

| category_id | GROUP_CONCAT(id) |

+-------------+------------------+

| 3 | 1,2,3 |

+-------------+------------------+

1 row in set (0.00 sec)

5.4.2 比较运算符

比较运算符是MySQL常用运算符之一,通常应用在条件表达式中对结果进行限定。

MySQL中比较运算符的结果值有3种:

1 (TRUE,表示为真)0 (FALSE,表示为假)NULL

比较运算符需要注意如下几个问题:

所有比较运算符都可以对数字和字符串进行比较,若参与比较的操作数的数据类型不同,则MySQL会自动将其转换为同类型的数据后再进行比较。

mysql> SELECT 5>='5', 3.0<>3;

+--------+--------+

| 5>='5' | 3.0<>3 |

+--------+--------+

| 1 | 0 |

+--------+--------+

1 row in set (0.00 sec)

比较运算符=、>、<、>=、<=、<>、!=在与NULL进行比较时,结果均为NULL。

mysql> SELECT 0 = NULL, NULL<1, NULL<>2;

+----------+--------+---------+

| 0 = NULL | NULL<1 | NULL<>2 |

+----------+--------+---------+

| NULL | NULL | NULL |

+----------+--------+---------+

1 row in set (0.00 sec)

运算符=与<=>均可以用于比较数据是否相等,两者的区别在于后者可以对NULL值进行比较。

mysql> SELECT NULL=NULL, NULL=1, NULL <=> NULL, NULL<=>1;

+-----------+--------+---------------+----------+

| NULL=NULL | NULL=1 | NULL <=> NULL | NULL<=>1 |

+-----------+--------+---------------+----------+

| NULL | NULL | 1 | 0 |

+-----------+--------+---------------+----------+

1 row in set (0.00 sec)

在条件表达式中对指定区间的数据进行判断时,可使用BETWEEN…AND…实现。

BETWEEN 条件1 AND 条件2

BETWEEN…AND:用于表示条件1到条件2之间的范围(包含条件1和条件2)。条件1和条件2在设置时,条件1必须小于等于条件2。

举例:

获取价格在2000到6000的商品:

NOT BETWEEN…AND…表示不在指定范围内,与BETWEEN…AND使用方式相同。

获取价格不在2000到6000的商品:

IS NULL或IS NOT NULL用于在条件表达式中判断字段是否为NULL。

LIKE运算符在前面学习查看数据表时已讲解,它的作用就是模糊匹配,NOT LIKE的使用方式与之相同,用于获取匹配不到的数据

匹配模式符“%”可以匹配任意0到多个字符,因此执行结果为4条记录;

若将其修改为“_”表示匹配任意1个字符,上述示例的执行结果就为空,没有符合要求的记录。

在使用时需根据实际的需求具体的选择使用哪种匹配模式符。

正则匹配查询

查询数据时可利用REGEXP关键字指定正则匹配模式轻松完成更为复杂的查询。

正则表达式的语法与其他编程语言相同,读者可自行查看相关的资料进行学习。

符号“|”在正则中表示分隔符,用于分割多种条件,在匹配时只要指定字段满足分隔符左右两边条件中的一个,就表示匹配成功。

关于比较运算,除了比较运算符外,MySQL还提供了很多进行比较运算的函数。

函数GREATEST()和LEAST()的参数至少有两个,用于比较后返回一个最大或最小的参数值。IN()只要比较的字段或数据在给定的集合内,那么比较结果就为真,NOT IN()正好与IN()的功能相反。

获取categoryid为3或15的商品:

![在这里插入图片描述]()

5.4.3 逻辑运算符

逻辑运算符也是MySQL常用运算符之一,通常应用在条件表达式中的逻辑判断,与比较运算符结合使用。参与逻辑运算的操作数以及逻辑判断的结果只有3种,分别为:

1 (TRUE,表示为真)0 (FALSE,表示为假)NULL。

仅有逻辑非(NOT或!)是一元运算符,其余均为二元运算符。

NOT和“!” 虽然功能相同,但是在一个表达式中同时出现时,先运算“!”,再运算“NOT”。

逻辑与:只有操作数全部为真时,运算的结果才为真。

在开发时,若使用“&&”连接多个相等比较的条件时,可以使用(a,b)=(x,y)的方式简化条件表达式(a=x && b=y)的书写。

SELECT id, name, price FROM sh_goods

WHERE (keyword, score) = ('电子产品', 5);

在进行逻辑与操作时,若操作数中含有NULL,而另一个操作数若为1(真),则结果为NULL,若另一个操作数为0(假),则结果为0。

mysql> SELECT 1&&NULL, NULL&&1, 0&&NULL, NULL&&0;

+---------+---------+---------+---------+

| 1&&NULL | NULL&&1 | 0&&NULL | NULL&&0 |

+---------+---------+---------+---------+

| NULL | NULL | 0 | 0 |

+---------+---------+---------+---------+

1 row in set (0.00 sec)

逻辑或:只要操作数有一个为真,则运算的结果就为真。

在进行逻辑或操作时,若操作数中含有NULL,而另一个操作数若为1(真),则结果为1;若另一个操作数为0(假),则结果为NULL。

mysql> SELECT 1||NULL, NULL||1, 0||NULL, NULL||0;

+---------+---------+---------+---------+

| 1||NULL | NULL||1 | 0||NULL | NULL||0 |

+---------+---------+---------+---------+

| 1 | 1 | NULL | NULL |

+---------+---------+---------+---------+

1 row in set (0.00 sec)

逻辑非的操作数仅有一个,当操作数为0(假)时,则运算结果为1;当操作数为1(真)时,则运算结果为0;当操作数为NULL时,运算结果为NULL。

mysql> SELECT NOT 10, NOT 0, NOT NULL, NOT 0 + !0, !0 + !0;

+--------+-------+----------+------------+---------+

| NOT 10 | NOT 0 | NOT NULL | NOT 0 + !0 | !0 + !0 |

+--------+-------+----------+------------+---------+

| 0 | 1 | NULL | 0 | 2 |

+--------+-------+----------+------------+---------+

1 row in set (0.00 sec)

逻辑异或操作,表示两个操作数同时都为1或0,则结果为0;若两个操作数一个为

1,一个为0,则结果为1;当操作数为NULL时,则结果为NULL。

mysql> SELECT 1 XOR 2, 0 XOR 0, 0 XOR 2, NULL XOR 2;

+---------+---------+---------+------------+

| 1 XOR 2 | 0 XOR 0 | 0 XOR 2 | NULL XOR 2 |

+---------+---------+---------+------------+

| 0 | 0 | 1 | NULL |

+---------+---------+---------+------------+

1 row in set (0.00 sec)

5.4.4 赋值运算符

MySQL中“=”是一个比较特殊的运算符,既可以用于比较数据是否相等,又可以表示赋值。因此,MySQL为了避免系统分不清楚运算符“=”表示赋值还是比较的含义,特意增加一个符号“:=”用于表示赋值运算。

“=”作为比较运算符时使用:

# “=”作为比较运算符和赋值运算符使用

UPDATE sh_goods SET stock = 1000 WHERE score = 4.5;

# “=”作为比较运算符使用,“:=”作为赋值运算符使用

UPDATE sh_goods SET stock := 1000 WHERE score = 4.5;

“stock = 1000”和“stock:=1000”中的“=”和“:=”都表示赋值运算符。“score = 4.5”中的“=”表示比较运算符。

在MySQL中,INSERT...SET和UPDATE…SET中出现的运算符“=”都会被认为是赋值运算符。

因此,建议除此之外的其他情况,若需要赋值运算符,推荐使用“:=” ,如为变量赋值。

5.4.5 位运算符

位运算符是针对二进制数的每一位进行运算的符号,运算的结果类型为BIGINT,最大范围可以是64位。

MySQL5.7中参与位运算的数据只能是BIGINT类型(64位的整数),而在MySQL8.0中则允许二进制字符串类型的参数,如BINARY、VARBINARY和BLOB。

因此,MySQL5.7中二进制类型字段的位运算可能在MySQL8.0中产生不同结果,系统也会报相关的警告提示信息。

演示VARBINARY类型的数据位运算

# ① 创建数据表,含有VARBINARY类型的字段

mysql> CREATE TABLE mydb.mybin (b1 VARBINARY(20), b2 VARBINARY(20));

Query OK, 0 rows affected (0.01 sec)

# ② 插入数据

mysql> INSERT INTO mydb.mybin VALUES (2, 6), (3, 1), (4, 9);

Query OK, 3 rows affected (0.00 sec)

Records: 3 Duplicates: 0 Warnings: 0

# ③ 查看数据表中两个字段的按位与、按位或结果

mysql> SELECT b1&b2, b1|b2 FROM mydb.mybin;

+-------+-------+

| b1&b2 | b1|b2 |

+-------+-------+

| 2 | 6 |

| 1 | 3 |

| 0 | 13 |

+-------+-------+

3 rows in set, 2 warnings (0.00 sec)

查看警告信息

mysql> SHOW WARNINGS\G

*************************** 1. row ***************************

Level: Warning

Code: 1287

Message: Bitwise operations on BINARY will change behavior in a future version, check the 'Bit functions' section in the manual.

*************************** 2. row ***************************

Level: Warning

Code: 1287

Message: Bitwise operations on BINARY will change behavior in a future version, check the 'Bit functions' section in the manual.

2 rows in set (0.00 sec)

解决位运算的警告问题

mysql> SELECT

-> CAST(b1 AS UNSIGNED) & CAST(b2 AS UNSIGNED) AS one,

-> CAST(b1 AS UNSIGNED) | CAST(b2 AS UNSIGNED) AS two

-> FROM mydb.mybin;

+-----+-----+

| one | two |

+-----+-----+

| 2 | 6 |

| 1 | 3 |

| 0 | 13 |

+-----+-----+

3 rows in set (0.00 sec)

关于位运算,除了位运算符外,MySQL还提供了很多进行位运算的函数。

5.4.6 运算符优先级

运算符优先级可以理解为运算符在一个表达式中参与运算的先后顺序,优先级别越高,则越早参与运算;优先级别越低,则越晚参与运算。

同行的运算符具有相同的优先级,除赋值运算符从右到左运算外,其余相同级别的运算符,在同一个表达式中出现时,运算的顺序为从左到右依次进行。

若要提升运算符的优先级别,可以使用圆括号“()”,当表达式中同时出现多个圆括号时,最内层的圆括号中的表达式优先级最高。

mysql> SELECT 2+3*5, (2+3)*5;

+-------+---------+

| 2+3*5 | (2+3)*5 |

+-------+---------+

| 17 | 25 |

+-------+---------+

1 row in set (0.00 sec)

“2+3*5”先按运算符的优先级计算乘法,然后再计算加法,因此结果为17。“(2+3)*5”则先计算圆括号内的加法,然后再计算乘法,因此结果为25。5.5 总结

本节主要讲了单表的数据操作、排序、分组和聚合等操作,并讲了常见的运算符的用法。

5.6 每日分享

生而为人,要时刻怀揣一颗善良感恩的心,莫以恶小而为之,莫以善小而不为。

标签: #mysql除法