在MySQL 8.0.34中,操作符用于处理数据和执行操作。其中包括算术、比较、逻辑、赋值和位操作符。掌握这些操作符对于编写有效的SQL查询和理解数据库行为非常重要。无论是进行数据分析,还是创建复杂的数据库查询,理解和使用这些操作符都是必不可少的技能。
一、算术操作符
加法
SELECT 工资+奖金 AS 总收入 FROM 员工表;
减法
SELECT 工资-50000 AS 工资差 FROM 员工表;
除法
SELECT 奖金/12 AS 月均奖金 FROM 员工表;
取余
SELECT 工资%1000 AS 余数 FROM 员工表;
二、比较运算符
等于
SELECT * FROM 员工表 WHERE 工资 = 50000;
不等于
SELECT * FROM 员工表 WHERE 工资 <> 50000;
或者
SELECT * FROM 员工表 WHERE 工资 != 50000;
小于
SELECT * FROM 员工表 WHERE 工资 < 50000;
大于
SELECT * FROM 员工表 WHERE 工资 > 50000;
小于或等于
SELECT * FROM 员工表 WHERE 工资 <= 50000;
大于或等于
SELECT * FROM 员工表 WHERE 工资 >= 50000;
LIKE(模糊匹配)
用于在WHERE
子句中搜索模式
-- %:匹配任何数量的字符,包括零个字符。
-- 查询会返回所有名字以"J"开头的员工
SELECT * FROM employees WHERE name LIKE 'J%';
-- _:匹配单个字符
-- 查询所有第二个字符为"A"的员工
SELECT * FROM employees WHERE name LIKE '_A%';
BETWEEN
(范围)
用于选择在两个值之间的记录
-- 查询会返回所有年龄在30到40岁之间的员工(是包含边界值的)
SELECT * FROM employees WHERE age BETWEEN 30 AND 40;
--查询会返回所有年龄在30到40岁之间的员工 (不包含边界值)
SELECT * FROM employees WHERE age > 30 AND age < 40
此外还可以在组合使用NOT BETWEEN
,以选择不在特定范围内的值。例如:
-- 查询会返回所有年龄不在30到40之间的员工
SELECT * FROM employees WHERE age NOT BETWEEN 30 AND 40;
IN
(列表)
用于在WHERE
子句中匹配多个值
-- 查询会返回所有名字不是'John','Jane'或'Jennifer'的员工
SELECT * FROM employees WHERE name NOT IN ('John', 'Jane', 'Jennifer');
IS NULL (为空)
IS NULL
和IS NOT NULL
操作符被用来检查一个字段是否有值(IS NOT NULL
)或者没有值(IS NULL
)。这是因为在SQL中,NULL表示一个字段没有值,而不是值为0或空字符串
-- 查询会返回所有email字段为空的员工
SELECT * FROM employees WHERE email IS NULL;
-- 查询会返回所有email字段不为空的员工
SELECT * FROM employees WHERE email IS NOT NULL;
注意:
在使用IS NULL
和IS NOT NULL
时,有一些需要注意的点:
-
不要使用
=
或<>
来比较NULL值。在SQL中,NULL表示"未知",所以任何值与NULL的比较结果都是未知,即不是真也不是假。即使运行成功,永远是查询不到结果的。 -
在设计数据库表时,应该尽量避免NULL值。虽然NULL值在某些情况下是有用的,但它们也会使查询变得更复杂,并可能导致意外的结果。
-
如果你的查询需要处理NULL值,记得使用
IS NULL
或IS NOT NULL
,并确保你的应用程序能够正确处理这些值。
三、逻辑运行符
and
SELECT * FROM 员工表 WHERE 工资 > 50000 AND 职位 = '经理';
or
SELECT * FROM 员工表 WHERE 工资 > 50000 OR 职位 = '经理';
not
SELECT * FROM 员工表 WHERE NOT 职位 = '经理';
and 和 OR的组合
SELECT * FROM 员工表 WHERE 工资 > 50000 AND (职位 = '经理' OR 职位 = '副总裁');
四、位操作符(可理解)
0 (十进制):
0 / 2 = 0,余数 0
0 (十进制) = 0000 (二进制)
1 (十进制):
1 / 2 = 0,余数 1
1 (十进制) = 0001 (二进制)
2 (十进制):
2 / 2 = 1,余数 0
1 / 2 = 0,余数 1
2 (十进制) = 0010 (二进制)
3 (十进制):
3 / 2 = 1,余数 1
1 / 2 = 0,余数 1
3 (十进制) = 0011 (二进制)
4 (十进制):
4 / 2 = 2,余数 0
2 / 2 = 1,余数 0
1 / 2 = 0,余数 1
4 (十进制) = 0100 (二进制)
5 (十进制):
5 / 2 = 2,余数 1
2 / 2 = 1,余数 0
1 / 2 = 0,余数 1
5 (十进制) = 0101 (二进制)
6 (十进制):
6 / 2 = 3,余数 0
3 / 2 = 1,余数 1
1 / 2 = 0,余数 1
6 (十进制) = 0110 (二进制)
7 (十进制):
7 / 2 = 3,余数 1
3 / 2 = 1,余数 1
1 / 2 = 0,余数 1
7 (十进制) = 0111 (二进制)
8 (十进制):
8 / 2 = 4,余数 0
4 / 2 = 2,余数 0
2 / 2 = 1,余数 0
1 / 2 = 0,余数 1
8 (十进制) = 1000 (二进制)
9 (十进制):
9 / 2 = 4,余数 1
4 / 2 = 2,余数 0
2 / 2 = 1,余数 0
1 / 2 = 0,余数 1
9 (十进制) = 1001 (二进制)
10 (十进制):
10 / 2 = 5,余数 0
5 / 2 = 2,余数 1
2 / 2 = 1,余数 0
1 / 2 = 0,余数 1
10 (十进制) = 1010 (二进制)
按位与(&)
返回两个二进制值的按位“AND”结果
SELECT 10 & 7;
返回2
表达式:
1010 (10的二进制表示)
& 0111 (7的二进制表示)
------
0010 (按位与操作的结果)
从上到下,每一列的二进制位都进行了比较。只有当两个位都是1时,结果的那一位才是1。所以,结果是0010,这是2的二进制表示。因此,10和7的按位与结果是2。
按位或(|)
返回两个二进制值的按位“OR”结果
SELECT 10 | 7;
返回15
表达式:
1010 (10的二进制表示)
| 0111 (7的二进制表示)
------
1111 (按位或操作的结果)
从上到下,每一列的二进制位都进行了比较。只有任何一个位是1,那么结果的那一位就是1。所以,对于 10 | 7,计算过程应该是。十进制中代表是15
按位异或(^)
返回两个二进制值的按位“XOR”结果
SELECT 10 ^ 7;
返回13
表达式:
1010 (10的二进制表示)
^ 0111 (7的二进制表示)
------
1101 (按位异或操作的结果)
从上到下,每一列的二进制位都进行了比较。按位异或操作的特性是,如果两个位不同(一个是0,一个是1),那么结果的那一位就是1。如果两个位相同(都是0或都是1),那么结果的那一位就是0。
按位非(~)
返回二进制值的按位“NOT”结果
SELECT ~7;
返回-8
表达式:
~ 0111
------
1000
从上到下,每一列的二进制位都进行了比较。将二进制数的每一位进行反转,即将0变为1,将1变为0。
左移(<<)
将二进制值向左移动特定的位数。
SELECT 2 << 1;
返回4
表达式(需要知道2在二进制中的表示是10。然后,将这个二进制数向左移动1位):
2(10) << 1
------------------
4(100)
<< 是一个位移操作符,表示左移。它的作用是将一个数的二进制表示向左移动指定的位数,右边空出来的位用0填充
右移(>>)
将二进制值向右移动特定的位数。
SELECT 2 >> 1;
返回1
表达式(需要知道2在二进制中的表示是10。然后,将这个二进制数向右移动1位):
2(10) >> 1
------------------
1(1)
>> 是一个位移操作符,表示右移。它的作用是将一个数的二进制表示向右移动指定的位数,左边空出来的位用0填充。
五、赋值运输符
:=
:=
用于将一个值赋给一个变量。这个操作符常用在SET语句、SELECT语句或DO语句中。
SET语句
这种赋值方式在存储过程、函数、触发器或事件中非常有用,因为你可以在其中创建和使用变量,以便存储和操作数据。
-- 这个语句的含义是将数值 5 赋给变量 @my_var
SET @my_var = 5; 和 SET @my_var := 5; 在功能上是一样的,一般为了严谨都采用后者
两者都可以用来赋值。但是在 SELECT 或其他某些语句中,只有 := 可以用来赋值,而 = 可能会被解析为比较操作符。例如,SELECT @my_var := 5; 是有效的,但 SELECT @my_var = 5; 实际上是在比较 @my_var 和 5 是否相等。
select语句
这两个语句的主要区别在于第一个语句将结果保存在了一个变量 @my_var 中,而第二个语句则直接返回了结果。
SELECT @my_var:= COUNT(*) FROM saas_enterprise;
SELECT @my_var;
这个语句的作用是计算 saas_enterprise 表中的行数,然后将这个结果赋值给变量 @my_var。这个语句执行完后,你可以通过 SELECT @my_var; 来查看这个变量的值,它会返回 saas_enterprise 表的行数。
SELECT COUNT(*) FROM saas_enterprise;
这个语句的作用是计算 saas_enterprise 表中的行数,并直接返回这个数值。执行这个语句后,你会得到一个结果集,其中包含一个数字,这个数字就是 saas_enterprise 表的行数。
换个角度理解思考如:
下面是一些使用 @my_var 的例子:
在WHERE子句中使用:
假设你想找出 orders 表中订单数量超过 saas_enterprise 表行数的所有企业。你可以这样写:
SELECT * FROM orders
WHERE order_count > @my_var;
在这个例子中,@my_var 是之前查询得到的 saas_enterprise 表的行数。
在LIMIT子句中使用:
假设你想根据 saas_enterprise 表的行数来限制查询的结果数量。你可以这样写:
SELECT * FROM orders LIMIT @my_var;
在这个例子中,@my_var 决定了返回结果的最大数量。
在INSERT语句中使用:
假设你想在 statistics 表中插入一个新的记录,记录 saas_enterprise 表的行数。你可以这样写:
INSERT INTO statistics (table_name, row_count)
VALUES ('saas_enterprise', @my_var);
在这个例子中,@my_var 是插入到新记录的一部分。
这些都是 @my_var 可以在其他查询中使用的例子。请注意,这个变量的值只在当前会话中有效,如果你关闭并重新打开数据库连接,这个变量的值就会被清空。
实际运用如下:
-- 设置 @my_var 变量的值为 saas_enterprise 表的行数
SET @my_var = (SELECT COUNT(*) FROM saas_enterprise);
-- 创建一个 SQL 语句的字符串,这个字符串包含了 LIMIT 子句,其中的限制数量是 @my_var 变量的值
-- CONCAT 函数用来拼接字符串
SET @sql = CONCAT('SELECT * FROM saas_enterprise_permission LIMIT ', @my_var);
-- 从 @sql 变量的值(即我们刚刚创建的 SQL 语句字符串)创建一个预处理语句
-- 预处理语句允许我们动态地构建和执行 SQL 语句
PREPARE stmt FROM @sql;
-- 执行我们刚刚创建的预处理语句
EXECUTE stmt;
-- 释放我们刚刚创建的预处理语句
-- 它释放服务器上的资源
DEALLOCATE PREPARE stmt;
等同于
SELECT * FROM saas_enterprise_permission
LIMIT (SELECT COUNT(*) FROM saas_enterprise);
DO语句
DO
是MySQL中的一个命令,它用于执行一个表达式但不返回结果。在例子中,@my_var := 5
是一个表达式,它将值5赋给变量@my_var
。DO
命令执行这个表达式,但不返回任何结果。
DO @my_var := 5;
这个命令将5赋给@my_var,但不返回任何结果。如果你想看到@my_var的值,你需要执行一个SELECT命令,如下所示:
SELECT @my_var;
六、集合操作符
UNION
用于合并多个查询结果集,并去除重复的行
-- 从user_init和user_result结果合并,并去除重复的行
SELECT * FROM user_init
UNION
SELECT * FROM user_result
注意事项:
- UNION 操作符要求两个查询的列数和数据类型必须相同。
- UNION 默认会对结果集进行排序,如果需要保持原始顺序,可以使用 UNION ALL。
UNION ALL
合并多个查询结果集,保留所有行,包括重复的行
-- 从user_init和user_result结果合并,保留所有行,包括重复的行。
SELECT * FROM user_init
UNION ALL
SELECT * FROM user_result
注意事项:
- UNION ALL 不会去重结果集中的行,因此执行速度可能比 UNION 更快。
- UNION ALL 不要求两个查询的列数和数据类型相同。
EXISTS
一种条件操作符,用于检查子查询是否返回任何行,并根据结果来决定是否选择父查询中的行。EXISTS
子句用于检查子查询的结果集是否为空。如果子查询返回至少一行结果,EXISTS
条件就会被认为是真的,否则为假的。它通常与 SELECT
语句的 WHERE
子句一起使用,用于过滤查询结果。
-- 查询将返回只是有一个订单的客户
SELECT * FROM user_init
WHERE EXISTS (
SELECT * FROM user_result
WHERE user_result.id = user_init.id
);
七、其他操作符
REGEXP
(正则表达式匹配)
用于在WHERE
子句中进行更复杂的模式匹配(可理解为LIKE的升级查询),等价于RLIKE
-- 查询会返回所有名字中包含一个或多个数字的员工
SELECT * FROM employees WHERE name REGEXP '[0-9]';
常用的正则(远不如此)如下:
.:匹配任何单个字符(除了换行符)。在 MySQL 中,你可以使用它来匹配任何字符,例如:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP '.';
*:匹配前面的元素零次或多次。在 MySQL 中,你需要使用 .* 来匹配任何数量的任何字符,例如:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP 'a.*';
+:匹配前面的元素一次或多次。在 MySQL 中,你需要使用 .+ 来匹配至少一个任何字符,例如:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP 'a.+';
?:匹配前面的元素零次或一次。在 MySQL 中,你可以使用它来匹配一个可选的字符,例如:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP 'a?';
^:匹配输入或行的开始。在 MySQL 中,你可以使用它来匹配以某个字符开始的字符串,例如:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP '^a';
$:匹配输入或行的结束。在 MySQL 中,你可以使用它来匹配以某个字符结束的字符串,例如:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP 'a$';
\d:在 MySQL 中,需要使用 [0-9] 来匹配任何数字,或者使用 REGEXP_LIKE 函数并开启 c 模式来使用 \d,例如:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP '[0-9]';
SELECT * FROM saas_enterprise WHERE REGEXP_LIKE(enterprise_name, '\\d', 'c');
另外
在 MySQL 中,\D、\w、\W、\s、\S 这些元字符可能不会被识别,你需要使用相应的字符类来替代它们。例如:
\D:匹配任何非数字字符。在 MySQL 中,你可以使用 [^0-9] 来替代 \D。:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP '[^0-9]';
\w:匹配任何字母、数字或下划线。在 MySQL 中,你可以使用 [a-zA-Z0-9_] 来替代 \w:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP '[a-zA-Z0-9_]';
\W:匹配任何非字母、非数字和非下划线的字符。在 MySQL 中,你可以使用 [^a-zA-Z0-9_] 来替代 \W:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP '[^a-zA-Z0-9_]';
\s 和 \S:在 MySQL 中,你需要使用空格或者其他特定的字符类来匹配空白字符或非空白字符。例如:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP ' '; -- 匹配包含空格的记录
SELECT * FROM saas_enterprise WHERE enterprise_name NOT REGEXP ' '; -- 匹配不包含空格的记录
对于方括号 [],使用它们来匹配一个字符集。例如:[abc]:匹配任何一个在方括号内的字符:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP '[abc]';
[^abc]:匹配任何一个不在方括号内的字符:
SELECT * FROM saas_enterprise WHERE enterprise_name REGEXP '[^abc]';