基础格式
SELECT 字段名FROM 表名;# 从 表名 表中 无条件 查询 所有字段
运算符
运算符 和其他语言大致相同 常见有
= # 等于 不同于java语言的=在java语言中=代表赋值而==代表等于 即 sql的=相当于java的==> # 大于< # 小于<= # 小于等于>= # 大于等于!= 或 <> # 不等于<=> # 安全等于 : 在sql中使用=判断两值相等时会出现 `NULL`值 的情况 如 :SELECT 1 = NULL as l1, 1 <=> NULL as l2, NULL = NULL as l3, NULL <=> NULL as l4;# 结果: l1->null , l2->0 , l3->null , l4->1 即 当 null 值参与到 = 计算中时 结果必定为 null# 而 <=> 解决了对应 null 值不适用的问题 即 : 字段<=>NULL 相当于 字段 IS NULL , NOT 字段<=>NULL# 相当于 字段 IS NOT NULL# 注意 ---> NULL 参与 = > < <= >= <> 的计算都返回 null
运算相关 关键字
LIKE 相似 # 字段 LIKE '%A%' 将查找出 字段中包含A的数据 % 代表多个字符 , 在字符左侧的%意味着字符左侧无论有多少个字符只要出现了这个字符即可成功匹配反之亦然# 字段 LIKE '_A%' 将查找出字段中第二字符为A的数据 _ 代表一个字符 , 在字符左侧_意味着字符左侧有一个字符后出现了这个字符即可成功匹配反之亦然\ 转义 # \_ -> 字符_ , \% -> 字符%REGEXP 正则 # 字段 REGEXP '正则' 表示 判断字段是否符合正则BETWEEN A AND B # 在 A 和 B 之间 ,# 字段 BETWEEN 5000 AND 12000; 即 字段 >= 5000 AND 字段 <= 12000IN () # 在()内的值之中 例如 :# 字段 IN (1,2,3,4) 即 字段值 在 1,2,3,4 中可以找到 任意一个值与之相等 即可
逻辑运算符
and # 逻辑 和、与or # 逻辑 或! 或 not # 逻辑非xor # 逻辑异或 《俩边值不同则为true》 例如 :SELECT TRUE XOR FALSE AS txf, -> TRUETRUE XOR TRUE AS txt, -> FALSEFALSE XOR FALSE AS fxf, -> FALSE1 XOR 0 AS 1x0; -> TRUE
排序,分页
ORDER BY 字段 # 排序 根据字段 进行排序 可指定排序顺序# ORDER BY A ASC, B DESC; 即 根据 字段A正序 后 根据字段B倒叙# ASC正序 默认可不写 , DESC 倒叙LIMIT N1,N2; # 截取一定数量的数据# LIMIT 1,10 即 从数据下标 1 往后取 10 条# ---> 注意 数据下标是从 0 开始的# 分页时 当前页:pageNo , 页面大小:pageSize 即 LIMIT (pageNo - 1) * pageSize, pageSize;# 在MySQL 8 之后 也可使用 LIMIT 10 OFFSET 1;来分页 相当于 LIMIT 1, 10;
连接查询
# sql92sql92 左连接在 右条件后加(+) 反之相反 不写 则默认为 内连接 <注意:mysql并不支持(+)的写法>SELECT e.employee_id,e.manager_id,e.last_name, e2.employee_id AS mid,e2.last_name AS mnameFROM employees AS e,employees AS e2WHERE e.manager_id = e2.employee_id(+);# sql99使用 XXXX JOINSELECT e.employee_id, e.manager_id, e.last_name, e2.employee_id AS mid,e2.last_name AS mnameFROM employees AS eLEFT JOIN employees AS e2 ON e.manager_id = e2.employee_id;# 关键字 LEFT JOIN , RIGHT JOIN, INNER JOIN 或 JOIN , FULL JOIN 相当于左连接的值UNION ALL右链接的值# 左连接 右连接 内连接 全连接 MySQL 不支持全连接# 表1 XXXX JOIN 表2 ON 表1.A = 表2.B ; 表1 连接 表2 条件是 表1.A = 表2.B
# 不常用的链接写法# *** 自然连接 当链接的两张表中的 字段名和类型完全相同时 自然连接将自动使用此字段连接查询SELECT e.last_name, e.department_id, d.department_id AS did, d.department_name, d.location_idFROM employees eNATURAL LEFT JOIN departments d;-- 相当于SELECT e.last_name, e.department_id, d.department_id AS did, d.department_name, d.location_idFROM employees eLEFT JOIN departments d ON e.department_id = d.department_idAND e.manager_id = d.manager_id;# *** 连接字段代替SELECT e.last_name, e.department_id, d.department_id AS did, d.department_name, d.location_idFROM employees eLEFT JOIN departments d ON e.department_id = d.department_idAND e.manager_id = d.manager_id;-- 相当于SELECT e.last_name, e.department_id, d.department_id AS did, d.department_name, d.location_idFROM employees eLEFT JOIN departments d USING (department_id, manager_id);
特别注意:当链接的多张表中出现了相同的字段时必须指明select列表中的重名字段来自哪一张表,否则将报错
单行函数
函数过多仅列举一点点进行举例:
NOW() 获取当前时间YEAR() 获取时间中的年份 等 ....# ***SELECT hire_date,DATEDIFF(NOW(), hire_date) AS day1,# DATEDIFF() 返回 expr1 - expr2,表示为从一个日期到另一个日期的天数。 expr1 和 expr2 是日期或日期和时间表达式。 计算中仅使用值的日期部分。TO_DAYS(NOW()) - TO_DAYS(hire_date) AS day2,# 给定日期日期,返回天数(自 0000-00-00 00:00:00 年以来的天数)YEAR(NOW()),YEAR(hire_date),YEAR(NOW()) - YEAR(hire_date) AS year1,DATEDIFF(NOW(), hire_date) / 365 AS year2,(TO_DAYS(NOW()) - TO_DAYS(hire_date)) / 365 AS year3FROM employeesORDER BY year1 DESC;### 可见 单行函数 可以 嵌套BENCHMARK(1000000, COUNT(1)) # 使 函数 COUNT(1) 执行 1000000次 用于测试效率
多行函数(聚合)
函数
avg() # 平均数sum() # 总合min() # 最小max() # 最大count() # 统计个数# ---> *** avg sum min max count 忽略null 即 不统计 不求和 不计数 不比较# 即 avg(commission_pct) = sum(commission_pct) / count(commission_pct)# != sum(commission_pct) / count(*) = avg(ifnull(commission_pct,0))
分组
GROUP BY 字段 # 根据 字段分组 可多个字段 例如 GROUP BY A,B; 根据A分组后在根据B分组# 分组函数常常配合 聚合函数使用# 例如 查询各个部门的员工最低 最高 平均 总 工资SELECT MAX(salary), MIN(salary), AVG(IFNULL(salary, 0)), SUM(salary)FROM employeesGROUP BY employees.department_id;# AVG(IFNULL(salary, 0)) 当工资为NULL时 看作0 计工资 并 加入个数统计 否则 将在统计个数时忽略# null的数据 导致结果偏大# *** 查询的字段除了聚合函数外 必须出现再group by 后面# 即SELECT employees.department_id,MAX(salary)FROM employeesGROUP BY employees.department_id;# ------<>> 否则 查询的字段若不在分组中会出现问题 MySQL中部分版本可能不会报错 但是在其他库中会报错# 若要对 聚合值 进行判断过滤 需使用 HAVING 其他值判断不要写在 HAVING 后 会影响效率# 因为HAVING的执行是位于WHERE之后的如果把WHERE的过滤条写到了HAVING后面# 会导致无法提前过滤掉大部分数据导致数据操作行数增大查询速度变慢SELECT employees.department_id,MAX(salary)FROM employeesWHERE department_id <=> NULLGROUP BY employees.department_idHAVING MAX(salary) > 10;# WITH ROLLUP将所有数据作为一组进行计算# 会让所有分组结束后多分一组(即多了一行数据)代表整个查询分为一组SELECT department_id, AVG(salary)FROM employeesGROUP BY department_idWITH ROLLUP;
执行顺序
FROM -> ON -> [XXX] JOIN -> WHERE -> GROUP BY -> HAVING => SELECT -> DISTINCT => ORDER BY -> LIMIT
由于MySQL的底层在HAVING前产生了临时表所以可以使用SELECT列表的字段别名 在其他库中是不支持的 不建议在HAVING 后使用别名
在WHERE中也不能使用别名
子查询
增加关键字
ANY/SOME(任一 有一个就行) ALL(所有)EXISTS 存在, 会将父查询中的每一行带入到EXISTS的子查询中验证是否存在,存在则展示否则将剔除
常见子查询例
# 查询 和 员工id = 104 的员工 的 工资 和 jobId 相同的 员工 信息SELECT *FROM employeesWHERE (salary, job_id) = (SELECT salary, job_idFROM employeesWHERE employee_id = 104);# 查询 与 jobId = IT 的任意一个员工 的工资相等的 员工信息 相当于 INSELECT *FROM employeesWHERE salary = ANY (SELECT salaryFROM employeesWHERE job_id = 'IT');# 查询有员工的部门信息SELECT *FROM departmentsWHERE EXISTS(SELECT department_idFROM employeesWHERE departments.id = employees.department_id);# 内查询可以使用外查询的字段# 查询比自己部门平均工资高的员工信息SELECT we.*FROM employees AS weWHERE we.salary > (SELECT AVG(IFNULL(ie.salary, 0))FROM employees ieWHERE ie.department_id = we.department_id);
进阶格式
SELECT 子查询/其他字段FROM 子查询/其他表XXXX JOIN 子查询/其他表WHERE非聚合函数值普通条件/含有子查询的条件GROYP BY N个字段HAVING 聚合函数值条件ORDER BY N个字段LIMIT 起始,结束
[

