mysql-内置函数,复合查询和内外连接
一 日期函数
| 函数名称 | 描述 | 示例 | 
|---|---|---|
| current_date() | 返回当前日期(格式:yyyy-mm-dd) | select current_date();→2017-11-19 | 
| current_time() | 返回当前时间(格式:hh:mm:ss) | select current_time();→13:51:21 | 
| current_timestamp() | 返回当前日期和时间(格式:yyyy-mm-dd hh:mm:ss) | select current_timestamp();→2017-11-19 13:51:48 | 
| date(datetime) | 提取日期部分 | select date('2023-10-01 12:30:45');→2023-10-01 | 
| date_add(date, interval n unit) | 日期加法(unit: year/day/minute/second) | select date_add('2017-10-28', interval 10 day);→2017-11-07 | 
| date_sub(date, interval n unit) | 日期减法(unit: year/day/minute/second) | select date_sub('2017-10-01', interval 2 day);→2017-09-29 | 
| datediff(date1, date2) | 计算两个日期间隔的天数(date1 - date2) | select datediff('2017-10-10', '2016-09-01');→404 | 
| now() | 返回当前日期和时间(同 current_timestamp()) | insert into msg(content, sendtime) values('hello', now()); | 
案例操作细节
- 显示留言日期(不显示时间)select content, date(sendtime) from msg;
- 查询2分钟内发布的帖子select * from msg where date_add(sendtime, interval 2 minute) > now();
二 字符串函数
| 函数名称 | 描述 | 示例 | 
|---|---|---|
| concat(str1, str2, ...) | 字符串拼接 | select concat(name, '的语文是', chinese, '分') from exam_result; | 
| instr(str, substring) | 返回子串在字符串中的位置(从1开始,未找到返回0) | select instr('hello', 'el');→2 | 
| ucase(str)/lcase(str) | 转换为大写/小写 | select lcase(substring(ename, 1, 1)) from emp; | 
| left(str, length) | 从左侧截取指定长度字符 | select left('abcdef', 3);→abc | 
| length(str) | 返回字符串字节长度(中文依赖字符集) | select length('中文');→6(utf8编码) | 
| replace(str, old, new) | 替换字符串中的子串 | select replace(ename, 's', '上海') from emp; | 
| substring(str, pos, len) | 从指定位置截取字符(pos从1开始,len可选) | select substring(ename, 2, 2) from emp; | 
| trim(str) | 去除字符串首尾空格 | select trim(' abc ');→abc | 
案例操作细节
- 显示姓名首字母小写select concat(lcase(substring(ename, 1, 1)), substring(ename, 2)) from emp;
- 计算字符串中逗号出现次数select length('10,a,b') - length(replace('10,a,b', ',', '')) as cnt;
三 数学函数
| 函数名称 | 描述 | 示例 | 
|---|---|---|
| abs(num) | 绝对值 | select abs(-100.2);→100.2 | 
| ceiling(num)/floor(num) | 向上取整 / 向下取整 | select ceiling(23.04);→24,floor(23.7);→23 | 
| format(num, decimal_places) | 格式化数字(四舍五入保留小数位) | select format(12.3456, 2);→12.35 | 
| rand() | 生成[0.0, 1.0)的随机浮点数 | select rand();→0.1234(随机值) | 
| mod(num, denom) | 取模运算 | select mod(10, 3);→1 | 
| conv(num, from_base, to_base) | 进制转换(如十进制转二进制) | select bin(10);→1010,conv(10, 10, 2);→1010 | 
四 其他函数
| 函数名称 | 描述 | 示例 | 
|---|---|---|
| user() | 返回当前用户 | select user();→root@localhost | 
| database() | 返回当前使用的数据库 | select database();→test_db | 
| md5(str) | 计算md5哈希值(32位字符串) | select md5('admin');→21232f297a57a5a743894a0e4a801fc3 | 
| ifnull(val1, val2) | 若val1为null,返回val2;否则返回val1 | select ifnull(null, '123');→123 | 
| password(str) | 对字符串加密(mysql用户密码专用) | select password('root');→*81f5e21e35407d884a6cd4a731ae8fb6... | 
关键操作细节
-  字符串长度计算 - length()以字节为单位,中文在utf8中占3字节,gbk中占2字节。
- 示例:select length('中文');→6(utf8)。
 
-  日期范围查询 - 使用date_add()或date_sub()动态计算时间范围。
- 示例:查询最近2分钟的数据:select * from msg where sendtime > date_sub(now(), interval 2 minute);
 
- 使用
-  空值处理 - ifnull()用于替代null值,避免空指针问题。
- 示例:select ifnull(qq, '未知') from students;
 
-  随机排序 - 结合rand()和order by实现随机抽取数据。
- 示例:select * from exam_result order by rand() limit 1;
 
- 结合
mysql复合查询
一、基本查询回顾
-  条件过滤与排序 -- 工资>500或岗位为manager,且姓名首字母大写 select * from emp where (sal>500 or job='manager') and ename like 'j%'; -- 按部门号升序、工资降序排序 select * from emp order by deptno, sal desc; -- 按年薪降序排序 select ename, sal*12+ifnull(comm,0) as '年薪' from emp order by 年薪 desc;
-  子查询应用 -- 显示工资最高的员工 select ename, job from emp where sal = (select max(sal) from emp); -- 工资高于平均工资的员工 select ename, sal from emp where sal > (select avg(sal) from emp);
-  分组统计 -- 每个部门的平均工资和最高工资 select deptno, format(avg(sal), 2), max(sal) from emp group by deptno; -- 平均工资<2000的部门 select deptno, avg(sal) as avg_sal from emp group by deptno having avg_sal<2000; -- 每种岗位的雇员总数和平均工资 select job, count(*), format(avg(sal),2) from emp group by job;
二、多表查询
-  联合查询(emp、dept、salgrade表) -- 显示员工名、工资、部门名(emp与dept关联) select ename, sal, dname from emp, dept where emp.deptno = dept.deptno; -- 显示部门10的部门名、员工名、工资 select ename, sal, dname from emp, dept where emp.deptno=dept.deptno and dept.deptno=10; -- 显示员工工资等级(emp与salgrade关联) select ename, sal, grade from emp, salgrade where sal between losal and hisal;
-  自连接(同一表内连接) -- 查询ford的上级领导(通过别名实现自连接) select leader.empno, leader.ename from emp leader, emp worker where leader.empno = worker.mgr and worker.ename='ford';
三、子查询
-  单行子查询(返回单行结果) -- 查询smith同部门的员工 select * from emp where deptno = (select deptno from emp where ename='smith');
-  多行子查询(返回多行结果) -- in: 查询与10号部门岗位相同的员工(不含10号部门) select ename, job, sal, deptno from emp where job in (select distinct job from emp where deptno=10) and deptno<>10; -- all: 工资高于30号部门所有员工的员工 select ename, sal, deptno from emp where sal > all(select sal from emp where deptno=30); -- any: 工资高于30号部门任意员工的员工 select ename, sal, deptno from emp where sal > any(select sal from emp where deptno=30);
-  多列子查询(返回多列结果) -- 查询与smith部门和岗位相同的员工(不含smith) select ename from emp where (deptno, job)=(select deptno, job from emp where ename='smith') and ename<>'smith';
-  from子句中的子查询(临时表) -- 显示工资高于部门平均工资的员工 select ename, deptno, sal, format(asal,2) from emp, (select avg(sal) asal, deptno dt from emp group by deptno) tmp where emp.sal > tmp.asal and emp.deptno=tmp.dt;
四、合并查询
-  union(去重并集) -- 工资>2500或职位为manager的员工(去重) select ename, sal, job from emp where sal>2500 union select ename, sal, job from emp where job='manager';
-  union all(不去重并集) -- 工资>2500或职位为manager的员工(保留重复) select ename, sal, job from emp where sal>2500 union all select ename, sal, job from emp where job='manager';
五、实战操作
- 查询员工入职时的薪水(按emp_no逆序)select emp_no, salary from salaries where from_date=hire_date order by emp_no desc;
- 生成所有表的count语句select concat('select count(*) from ', table_name, ';') from information_schema.tables where table_schema='当前数据库名';
- 获取非manager员工select emp_no from employees where emp_no not in (select emp_no from titles where title='manager');
关键细节
- 多表连接必须指定条件,避免笛卡尔积(如emp.deptno = dept.deptno)。
- 自连接需使用别名区分表(如emp leader, emp worker)。
- 子查询在from中作为临时表,需定义别名并关联字段。
- union要求列数和类型一致,默认去重,union all保留重复。
- 聚合函数与group by配合,非聚合字段需包含在group by中。
mysql内外连接
一、内连接(inner join)
语法:
select 字段 from 表1 inner join 表2 on 连接条件 [and 其他条件];  
特点:
- 仅返回两个表中匹配的行,不匹配的行被过滤。
- 等价于使用where子句的隐式内连接(如select ... from 表1, 表2 where 表1.字段=表2.字段)。
案例:
-- 显示smith的名字和部门名称  
-- 隐式内连接  
select ename, dname from emp, dept where emp.deptno=dept.deptno and ename='smith';  
-- 显式内连接  
select ename, dname from emp inner join dept on emp.deptno=dept.deptno and ename='smith';  
二、外连接(outer join)
1. 左外连接(left join)
语法:
select 字段 from 表1 left join 表2 on 连接条件;  
特点:
- 左表(表1)完全显示,右表无匹配时填充null。
- 应用场景:需包含左表所有记录,即使右表无匹配。
案例:
-- 学生表(stu)与成绩表(exam)左连接,显示所有学生(包括无成绩的)  
select * from stu left join exam on stu.id=exam.id;  
输出示例:
+------+------+------+-------+  
| id   | name | id   | grade |  
+------+------+------+-------+  
| 1    | jack | 1    | 56    |  
| 2    | tom  | 2    | 76    |  
| 3    | kity | null | null  |  
| 4    | nono | null | null  |  
+------+------+------+-------+  
2. 右外连接(right join)
语法:
select 字段 from 表1 right join 表2 on 连接条件;  
特点:
- 右表(表2)完全显示,左表无匹配时填充null。
- 应用场景:需包含右表所有记录,即使左表无匹配。
案例:
-- 学生表(stu)与成绩表(exam)右连接,显示所有成绩(包括无学生的)  
select * from stu right join exam on stu.id=exam.id;  
输出示例:
+------+------+------+-------+  
| id   | name | id   | grade |  
+------+------+------+-------+  
| 1    | jack | 1    | 56    |  
| 2    | tom  | 2    | 76    |  
| null | null | 11   | 8     |  
+------+------+------+-------+  
三、关键操作细节
-  连接条件必须明确: - 使用on指定匹配条件(如stu.id=exam.id),避免笛卡尔积导致数据冗余。
 
- 使用
-  外连接的优先级: - 左外连接以左表为主,右外连接以右表为主。
- 可通过调整表顺序实现相同效果:-- 方法1:左连接 select d.dname, e.* from dept d left join emp e on d.deptno=e.deptno; -- 方法2:右连接 select d.dname, e.* from emp e right join dept d on d.deptno=e.deptno;
 
-  过滤条件的放置: - 若需对外连接结果进一步过滤,使用where而非on:-- 显示左表中无匹配的部门 select d.dname from dept d left join emp e on d.deptno=e.deptno where e.empno is null;
 
- 若需对外连接结果进一步过滤,使用
四、重难点总结
-  区别内连接与外连接: - 内连接:仅返回匹配行。
- 外连接:保留主表所有行,辅表无匹配时填充null。
 
-  左连接 vs 右连接: - 左连接以左表为主,右连接以右表为主。
- 可通过调整表顺序互换使用。
 
-  实际应用场景: - 内连接:需精确匹配的场景(如员工与部门关联)。
- 左/右外连接:需包含主表所有记录的场景(如显示所有学生成绩,即使无考试记录)。
 
五、实战应用
-  leetcode例题: - rank-scores:使用自连接或窗口函数(需结合连接操作)。
- exchange-seats:通过自连接或条件判断实现座位交换。
 内连接:仅返回匹配行。
- 外连接:保留主表所有行,辅表无匹配时填充null。
 
-  左连接 vs 右连接: - 左连接以左表为主,右连接以右表为主。
- 可通过调整表顺序互换使用。
 
-  实际应用场景: - 内连接:需精确匹配的场景(如员工与部门关联)。
- 左/右外连接:需包含主表所有记录的场景(如显示所有学生成绩,即使无考试记录)。
 
五、实战应用
- leetcode例题: - rank-scores:使用自连接或窗口函数(需结合连接操作)。
- exchange-seats:通过自连接或条件判断实现座位交换。
 
