MySQL - DML语句

基础

DML 就是增删改查(crud)

  • 数据操作语言(DML):用于对数据库中的数据进行增、删、改、查等操作。
    • 插入数据:INSERT INTO
    • 删除数据:DELETE FROM
    • 更新数据:UPDATE
    • 查询数据:SELECT

NULL

NULL 有两种,“未知”unknown 和“inapplicable”不适用。

  • 不知道戴眼镜的人眼睛是什么颜色,就是未知。只要不摘掉眼睛,就不知道,但是这个人眼睛肯定有颜色的。
  • 不知道冰箱的眼睛是什么颜色。这就是不适用,这个属性不适用于冰箱。冰箱是没有眼睛的。
  • 现在 DBMS 都将这两种类型 NULL 归为了一类,并采用三值逻辑

SQL的保留字中,很多都被归类为谓词一类,例如>,<>,= 等比较谓词,以及 BETWEEN, LIKE, IN, IS NULL 等。

NULL 不是值,所以不能对其使用谓词,如果使用谓词,结果是 unknown。
可以认为它只是一个没有值的标记,而比较谓词只适用于比较值。因此对非值的 NULL 使用比较谓词是没有意义的

使用 IS NULL, 而不是"= NULL"?

应该注意到,NULL 与 0、空字符串都不同。

添加 insert

普通插入

insert into 表名(字段名1,字段名2) values(字段1,字段2)
insert into 表名 values(字段1,字段2)
insert into 表名 values(字段1,字段2),(字段1,字段2),(字段1,字段2)

INSERT INTO employee VALUES(02,'Jack',119119119);  #按字段顺序插入

--一次添加多个,course表一个id字段,name字段
insert into course values(1,'语文'),(2,'数学'),(3,'英语');

插入检索出来的数据

INSERT INTO mytable1(col1, col2)
SELECT col1, col2
FROM mytable2;

将一个表的内容插入到一个新表

CREATE TABLE newtable AS
SELECT * FROM mytable;

删除 delete


#删除一行记录
delete from tb名 where 条件 

#DDL语言
#drop可以删除数据库和表
drop database db名
drop table tb名 #删除表
truncate table 表名 #清空表,仅删除所有字段

修改 update

--  修改表中某个值
UPDATE 表名字 SET1=1,2=2 WHERE 条件;


值是字符串需要用引号括起来

函数

各个 DBMS 的函数都是不相同的,因此不可移植,以下主要是 MySQL 的函数。

计算
函数名:COUNTSUMAVGMAXMIN
作用:计数求和求平均值最大值最小值

其中 COUNT 函数可用于任何数据类型(因为它只是计数),而 SUM 、AVG 函数都只能对数字类数据类型做计算,MAX 和 MIN 可用于数值、字符串或是日期时间数据类型。

SELECT MAX(salary) AS max_salary,MIN(salary) FROM employee;

AVG() 会忽略 NULL 行。

使用 DISTINCT 可以汇总不同的值。

SELECT AVG(DISTINCT col1) AS avg_col
FROM mytable;
文本处理
函数说明
LEFT()左边的字符
RIGHT()右边的字符
LOWER()转换为小写字符
UPPER()转换为大写字符
LTRIM()去除左边的空格
RTRIM()去除右边的空格
LENGTH()长度
SOUNDEX()转换为语音值

其中, SOUNDEX() 可以将一个字符串转换为描述其语音表示的字母数字模式。

SELECT *
FROM mytable
WHERE SOUNDEX(col1) = SOUNDEX('apple')
日期和时间处理
  • 日期格式:YYYY-MM-DD
  • 时间格式:HH:<zero-width space>MM:SS
函数说明
ADDDATE()增加一个日期(天、周等)
ADDTIME()增加一个时间(时、分等)
CURDATE()返回当前日期
CURTIME()返回当前时间
DATE()返回日期时间的日期部分
DATEDIFF()计算两个日期之差
DATE_ADD()高度灵活的日期运算函数
DATE_FORMAT()返回一个格式化的日期或时间串
DAY()返回一个日期的天数部分
DAYOFWEEK()对于一个日期,返回对应的星期几
HOUR()返回一个时间的小时部分
MINUTE()返回一个时间的分钟部分
MONTH()返回一个日期的月份部分
NOW()返回当前日期和时间
SECOND()返回一个时间的秒部分
TIME()返回一个日期时间的时间部分
YEAR()返回一个日期的年份部分
mysql> SELECT NOW();
2018-4-14 20:25:11

时间计算

  • datediff(日期 1, 日期 2)
    • 得到的结果是日期 1 与日期 2 相差的天数。
    • 如果日期 1 比日期 2 大,结果为正;如果日期 1 比日期 2 小,结果为负。
  • timestampdiff(时间类型, 日期 1, 日期 2):
    • 以日期二为标准。日期二大的话,结果为正。
    • 在“时间类型”的参数位置,通过添加“day”, “hour”, “second”等关键词,来规定计算天数差、小时数差、还是分钟数差。

数值处理

函数说明
SIN()正弦
COS()余弦
TAN()正切
ABS()绝对值
SQRT()平方根
MOD()余数
EXP()指数
PI()圆周率
RAND()随机数

排名函数

rank():按照某字段的排序结果添加排名,但它是跳跃的、间断的排名,两个并列第一名后,下一个是第三名
dense_rank():dense 英语中指“稠密的、密集的”。dense_rank()是的排序数字是连续的、不间断。当有相同的分数时,它们的排名结果是并列的,例如,1,2,2,3。
row_number():从 8.0 版开始引入了功能。这 ROW_NUMBER()是一个窗口函数或分析函数,它为从 1 开始应用的每一行分配一个序号

SELECT name , 
	score ,
	rank() over(partition by name ORDER BY score desc) as 'Rank' 
	FROM rank;
--首先,PARTITION BY子句按姓名将结果集分成多个分区。
--然后,ORDER BY子句按分数对结果集进行排序。
+------+------+---------+
| name | score|   Rank  |
+------+------+---------+
|  a   |  100 |       1 |
|  a   |  90  |       2 |
|  a   |  89  |       3 |
|  b   |  100 |       1 |
|  c   |  95  |       1 |
|  d   |  95  |       1 |
|  e   |  95  |       1 |
+------+------+---------+

select查询

常见子句

  • AS:起别名,(可以给字段起别名,也可以给表起别名)
  • DISTINCT:去重,相同值只会出现一次。它作用于所有列,也就是说所有列的值都相同才算相同。
  • ORDER BY 排序: ASC :升序(默认), DESC :降序
  • LIMIT 分页:限制返回的行数。有两个参数,limit offset,pagesize;
    • offset代表的是起始的条目索引,默认从0开始
    • size代表的是显示的条目数

distinct


--可以按多个列进行排序,并且为每个列指定不同的排序方式
-- 查询成绩表中学生所有成绩,按照课程号升序,成绩降序排列,显示前5条数据
SELECT DISTINCT col1, col2  
FROM score 
ORDER BY 课程号 ASC,成绩 DESC
LIMIT 5;


select* from table LIMIT 2,10;--检索从第3行开始,累加10条记录,共显示id为3....12

where条件查询

  • WHERE 子句类似于程序语言中的 if 条件,根据 MySQL 表中的字段值来读取指定的数据。
  • 在 WHERE 子句中,你可以使用各种条件运算符(如 =, <, >, <=, >=, !=),逻辑运算符(如 AND, OR, NOT),in
SELECT column1, column2, ...
FROM table_name
[WHERE condition]
[ORDER BY column_name [ASC | DESC]]
[LIMIT number];

WHERE 子句可用的操作符

算数运算符

>	大于
<	小于
=	等于
! =	或者< >  不等于
>=	大于等于
<=	小于等于
  • 逻辑运算符
    • and 与,同时满足多个条件
    • or 或,满足多个条件中的一个即可
    • not 否,不满足条件
  • in与not in运算符
    • in 在一个条件列表中
    • not in 不在一个条件列表中
#组合条件(AND、OR)
SELECT * FROM products WHERE category = 'Electronics' AND price > 100.00;
SELECT * FROM orders WHERE order_date >= '2023-01-01' OR total_amount > 1000.00;

--模糊匹配条件(LIKE):
SELECT * FROM customers WHERE first_name LIKE 'J%';

--BETWEEN AND 条件:
SELECT * FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31';
--IN 条件:
SELECT * FROM countries WHERE country_code IN ('US', 'CA', 'MX');

SELECT * FROM products WHERE  category ! = 'Clothing';
-- NOT 条件:
SELECT * FROM products WHERE NOT category = 'Clothing';


--IS NULL 条件
SELECT * FROM employees WHERE department IS NULL;
--IS NOT NULL 条件:
SELECT * FROM customers WHERE email IS NOT NULL;

group分组查询

GROUP BY 语句根据一个或多个列对结果集进行分组。在分组的列上通常与聚合函数一起使用:COUNT, SUM, AVG,等函数。
分组规定:

  • GROUP BY 子句出现在 WHERE 子句之后,ORDER BY 子句之前;
  • 除了汇总字段外,SELECT 语句中的每一字段都必须在 GROUP BY 子句中给出;
  • NULL 的行会单独分为一组;
  • 大多数 SQL 实现不支持 GROUP BY 列具有可变长度的数据类型。
  • WHERE 过滤行,HAVING字句 过滤分组,行过滤应当先于分组过滤。
SELECT column1, aggregate_function(column2)
FROM table_name
WHERE condition
GROUP BY column1, column2
HAVING num >= 2;
  • column1:指定分组的列。
  • aggregate_function(column2):对分组后的每个组执行的聚合函数。
  • table_name:要查询的表名。
  • condition:可选,用于筛选结果的条件。

聚合函数:聚合函数是对一组值执行计算并返回单一的值的函数,它经常与SQL语句的SELECT语句的 GROUP BY 子句一同使用。以下是一些常见的聚合函数:

  • COUNT:返回指定组中项目的数量。
  • SUM:返回指定组中的总计值,空值被忽略。
  • AVG:返回指定组中的平均值,空值被忽略。
  • MAX:返回指定组中的最大值。
  • MIN:返回指定组中的最小值。
  • FIRST:返回指定组中的第一个值。
  • LAST:返回指定组中的最后一个值。
  • GROUP_CONCAT:返回指定列中的所有值以逗号分隔的列表。
  • ARRAY_AGG:返回一个数组,其中包含指定列中的所有值。
select id, count(big_type) value,big_type name from menu

value是count(big_type)的别名,这里省略了一个as关键字

like模糊匹配

LIKE是一个用于模糊匹配的运算符。它可以与通配符一起使用,以便在查询时匹配特定模式的数据。
LIKE运算符对大小写是敏感的。如果需要进行大小写不敏感的匹配,可以使用数据库特定的函数或操作符来实现。
not like

通配符也是用在过滤语句中,但它只能用于文本字段。不要滥用通配符,通配符位于开头处匹配会非常慢。

  • % 匹配 >=0 个任意字符;
  • _ 匹配 ==1 个任意字符;
  • [ ] :可以匹配集合内的字符,例如 [ab] 将匹配字符 a 或者 b。用脱字符 ^ 可以对其进行否定,也就是不匹配集合内的字符。
--匹配以特定字符串开头的数据
SELECT * FROM table_name WHERE column_name LIKE 'prefix%';
--匹配以特定字符串结尾的数据
SELECT * FROM table_name WHERE column_name LIKE '%suffix';
--匹配包含特定字符串的数据
SELECT * FROM table_name WHERE column_name LIKE '%substring%';
-- 匹配长度为特定值的数据:
SELECT * FROM table_name WHERE column_name LIKE '___';

SELECT * FROM mytable WHERE col LIKE '[^AB]%'; -- 不以 A 和 B 开头的任意文本
select employee_id,
if(employee_id%2=1 and name not like 'M%',salary,0) as bonus
--if(mod(employee_id,2)=1 and name not like 'M%',salary,0) as bonus
from Employees
order by employee_id;

IF 表达式

IF( expr1 , expr2 , expr3 )
expr1 的值为 TRUE,则返回值为 expr2 
expr1 的值为FALSE,则返回值为 expr3
IFNULL( expr1 , expr2 ):判断第一个参数expr1是否为NULL:
如果expr1不为空,直接返回expr1;
如果expr1为空,返回第二个参数 expr2
NULLIF(expr1,expr2):如果两个参数相等则返回NULL,否则返回第一个参数的值expr1

在SQL语句中实现“if-then-else”逻辑计算功能,有两种形式:simple casesearched case

simple case的语法结构

CASE  value
    WHEN  [compare_value] THEN  result
    [WHEN [compare_value] THEN  result ...] 
    [ELSE  result]  END

将case后面的值value分别和每个when子句后面的值compare_value进行相等比较:
如果一旦和某个when子句后面的值相等则返回相应的then子句后面的值result;
如果和所有when子句后面的值都不相等,则返回else子句后面的值;
如果没有else部分则返回null。
注意
  ①value可以是字面量、表达式或者列名
  ②CASE表达式的数据类型取决于跟在then或else后面的表达式的类型

mysql> select userid,case salary                                             
    -> when 1000 then 'low'
    -> when 2000 then 'med'
    -> when 3000 then 'high'
    -> else '无效值' end salary_grade
    -> from salary_tab;
+--------+--------------+
| userid | salary_grade |
+--------+--------------+
|      1 | low          |
|      2 | med          |
|      3 | high         |
|      4 | 无效值        |
|      5 | low          |
+--------+--------------+

searched case的语法结构

CASE
    WHEN [condition] THEN result
    [WHEN [condition] THEN result ...]
    [ELSE result]  END


语义:
  如果某个when子句后面的条件condition为true,则返回相应的when子句后面的值result;
  如果所有的when子句后面的条件condition都不为true,则返回else子句后面的值;
  如果没有else部分则返回null。

mysql> select userid,case
    -> when salary<=1000 then 'low'
    -> when salary=2000 then 'med'
    -> when salary>=3000 then 'high'
    -> else '无效值' end salary_grade
    -> from salary_tab;
+--------+--------------+
| userid | salary_grade |
+--------+--------------+
|      1 | low          |
|      2 | med          |
|      3 | high         |
|      4 | 无效值        |
|      5 | low          |
+--------+--------------+

子查询

出现在其他语句中的select语句,称为子查询内查询
子查询就是嵌套查询,一个 select 语句中包含另一个完整的 select 语句。
子查询中只能返回一个字段的数据。

子查询分类

按子查询的位置分

位置支持的查询
SELECT后面支持标量子查询
FROM后面支持表子查询
WHEREHAVING后面支持标量子查询列子查询行子查询
EXISTS后面支持表子查询

按结果集的行列数不同分

分类类型结果集行数
标量子查询一行一列
列子查询一列多行
行子查询一行多列
表子查询多行多列

子查询外部的语句可以是:INSERT / UPDATE / DELETE / SELECT 的任何一个
子查询应用的位置主要有三种情况:分别是WHERE之后、FROM之后、SELECCT之后

where 后

  1. 标量子查询

查询 employees 表中 job_id与141号员工相同salary比143号员工多的员工的 姓名last_namejob_id工资salary

SELECT last_name, job_id, salary
FROM employees
WHERE job_id=(
	SELECT job_id
	FROM employees
	WHERE employee_id=141
)AND salary>(
	SELECT salary
	FROM employees
	WHERE employee_id=143
);

  1. 列子查询(多行子查询)
    使用多行操作符:
  • IN/NOT IN
    • IN()等价于=ANY() NOT IN()等价于<>ALL()
  • ANY/SOME
  • ALL

返回location_id1400或1700的部门中的所有员工姓名

SELECT last_name
FROM departments d INNER JOIN employees e
	ON d.department_id = e.department_id
WHERE d.location_id IN (1400, 1700);

SELECT 后面的子查询

查询每个部门员工个数

使用联表查询操作:

SELECT department_name 部门名, COUNT(1) 员工数量
FROM employees e RIGHT JOIN departments d
	ON e.department_id = d.department_id
GROUP BY department_name

使用子查询

SELECT department_id, department_name,(
	SELECT COUNT(1)
	FROM employees e
	WHERE e.department_id=d.department_id
) 对应员工数
FROM departments d;

在使用子查询中,外部的表名的别名可以传递到子查询中,例如上面的departments 表的别名d就传递到了子查询中。

该子查询可以理解为:

  1. 先获取外层查询的结果集
  2. 然后对结果集的每条记录进行遍历,将对应的参数填入到子查询中得到单条记录的结果拼接到新列中

FROM 后面的子查询

查询对应的工资等级,连接①的结果集和job_grades

SELECT department_id, ag, grade_level
FROM (
	SELECT AVG(salary) ag,department_id
	FROM employees e
	WHERE e.department_id IS NOT NULL
	GROUP BY department_id
) ag_dep INNER JOIN job_grades j
	ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;

即可以将子查询的结果集作为一张表用于联表查询操作

EXISTS 后面的子查询

EXISTS语句后的括号中填入一个子查询语句,返回的结果为false(0)或true(1),分别代表查询结果是否为空。

SELECT EXISTS(SELECT employee_id FROM employees);
SELECT EXISTS(SELECT employee_id FROM employees WHERE salary=30000);

连接查询

在处理多个表时,子查询只有在结果来自一个表时才有用。
但如果需要显示两个表或多个表中的数据,这时就必须使用连接 (join) 操作。 连接的基本思想是把两个或多个表当作一个新的表来操作,如下:

  • 连接用于连接多个表,使用 JOIN 关键字,并且条件语句使用 ON 而不是 WHERE。
  • INNER JOIN:内连接(等值连接),只返回两个表中匹配的行。只有在连接条件都满足的情况下,才会返回结果。若某个表中的行在另一个表中没有对应的匹配行,则该行不会出现在结果集中。
  • 外连接:left join,left outer join,right join,right outer join,union
  • 交叉连接:cross join
  • 表别名:可以用 AS 给列名、计算字段和表名取别名,给表名取别名是为了简化 SQL 语句以及连接相同表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

内连接

INNER JOIN:查询A、B 交集部分数据
语法



显式内连接
select 字段列表 from 表1 【inner】 join 表2 on 连接条件 ... ;

例题
查询每一个员工的姓名 , 及关联的部门的名称
表结构: emp , dept
连接条件: emp.dept_id = dept.id

select name name 
from emp as e 
join dept as d 
on e.dept_id=d.id;


自连接连接的表是自身。自连接表一定要起别名
把一张表连接查询多次

一张员工表,包含员工姓名和员工所属部门,要找出与 Jim 处在同一部门的所有员工姓名。

子查询版本

SELECT name
FROM employee
WHERE department = (
      SELECT department
      FROM employee
      WHERE name = "Jim");

自连接版本

SELECT e1.name
FROM employee AS e1 
INNER JOIN employee AS e2
ON e1.department = e2.department
AND e2.name = "Jim";

外连接

外连接保留了没有关联的那些行。分为左外连接,右外连接以及全外连接,左外连接就是保留左表没有关联的行。

  • LEFT JOIN on左连接,返回左表中的所有行和右表中匹配的行。若右表中没有匹配的行,则返回NULL值,左连接保留了左表的所有数据,不管是否有匹配的右表数据。
  • RIGHT JOIN on右连接,返回右表中的所有行和左表中匹配的行。若左表中没有匹配的行,则返回NULL值,右连接保留了右表的所有数据,不管是否有匹配的左表数据。
  • FULL JOIN on全连接,返回左表和右表中的所有行。若某一表中的行在另一表中没有对应的匹配行,则返回NULL值,全连接保留了两个表的所有数据。
--左外连接
select  字段列表  
from1  
leftouterjoin2  
on  条件...
--右外连接
select  字段列表  
from1  
rightouterjoin2  
on  条件...

select * from a full join b on a.id = b.id

检索所有顾客的订单信息,包括还没有订单信息的顾客。

SELECT Customers.cust_id, Customer.cust_name, Orders.order_id
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;

其他


#自然连接是把同名列通过等值测试连接起来的,同名列可以有多个。
SELECT A.value, B.value
FROM tablea AS A NATURAL JOIN tableb AS B;

交叉联结

使用交叉联结会将两个表中所有的数据两两组合。
直接使用交叉联结的业务需求比较少见,往往需要结合具体条件,对数据进行有目的的提取

使用多表连接查询时会遇到的问题?

  1. 错误的连接条件
    连接条件是指在连接两个表时使用的条件,如果连接条件不正确或不完整,会导致结果不准确或无法获取所需的数据。

  2. 数据重复
    当连接的两个表中存在多对一或多对多的关系时,会导致结果中出现重复的数据。
    需要使用DISTINCT关键字或其他方法来消除重复数据。

  3. 性能问题
    表连接操作涉及多个表,可能会对查询性能产生影响,尤其是对大型表或复杂查询的情况下。
    需要优化查询、创建索引或重新考虑查询需求的方法来改善性能。

  4. 表连接顺序
    不同的表连接顺序可能会导致不同的结果,并且某些顺序可能更高效,因此,需要仔细考虑表连接顺序以获取准确的结果并提高查询性能。

  5. 列名易混淆
    当连接多个表时,可能会存在相同的列名。
    在查询中需要使用表别名或限定列名来避免混淆。

  6. 缺少索引
    如果没有为连接条件上的列创建索引,可能会导致查询性能下降。
    需要根据连接条件创建必要的索引以提高查询性能。

  7. 不易理解
    使用多个表连接可能会增加查询的复杂性,使得查询语句更难理解和维护。
    在编写表连接查询时,需要仔细考虑和测试查询逻辑,以确保正确性和可读性。

多表联合查询

  • 通过联合查询,可以得到两张表中记录的集合或者公共记录的集合,或者其中某张表中的记录的集合
  • 联合查询以行为单位对表进行操作,主要是进行行数的增减
  • 作为联合查询的多表之间的列数、以及列数的类型必须相同(例如:表1查询哪些列,表2就查询哪些列)
  • 联合查询默认会去除重复的记录
  • 联合查询可以使用任何SELECT语句,但是ORDER BY子句只能在最后一次使用

UNION连接

MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合,并去除重复的行。

UNION 操作符必须由两个或多个 SELECT 语句组成,每个 SELECT 语句的列数和对应位置的数据类型必须相同。

默认会去除相同行,如果需要保留相同行,使用 UNION ALL。

只能包含一个 ORDER BY 子句,并且必须位于语句的最后。

SELECT column1, column2, ...
FROM table1
WHERE condition1
UNION
SELECT column1, column2, ...
FROM table2
WHERE condition2
[ORDER BY column1, column2, ...];

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值