链接:https://baobeihuijia.com/bbhj/contents/3/199913.html
三个概念区分
对数据库的大致了解过程
MySQL详细学习教程(建议收藏)-CSDN博客
聚集索引(聚类索引)与非聚集索引(非聚类索引) - 知乎 (zhihu.com)
主键约束(PRIMARY KEY)和唯一约束(UNIQUE)的区别_主键约束和唯一约束有什么区别-CSDN博客
事务ACID理解-CSDN博客
数据库三级模式:外模式、模式和内模式_数据库模式内模式外模式-CSDN博客
基础知识
1、> < = != >= <=
2、and or not
3、like / between and / in / is null
like 用通配符% 表示任意多的字符,包括0个,下划线表示一个
SELECT *
FROM employees
WHERE first_name LIKE ‘%a%’;
SELECT *
FROM employees
WHERE first_name LIKE ‘__e__a%’;
SELECT *
FROM employees
WHERE last_name LIKE ‘__%’
between
两边都是闭区间、有前后关系
SELECT *
FROM employees
WHERE employee_id BETWEEN 100 AND 120;
IN: 表示某字段是否满足in列表中的一项,in中的判断逻辑是:是否能找到直接相等?
IS NULL:等号不能判断null, <=>安全等于符号
排序查询
默认为升序、ASC \ DESC
一般放在查询的最后边
SELECT *,salary*12*(1+IFNULL(commission_pct,0)) AS money
FROM employees
ORDER BY money DESC;
# 按照多个条件进行排序
SELECT *
FROM employees
ORDER BY salary DESC, employee_id;
常见函数
单行函数:concat / length / ifnull / UPPER / LOWER (变化大小写) / substr(截取字符串) / instr(返回第一次出现的起始索引),trim是去掉左右空格,lpad
# 返回第一次出现的起始索引
SELECT INSTR('zhuahdhqwdhqwo','hq');
# 可以选择去前或者去后
SELECT TRIM('a' FROM 'aaaazhiyaaaaaaa');
# lpad进行左长度填充,超过固定长度就会截断
SELECT LPAD('yyy',10,'-');
# rpad右填充
SELECT RPAD('yyy',10,'-');
# replace
SELECT REPLACE('nihaowoshiczy','czy','dameinv');
# round:四舍五入
SELECT ROUND(4.5);
SELECT ROUND(1.657,2);
# ceil:向上取整,返回大于等于本身的最小整数
# floor:向下取整,返回小于等于本身的最小整数
# truncate 截断
SELECT TRUNCATE(1.666666,3);
#mod取余,结果只看被除数的正负号: mod(a,b) = a-a/b*b
#时间转换 STR_TO_DATE
SELECT STR_TO_DATE('7-31 2023','%c-%d %Y');
SELECT DATE_FORMAT(NOW(),'%Y %c_%d');
select version();
select database();
# 查询时间之差
SELECT DATEDIFF(NOW(),'2000-7-31');
流程控制函数
# if
SELECT IF(commission_pct IS NULL,'A','B') FROM employees;
# case当作switch使用
SELECT salary, department_id,
CASE department_id
WHEN 30 THEN salary*1.1
WHEN 40 THEN salary*1.2
WHEN 50 THEN salary*1.3
ELSE salary
END
FROM employees;
# case当作if else使用
SELECT salary,
CASE
WHEN salary >20000 THEN 'A'
WHEN salary >15000 THEN 'B'
WHEN salary >10000 THEN 'C'
ELSE 'D'
END
FROM employees;
分组函数:max / min / avg / sum / count 和分组函数一起查询的字段需要和分组函数结果一致
sum和avg不计算考虑null
max和min也忽略考虑null
count计算的是非空字段的数量
SELECT COUNT(*) FROM employees;
SELECT COUNT(1) FROM employees;
查询
分组查询
SELECT MAX(salary),job_id
FROM employees
GROUP BY job_id;
SELECT COUNT(*), department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*)>2;
# 查询每个工种有奖金的最高工资大于12000的工种和最高工资
SELECT job_id, MAX(salary)
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id
HAVING MAX(salary)>12000;
# 查询领导编号大于102的每个领导下最低工资大于5000的领导编号和最低工资
SELECT manager_id, MIN(salary)
FROM employees
WHERE manager_id > 102
GROUP BY manager_id
HAVING MIN(salary)>5000;
# 多个字段分组
SELECT AVG(salary), department_id, job_id
FROM employees
GROUP BY department_id, job_id;
# 多个字段分组查询
SELECT AVG(salary), department_id, job_id
FROM employees
WHERE department_id IS NOT NULL
GROUP BY department_id, job_id
HAVING AVG(salary)>10000
ORDER BY AVG(salary) DESC;
连接查询:sql92和sql99语法
# sql92语法内连接语法:
# 等值连接:产生交集部分
SELECT `name`,boyname FROM beauty, boys
WHERE beauty.`boyfriend_id` = boys.`id`;
SELECT department_name,d.manager_id,MIN(salary)
FROM departments d, employees e
WHERE e.`department_id` = d.`department_id` AND e.`commission_pct` IS NOT NULL
GROUP BY department_name,d.manager_id;
# 非等值连接
SELECT salary, grade_id
FROM employees,job_grade
WHERE salary BETWEEN lowerst_sal AND highest_sal;
# 自连接
SELECT a.`employee_id`, b.`employee_id`
FROM employees a, employees b
WHERE a.`manager_id` = b.`employee_id`;
SELECT country_id, COUNT(*)
FROM departments d,locations l
WHERE d.`location_id` = l.`location_id`
GROUP BY l.`country_id`
HAVING COUNT(*)>2;
# sql99内连接语法
#inner join
SELECT last_name,department_name
FROM employees e
INNER JOIN departments d
ON e.`department_id` = d.`department_id`;
# 三表连接
SELECT last_name,department_name,job_title
FROM employees e
INNER JOIN departments d
ON e.`department_id` = d.`department_id`
INNER JOIN jobs j
ON e.`job_id` = j.`job_id`
ORDER BY department_name;
# 非等值连接
# 自连接
SELECT e.last_name,m.last_name
FROM employees e
INNER JOIN employees m
ON e.`manager_id` = m.`employee_id`
WHERE e.`last_name` LIKE '%k%';
# 外连接,用于查询一个表中有另一个表中没有,结果为主表的全部记录
# 包括两部分:内连接(只要有相等就会显示) + 主表有但是从表没有的显示为null(筛选的时候用从表的主键)
# 左外和右外交换表的顺序,可以实现同样的结果
# 一般是为了查询除了交集部分的不匹配的行
# left outer right outer
SELECT `name`,boys.*
FROM beauty
LEFT OUTER JOIN boys
ON beauty.`boyfriend_id` = boys.`id`
WHERE boys.id IS NOT NULL;
SELECT department_name
FROM departments d
LEFT OUTER JOIN employees e
ON d.department_id = e.department_id
WHERE e.employee_id IS NULL;
# 查询部门名为SAL或者IT的员工信息,防止出现SAL部门没有员工
SELECT e.*
FROM employees e
RIGHT OUTER JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_name`= 'SAL' OR d.`department_name` = 'IT';
# full outer join,除了内连接结果,保留左和右边没有匹配的部分
# 交叉连接:就是笛卡尔乘积
SELECT `name`, boyname
FROM beauty
CROSS JOIN boys;
子查询
# 有了子查询后尽量不要用两表连接筛选了
# 如果是select嵌套select那么成为外查询/主查询
# 子查询,结果集为一个标量值
# where后边加select
SELECT last_name,job_id,salary
FROM employees
WHERE salary=(
SELECT MIN(salary)
FROM employees
);
# having后边加select
SELECT department_id,MIN(salary)
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
);
in/not in:可以改写为 =any / !=all
ANY
ALL
# select后边加select
# 查询是一条一条进行遍历的,所以在select后边的查询必须是一行一列
SELECT d.*,(
SELECT COUNT(*)
FROM employees e
WHERE e.department_id = d.department_id
)FROM departments d;
# from后边加select,必须给新表起别名
SELECT ag_dep.*, jg.level
FROM
(
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep INNER JOIN job_grades jg
ON ag_dep.ag BETWEEN jg.lowest_sal AND jg.highest_sal
# exist
SELECT d.department_name
FROM departments d
WHERE d.department_id IN (
SELECT e.department_id
FROM employees e
);
SELECT d.department_name
FROM departments d
WHERE EXISTS(
SELECT *
FROM employees e
WHERE e.`department_id` = d.`department_id`
);
SELECT bo.*
FROM boys bo
WHERE EXISTS(
SELECT *
FROM beauty b
WHERE b.`boyfriend_id` = bo.`id`
);
SELECT bo.*
FROM boys bo
WHERE bo.`id` IN (
SELECT b.`boyfriend_id`
FROM beauty b
);
分页查询
# 分页查询
limit offset,size;
offset:要显示的起始索引,从0开始
size:要显示的条目数
# 分页公式:
limit (page-1)*size,size;
SELECT *
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 10;
# 一个经典的样例
# 查平均工资最高的部门的manager的信息
# 两个表的不同拼接会是不同结果
(
如果是employee的department_id和department的department_id拼接,那么得到的结果是我们知道每个员工的部门详细信息
但是如果是employee的employee_id和department的manager_id拼接,那么得到的是我们知道每个部门领导人的详细信息
)
SELECT *
FROM employees e
INNER JOIN departments d
ON e.`employee_id` = d.`manager_id`
WHERE d.`department_id` = (
SELECT department_id
FROM employees
GROUP BY department_id
ORDER BY AVG(salary) DESC
LIMIT 1
);
联合查询
union 连接两个查询结果:查询结果来自于多个表,表之间没有连接关系,但是查询结果列数和列类型要一致
union all:可以包含两个表中的重复项