查询在业务开发中非常常见,几乎 80% 的业务都和查询有关。

2.1 基础查询


语法:

  1. select 查询列表
  2. from 表名;

分析:

  • 查询列表可以是:表中的字段、常量值、表达式、函数
  • 查询的结果是 一个虚拟的表格

实际应用:

  • 字段:工作中使用到的最多的就是各种各样的查询,字段当然是主体。需要查表中的哪一列数据就将相应的列放入查询列表中
  • 常量值:有时候前端需要展示一些固定的值,比如订单待处理页面的订单的状态列都是待处理,此时可以在列中增加一个 “待处理”的字符串常量。
  • 表达式,表达式通常是对某一个字段进行处理之后返回它的值,比如合计列,用来合计某些列的总数数,就可以在查询列表中使用加和表达式。
  • 函数:MySQL 中内置了一些函数,可以对单列或者是多列进行处理,返回值则会当成一个新的列返回

示例1:查询单个列

  1. SELECT last_name
  2. FROM employees;

示例2:查询多个列

  1. SELECT last_name,salary,email
  2. FROM employees;

实例3:查询全部字段

  1. # 方式一:
  2. SELECT
  3. first_name,email,phone_number,job_id,salary,
  4. commission_pct,manager_id,department_id,hiredate
  5. FROM employees;
  6. # 方式二
  7. SELECT *
  8. FROM employees;

注意:方式二非常不建议在实际开发中使用,具体原因可以去百度,记住即可。
实例4:查询常量值

  1. SELECT 10;
  2. SELECT 'john';

实例5:查询表达式

  1. SELECT 100*98;

实例6:查询函数

  1. SELECT VERSION();

2.2 条件查询


数据库表一般包含大量的数据,很少需要检索表中的所有行。通常会根据特定操作或者报告的需要提取表数据的子集。

语法:

  1. SELECT 查询列表
  2. FROM 表名
  3. WHERE 筛选条件;

where 操作符:

操作符 说明
> 大于
< 小于
= 等于
<=> 安全等于
>= 大于等于
<= 小于等于
<> 不等于
IS NULL 判空
IS NOT NULL 判非空
BETWEEN AND 指定区间
IN 判定是否在集合中
AND
OR
NOT
LIKE 模糊查询

实例1:查询工资大于 12000 的员工

  1. select *
  2. FROM employees
  3. where salary>12000;

实例2:查询部门编号不等于 90 的员工名和部门编号

  1. select last_name,department_id
  2. FROM employees
  3. WHERE department_id <> 90;

实例3:工资在 10000 到 20000 之间的员工名、工资以及奖金

  1. SELECT last_name,salary,commission_pct
  2. FROM employees
  3. WHERE salary>=10000 AND salary<=20000;
  4. # 等价于
  5. SELECT last_name,salary,commission_pct
  6. FROM employees
  7. WHERE salary BETWEEN 10000 AND 20000;

在使用 BETWEEN AND 时要注意:

  • column BETWEEN a AND b 关键字等价于 column >= a AND column <= b 用数学语言来说就是 a 和 b 的闭区间(包含边界值)。
  • a 和 b 的位置不能替换,不然会查不到结果
  • a 和 b 的类型必须一致,或者可以自动转换

实例4:查询部门编号不是在90到110之间,或者工资高于15000的员工信息

  1. SELECT *
  2. FROM employees
  3. WHERE employee_id < 90 OR employee_id >110
  4. OR salary > 15000;

实例5:查询员工中包含字符 a 的员工

  1. SELECT *
  2. FROM employees
  3. where last_name LIKE '%a%';

LIKE 用于模糊查询,% 表示任意多个任意字符

实例6:查询员工名中第二个字符为 a 的员工

  1. SELECT *
  2. FROM employees
  3. where last_name LIKE '_a%';

“_” 表示占位符,表示一个任意符号。

实例7:查询员工姓名中第二个为 _ 员工

  1. # 使用转义字符
  2. SELECT last_name
  3. FROM employees
  4. where last_name LIKE '_\_%';
  5. # 自定义转义符
  6. SELECT last_name
  7. FROM employees
  8. WHERE last_name LIKE '_$_%' ESCAPE '$';

对于特殊符号,可以使用默认的转义字符 \ 进行转义,也可以使用 ESCAPE 关键字自定义自己的转义符号

实例8: 查询员工的工种编号是否是 IT_PROGE,AD_VP,AD_PRES 中的一个员工名和公众编号

  1. SELECT last_name,job_id
  2. FROM employees
  3. WHERE job_id IN ('IT_PROGE','AD_VP','AD_PRES');
  • 使用in提高语句的简洁度,in可以和多个等值判断替换 x in(1,2,3)可以替换成 x=1 or x=2 or x=3
  • in列表中不会匹配通配符,因为 in和等值判断等效,所以 x = %a%这种等式无法成立,因为 = 是确认条件,不是模糊条件
  • in列表的值类型必须一致或者兼容

实例9:查询没有奖金的员工名和奖金率

  1. SELECT last_name,commission_pct
  2. FROM employees
  3. WHERE commission_pct IS NULL;

实例10:查询有奖金员工的员工名和奖金率

  1. SELECT last_name,commission_pct
  2. FROM employees
  3. WHERE commission_pct IS NOT NULL;

= 和 <> 不能用于判断 NULL 值,IS NULL 或 IS NOT NULL 可以判断 NULL 值,但是 IS 不能单独使用

实例11:查询没有奖金的员工共名和奖金率

  1. SELECT last_name,commission_pct
  2. FROM employees
  3. WHERE commission_pct <=> NULL;

实例12:查询奖金率为 0.4 的员工名和奖金率

  1. SELECT last_name,commission_pct
  2. FROM employees
  3. WHERE commission_pct <=> 0.4;

<=> 符号既可以用来判断 null 值,也可以用来判断普通的数值类型。但是它的可读性比较差。

经典面试题:限免两条语句的查询结果是否一样?

  1. SELECT * FROM employees; #共107条
  2. SELECT * FROM employees WHERE commission_pct LIKE "%%" AND last_name LIKE "%%";#35

不一样,%%不匹配空值

2.3 排序查询


其实,检索出的数据并不是以纯粹的随机顺序显示的。如果不排序,数据一般将以它在底层中出现的顺序显示。这可以是数据最初添加到表中的数据。但是,如果数据后来进行过更新或删除,则此顺序将会收到 MySQL 重用回收存储空间的影响。因此,如果不明确控制的话,不能(也不应该)一来该排序顺序。关系数据库设计理论认为,如果明确规定排序顺序,则不应该假定检索出的数据的顺序有意义。所以为了明确地对 SELECT 语句,可使用 ORDER BY 子句 ,ORDER BY 子句取一个或多个列的名字,据此对输出进行排序。

子句的概念:SQL语句由子句构成,有些子句是必须的,而有的有的是可选的。一个子句通常由一个关键字和所提供的数据组成。例如 SELECT 子句和 FROM 子句。

语法:

  1. SELECT 条件列表
  2. FROM 表名
  3. [where 筛选条件]
  4. order by 排序条件 [asc|desc]

默认是 asc 升序排序

实例1:查询员工工资,要求工资从低到高排序

  1. SELECT salary
  2. FROM employees
  3. ORDER BY salary ASC;

实例2:查询员工工资,要求工资从高到低排序

  1. SELECT salary
  2. FROM employees
  3. ORDER BY salary DESC;

实例3:按年薪的高低显示员工的信息和年薪

  1. SELECT first_name,salary*12*(1+IFNULL(commission_pct,0)) 年薪
  2. FROM employees
  3. ORDER BY salary*12*(1+IFNULL(commission_pct,0));
  4. SELECT first_name,salary*12*(1+IFNULL(commission_pct,0)) 年薪
  5. FROM employees
  6. ORDER BY 年薪;

可以通过表达式,或者是表达式的别名进行排序

实例4:按照姓名的长度显示员工的姓名和工资

  1. SELECT first_name,LENGTH(first_name)
  2. FROM employees
  3. ORDER BY LENGTH(first_name);

按照函数的返回值对数据进行排序

实例5:查询员工信息,要求先按工资升序排序,再按员工编号降序排序

  1. SELECT *
  2. FROM employees
  3. ORDER BY salary ASC,employee_id DESC;

总结:

  1. asc 代表的是升序,desc代表的是降序,如果不写,则默认是升序
  2. order by 子句可以支持单个字段、多个字段、表达式、函数、别名
  3. order 子句一般放在查询语句的最后面,limit 子句除外。

    2.4 分组查询

    分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算。
    语法:
    1. SELECT 查询列表
    2. FROM TABLE
    3. [WHERE CONDITION]
    4. GROUP BY 分组字段
    5. [ORDER BY column]

    特点:

    • 查询列表最好是分组函数和 group by 后面的字段(不会报错,但是逻辑上显然是无效的查询)
    • GROUP BY 子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据提供更细致的控制。比如对 A,B 两个字段进行分组,那么 A1,B1 和 A1,B2 就成了两个分组,也就是嵌套分组的意思,A 分组中继续对 B 进行分组。
    • GROUP BY 子句中列出的梅个列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在 SELECT 中使用表达式,则必须在 GROUP BY 子句中指定相同的表达式,不能使用别名。
    • 如果分组中具有 NULL 值,则 NULL 将作为一个分组返回。如果列中有多行 NULL 值,它们将被分为一组。
    • GROUP BY 子句必须出现在 WHERE 子句之后,ORDER BY 子句之前

实例1:查询邮箱中包含 a 字符的,每个部门的平均工资

  1. SELECT AVG(salary),department_id
  2. FROM employees
  3. #WHERE INSTR(email,'a') <> 0
  4. WHERE email LIKE '%a%'
  5. GROUP BY department_id;

实例2:查询每个领导手下有奖金的员工的最高工资

  1. select MAX(salary),manager_id
  2. FROM employees
  3. WHERE commission_pct IS NOT NULL
  4. GROUP BY manager_id;

having 关键字


除了能用 GROUP BY 分组数据外,MySQL 还允许过滤分组,规定包括哪些分组,排除哪些分组。WHERE 语句只是针对行进行过滤,而不能对组进行过滤。如果要对分组进行过滤,就需要使用 HAVING 关键字。用法和 WHERE 一样,唯一的区别是 WHERE 过滤行,而 HAVING 过滤组。

实例1:查询员工数大于 2 的部分

  1. SELECT department_id,COUNT(*)
  2. FROM employees
  3. GROUP BY department_id
  4. HAVING COUNT(*)>2;

实例2:查询每个工种有奖金的员工的最高工资,并且只显示最高工资大于 12000 的工种

  1. SELECT MAX(salary),job_id
  2. FROM employees
  3. GROUP BY job_id
  4. HAVING MAX(salary)>12000;

实例3:查询临到编码大于 102 的,手下员工的最低工资大于 5000 的最低工资

  1. SELECT manager_id,MIN(salary) 最低工资
  2. FROM employees
  3. WHERE manager_id >102
  4. GROUP BY manager_id
  5. HAVING 最低工资>5000;

manager_id > 102 这句,既可以使用 WHERE 来筛选,又可以使用 HAVING 语句来筛选。这是因为分组规则就是 manager_id,虽然 WHERE 是针对行来筛选的,但是对于分组来说效果是一样的,按照 manager_id 进行分组时,组内的所有 manager_id 都是一样的。所以 对于分组字段的筛选,WHERE 和 HAVING 基本一致。但是还是建议放在 WHERE 子句中,性能会更高一点,避免先对数据进行分组,又筛选掉一部分组。

实例4:按员工姓名的长度进行分组,查询每一组的员工的个数,筛选员工个数大于 5 的组。

  1. SELECT COUNT(*),LENGTH(last_name)
  2. FROM employees
  3. GROUP BY LENGTH(last_name)
  4. HAVING COUNT(*) > 5;

实例5:查询每个部门每个工种的员工的基本工资

  1. SELECT AVG(salary),department_id,job_id
  2. FROM employees
  3. GROUP BY department_id,job_id;

分组字段部分先后,从两个分组里面找交集

案例6:查询每个工种的员工的平均工资,并按照平均工资排序

  1. SELECT AVG(salary),department_id,job_id
  2. FROM employees
  3. GROUP BY department_id,job_id
  4. ORDER BY AVG(salary)

总结:

  1. 分组函数做条件必须放在 having 子句中
  2. 能用分组前筛选的,就有限考虑使用分组前筛选
  3. group by 子句支持单个字段分组,多个个字段分组(多个字段之间用逗号隔开,没有顺序之分),也可以支持表达式或者是函数,但是用的较少。

    补充知识:


本章节的主要知识有:

  • 起别名
  • 去重
  • 正则表达式

    1. 起别名


查询获得的结果是一张二维表,类似于 excel,表头就是我们查询列表中的列的名字,但是通常字段的名字并不利于我们理解和使用,因此我们也可以对表头进行自定义
语法:

  1. SELECT 查询字段1 AS 别名1,查询字段2 AS 别名2;

分析

  • 查询出来的二维表的表头是 别名1,别名2。而不是原先的 查询字段1,查询字段2。

实际应用:

  • 实际开发中经常涉及到数据的封装,即把从数据库中查出来的数据封装到 POJO对象中。要想封装到对应的字段中,就必须有映射关系。一般来说,数据库中字段的名字和对象中 setter 方法是一样的。但是有时候因为业务不同,命名并不一致,此时也经常会使用到起别名,使得表的字段名和Java对象相对应。

实例:

  1. # 方式一: AS 后面跟 别名
  2. SELECT 100%99 AS 结果;
  3. SELECT last_name AS 姓,first_name AS
  4. FROM employees;
  5. # 方式二:省略 AS
  6. SELECT last_name 姓,first_name
  7. FROM employees;
  8. # 别名和关键字重复
  9. SELECT salary AS "select"
  10. from employees;

Tis:建议规范书写 sql 时,将所有的关键字大写,而所有的表和列名小写

2. 去重


查询时不想显示重复的列,可以使用 DISTINCT 关键字修饰列,就不会出现重复的列了。
语法

  1. select DISTINCT 查询列表
  2. from 表名;

注意:
DISTINCT 关键字应用于所有列而不仅是前置它的列。如果给出多个列,那么只有当这多个列的所有值都相同才会去重

3. 正则表达式

语法
  1. SELECT 查询列表
  2. FROM 表名
  3. WHERE 字段 REGEXP '正则表达式规则';
  • REGEXP 在列值内进行匹配,如果被匹配的文本在列值中出现, REGEXP 将会找到它,相应的行将被返回。(比如 REGEXP ‘1000’,凡是包含 1000 的列值都会被返回)。
  • MySQL中的正则表达式匹配不区分大小写。如果要区分大小写,可使用 BINARY 关键字,如 WHERE prod_name REGEXP BINARY ‘JetPack .000’

进行OR匹配

为搜索两个串之一(或者为这个串,或者为另一个串),使用 | ,如下所示:

  1. SELECT prod_name
  2. FROM products
  3. WHERE prod_name REGEXP '1000|2000'
  4. ORDER BY prod_name;

语句中使用了正则表达式 1000|2000| 为正则表达式的 OR 操作符。它表示匹配其中之一,因此 1000 和 2000 都匹配并返回。

使用 | 从功能上类似于在 SELECT 语句中使用 OR 语句,多个 OR 条件可并入单个正则表达式。

  1. SELECT prod_name
  2. FROM products
  3. WHERE prod_name REGEXP '1000|2000|3000|4000'
  4. ORDER BY prod_name;

匹配几个字符之一

使用 [123] 表示取中括号中的任意一个

  1. SELECT prod_name
  2. FROM products
  3. WHERE prod_name REGEXP '[123] Ton'
  4. ORDER by prod_name;

结果:
image.png

匹配范围

集合可用来定义要匹配的一个或多个字符,例如,下面的集合将匹配数字0到9:
[123456789]
但是为了简化这种类型的集合,可使用 - 来定义一分范围。下面的式子功能上等同于上述数字列表:
[0-9]
范围不限于完整的集合,[1-3] 和 [6-9] 也是合法范围。此外范围不一定只是数值的,[a-z] 匹配任意字母字符。

匹配特殊字符

正则表达式语言具有特定含义的特殊字符构成。如果我们要匹配的正好就是这些特殊符号本身,可以以 \\ 为前导对这些特殊符号进行转义

匹配字符类

存在找出你自己常用的数字、所有字母字符、所有字母字符或所有数字字母字符等的匹配。为了更方便工作,可以使用预定义的字符集,称为字符类(character class)。
image.png

匹配多个实例

目前位置,所有正则表达式都试图匹配单次出现。如果存在一个匹配,该行被检索出来,如果不存在,检索不出任何行。但有时需要对匹配的数目进行更强的控制。例如,你可能需要寻找所有的数,不管数中包含多少数字,或者你可能想寻找一个单词并且还能够适应一个尾随的 s (如果存在),等等。
这可以用表 9-3 列出的正则表达式重复元字符来完成
image.png

定位符

目前位置的所有例子都是匹配一个串中任意位置的文本。为了匹配特定位置的文本,需要使用定位符。
image.png

**^** 的双重用处 ^ 在集合中,用它来否定集合 不在集合中,用来指串的开始处。 使 REGEXP 起类似 LIKE 的作用 本章前面说过, LIKE 和 REGEXP的不同在于, LIKE 匹配整个串而 REGEXP 匹配子串。利用定位符,通过用 ^ 开始每个表达式,用 $ 结束每个表达式,可以使REGEXP 的作用与 LIKE 一样。

补充:

  • concat():字符串连接函数(字符串1,字符串2,…)
  • ifnull():如果某字段或表达式为null,则返回特定的值,否则返回原本的值。ifnull(需要本段的字段,如果为null要返回的值)
  • isnull():判断字段是否为null,如果为null返回1,如果不为null返回0.在数据库中0代表false,1代表true
  • WHERE 子句通常用来过滤数据,在实际应用中,也可以在程序中进行过滤,不过这种方式并不让人满意,因为本来该由数据库处理的数据却让应用程序来处理,一方面影响了程序的性能,另一方面多余的数据也占用了带宽,对资源造成一定的浪费。并且在有索引的情况下,速度是远远高于应用程序的。

注意:

  • SQL(像多数语言一样)在处理 OR 操作符前,优先处理 AND 操

作符。例如 condition1 OR condition2 AND condition3 会优先执行 condition2 AND condition3

  • MySQL 支持使用NOT对IN、BETWEEN和EXISTS子句取反。
  • 不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用其他操作符(因为通配符性能较低)
  • 在确实需要使用通配符时,除非绝非必要,否则不要把它们用在搜索模式的开始处。把通配符置于搜索模式的开始,搜索起来时最慢的(也就是尽量把模糊查询的子句放在最后面)

4. MySQL 常用函数


MySQL 中的函数类似于 Java 中的方法,将一组逻辑语句封装在一起,对外暴露方法名。隐藏了实现细节,提高代码的重用性。

4.1 单行函数

单行函数只会对当前行进行处理,不能跨行。

4.1.1 字符处理函数

length() :获取参数值的字节个数

  1. SELECT LENGTH('john'); # 4个字节
  2. SELECT LENGTH("我爱你中国");# 15 个字节

concat:拼接多个字符

  1. SELECT
  2. CONCAT(last_name,'_',first_name)
  3. FROM
  4. employees;

upper、lower 将字符全部转换为大写或者是小写

  1. # upper、lower
  2. SELECT UPPER('jhon');
  3. SELECT LOWER('ABC');
  4. ## 案例:将姓变大写,名变小写,然后拼接
  5. SELECT CONCAT(UPPER(last_name),'_',LOWER(first_name))
  6. FROM employees;

substr、substring通过字符下标获取对应的子串

  1. SELECT SUBSTR('文天祥人生自古谁无死',1,3); # 文天祥
  2. SELECT SUBSTRING('民族英雄文天祥',5); #文天祥

注意在mysql数据库中,索引是从1开始的,这个函数可以只提供一个参数,表示从这个参数开始到字符结束的位置。也可以给定两个参数,例如给a,b:那么从a(包含a)到b(也包含b)下标的子串。

instr: 获取字符中,字串第一次出现的第一个字符的下标。如果没有则返回0

  1. SELECT INSTR("hello","ll");#3

trim:去除首尾两个的空格,或者是指定的值

  1. ## trim去除空格
  2. select LENGTH(" 1234567 "),LENGTH(TRIM(" 1234567 "));
  3. ## 去除字符串首部和尾部出现的a
  4. SELECT TRIM('a' FROM "aaaaaaaaaaasksksaakkaaaaaaaa");

lpad 和 rpad 用指定的字符将字符串填充到指定长度

  1. ## LPAD(str,len,padstr)
  2. SELECT LPAD("i love you",20,"-+")
  3. ## 如果填充长度比那个字符串本来的长度还小,则将字符串超过的部分删除
  4. SELECT LPAD("i love you",3,"-+") # i l
  5. ## RPAD(str,len,padstr)
  6. SELECT RPAD("dpttt",2,"k") #dp

replace(字符串,被替代的部分,用来替代的部分)

  1. ##REPLACE(str,from_str,to_str)
  2. SELECT REPLACE("今天的天气很不错","今天","明天");

left(str,len) 返回串左边的字符

  1. SELECT LEFT("中文字符",2);#中文

right(str,len) 返回串右边的字符

  1. SELECT RIGHT("中文字符",2)#字符

locate(substr,str) 找出串的一个子串

  1. SELECT LOCATE("ll","hello");#3

和 locate 效果一样

LTrim() 去掉串左边的空格

  1. select LTRIM(" hello ");#hello

Rtrim() 去掉串右边的的空格

  1. select RTRIM(" hello ");# hello

Soundex() 返回串的 SOUNDEX 值

Soundex 是一个将任何文本串转换为描述其语音表示的字母数字模式的算法。SOUNDEX 考虑了类似的发音字符串和音节,使得能对串进行发音比较而不是字母比较。虽然 SOUNDEX 不是SQL的概念,但 MySQL 提供了对 SOUNDEX 的支持。

image.png

4.1.2 数学函数

round 四舍五入

  1. ## ROUND(X)
  2. SELECT ROUND(1.47);#1
  3. SELECT ROUND(-1.45);#1

只针对小数点后一位进行四舍五入

ceil 向上取整

  1. ## ROUND(X)
  2. SELECT CEIL(1.001);#2
  3. SELECT CEIL(-1.001);#-1

返回大于等于输入值的最小整数

floor 向下取整

  1. ## FLOOR(X)
  2. SELECT FLOOR(1.999);#1
  3. SELECT FLOOR(-1.999);#-2

truncate 截断,小数点后保存几位

  1. ## 截断
  2. SELECT TRUNCATE(10.999,2);#10.99

直接截断不进行四舍五入

mod取余

  1. ## MOD(N,M)
  2. SELECT MOD(10,3);#1
  3. SELECT MOD(-10,3);#-1
  4. SELECT MOD(10,-3);#1

取余公式:a%b=a-a/bb;在Java中,整数除以整数就是整数。所以 10-10/33=10-3*3=10-9; 为什么可以这么算? 这是因为,余数就是被除数减去除数的最大整数倍得到的结果。 速记:取余的结果的正负只和被余数的正负有关。

4.1.3 日期函数

日期函数的意思是,输入的参数类型为日期类型,针对日期类型去处理

now():返回当前系统日期+时间

curtime:返回当前时间不包含日期

获取一个日期中的 年、月、日、时、分、秒
## 获取年
SELECT YEAR(NOW()) 年;#2021
SELECT YEAR('199606-26');#NULL
SELECT YEAR('1996-0-626');#NULL
SELECT YEAR('1996 06-26');#NULL
SELECT YEAR('1996 06 26');#NULL
SELECT YEAR('1996-06-26');#1996
SELECT YEAR('1996&06-26');#1996
SELECT YEAR('1996^06-26');#1996
##获取月
SELECT MONTH('1996-06&26');#6
##获取日
SELECT DAY('1996-06&26');#26
##获取时
SELECT HOUR('1992-04-03 22:30:59');#22
## 获取分
SELECT MINUTE('1992-04-03 22:30:59');#30
## 获取秒
SELECT SECOND('1992-04-03 22:30:59');#59

str_to_date:将日期格式的字符串转换成指定格式的日期

date_format:将日期装换成字符串

image.png
格式转换表
image.png

# str-to_date()按照指定的格式解析
SELECT STR_TO_DATE('06-26-1996','%m-%d-%Y');#1996-06-26
# 这个函数的意思是,将字符串按照指定的格式解析后,返回一个数据库格式的日期字符串,即年-月-日这种格式
# date_format
SELECT DATE_FORMAT('1996-06-26','%m-%d-%Y');#06-26-1996

从这两个函数可以看出来,其实数据库中所谓的日期,本质就是字符串,但是这个字符串必须符合 年-月-日 00:00:00 这样的格式,不然就是字符串,而不是日期。随意这两个方法本质上是在将字符串中的字符的顺序进行改变。

注意:
如果要的是日期,请使用 Date() :如果你想要的仅是日期,
则使用 Date() 是一个良好的习惯,即使你知道相应的列只包
含日期也是如此。这样,如果由于某种原因表中以后有日期和
时间值,你的SQL代码也不用改变。当然,也存在一个 Time()
函数,在你只想要时间时应该使用它。
Date() 和 Time() 都是在MySQL 4.1.1中第一次引入的。

技巧:
如果你想检索出 2005 年 9 月下的所有订单,怎么办?简单的相等测试不行,因为他也要匹配月份中的天数。有几种解决办法,其中之一如下所示
image.png
还有另一种办法(一种不需要记住每个月中有多少天或不需要操心闰年2月的办法):
image.png

4.1.4 其他函数

## 查看数据库的版本
SELECT VERSION();
## 查看当前数据库
SELECT DATABASE();
## 查看当前用户
SELECT USER();

4.1.5 流程控制函数

## if ELSE
SELECT IF(10>5,"10大于5","10不大于5");

/**
case 要判断的字段或者表达式
WHEN 常量1 THEN 要显示的值1 或语句1;
WHEN 常量2 THEN 要显示的值2 或语句2;
……
ELSE 要显示的值n或语句n
END
一般使用需要搭配select进行使用,这时候 then后面只能跟对应的值,而不能是语句
但是如果是用在存储过程当中,就可以单独使用该语句,then后面就可以跟语句
如果是语句,就要加分号,如果是值就不能加分号
*/

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    AS 新工资
FROM    employees;
## 案例,查询员工的工资情况
/*

如果工资>20000,显示A级别
如果工资>15000,显示B级别
如果工资>10000,显示c级别
否则,显示D级别

*/
SELECT salary,
CASE 
    WHEN salary>20000 THEN 'A'
    WHEN salary>15000 THEN 'B'
    WHEN salary>10000 THEN 'C'
    ELSE    'D'
END  as 工资级别
FROM employees;

第一行 department_id 后面的逗号不能少。case 是一个整体

单行函数总结
字符函数:
length,concat,substr,instr,trim,upper,lower,lpad,rpad,replace
数学函数:
round,ceil,floor,truncate,mod
日期函数:
now,curdate,curtime,year,month,monthname,day,hour,minute,second,str_to_date,date_format
其它函数:version,datebase,user
控制函数
if,case

4.2 分组函数

功能:用作统计使用,又称为聚合函数,或统计函数,或组函数 分类:sum 求和,avg平均值、max最大值、min最小值、count计算个数

# 简单的使用
SELECT SUM(salary) FROM employees;
SELECT avg(salary) FROM employees;
SELECT MIN(salary) FROM employees;
SELECT COUNT(salary) FROM employees;


SELECT SUM(salary) 工资和,AVG(salary) 平均工资 ,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 非空数据的个数 
FROM employees;

#2. 参数支持哪些类型

SELECT SUM(last_name),AVG(last_name) FROM employees;# 虽然没有报错,但是没有逻辑意义
SELECT SUM(hiredate),AVG(hiredate) FROM employees;# 日期类型也不能用于统计,没有报错,但是没有意义

SELECT MAX(last_name),MIN(last_name) FROM employees;# 可以排序,自然就有大小之分,根据字典序
SELECT MAX(hiredate),MIN(hiredate) FROM employees;# 根据时间大小

SELECT COUNT(commission_pct) FROM employees;#count只计算非空的行
SELECT COUNT(last_name) FROM employees;

特点:

  1. sum、avg一般由于处理数值型。
    max,min,count可以处理任何类型
  2. 是否忽略null值
    所有的分组函数都是忽略null值的。
  3. 可以和distinct搭配实现去重的运算
    #和distinct搭配去重
    SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;
    SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;
    
    count 函数的详细介绍 ```sql

    count函数的的详细介绍

SELECT COUNT(salary) FROM employees; SELECT COUNT(*) FROM employees; SELECT COUNT(1) FROM employees;


- count函数的参数有上述3中,参数为字段、*、常量值
- count里面可以是多个字段,如果其中的字段都为null,才会忽略这一行,只要有一个字段的值不为null,就不是null
- count里面 * 表示所有的字段,因此在计算行数时,直接+1,不会进行判断,因为没有一行所有的字段都为null。
- count里面 1 或者是 '字符串' 相当于给每一行添加一个字段,字段的值为count里面的值,因此不会忽略任意一行
- 效率:count(*)和count(1)的效率相同,比 count(字段)要高,因为count(字段)会进行判断,看字段值是否为空。
- 一般使用 count(*) 来查询行数。

**和分组函数以同查询的字段有限制**
```sql
SELECT AVG(salary) ,employee_id FROM employees;# 虽然没有错,但是没有意义

和分组函数一同查询的字段要求是 group by 后的字段

练习

# 1.查询公司员工工资的最大值,最小值,平均值,总和
SELECT MAX(salary),MIN(salary),ROUND(AVG(salary),2),SUM(salary)
FROM employees;

# 2. 查询员工表中的最大入职时间和最小入职时间的相差天数
#SELECT YEAR(MAX(hiredate))-YEAR(MIN(hiredate))*365+MONTH() FROM employees;
# 日期相减函数
SELECT DATEDIFF(MAX(hiredate),MIN(hiredate)) FROM employees;

# 3. 查询部门编号为90的员工的个数
SELECT COUNT(*) FROM employees where department_id = 90;

注意:
函数没有SQL的可以执行强 多数 SQL 语句是可以执的,在SQL实现之间有差异时,这些差异通常不那么难处理。而函数的可以执行却不强。几乎每种主要的 DBMS 的实现都支持其他实现不支持的函数,而且有时差异还很大。