目录
1.1 多表关联查询
1.1.1 外连接查询
1.1.2 自然连接查询
1.2 子查询
1.3 SQL函数
1.3.1 聚合函数
补充:COUNT(*) 和 COUNT(1) 和 COUNT(字段名) 三者区别
COUNT(*) 和 COUNT(1)
COUNT(1) 和 COUNT(字段)
三者区别:
1.3.2 数值型函数
1.3.3 字符串函数
1.3.4 日期函数
1.3.5 流程控制函数
左外连接 | LEFT JOIN 获取相交数据+左外关键字以左表的全部数据 |
右外连接 | RIGHT JOIN 获取相交数据+右外关键字以右的全部数据 |
示例:
#左外连接
SELECT s.StudentName "姓名",s.Address "住址",g.GradeName "班级名称"
FROM grade g LEFT JOIN student s ON s.GradeID = g.GradeID;
#右外连接
SELECT s.StudentName "姓名",s.Address "住址",g.GradeName "班级名称"
FROM student s RIGHT JOIN grade g ON s.GradeID = g.GradeID;
自己和自己形成主外键关系
+------------+-----+-----------------+
| categoryId | pid | categoryName |
+------------+-----+-----------------+
| 2 | 1 | 美术设计 |
| 3 | 1 | 软件开发 |
| 4 | 3 | 数据库基础 |
| 5 | 2 | Photoshop基础 |
| 6 | 2 | 色彩搭配学 |
| 7 | 3 | PHP基础 |
| 8 | 3 | 一起学JAVA |
+------------+-----+-----------------+
假设:
1 意味着是根目录
编号 2 的美术设计 和 编号 3 的软件开发 父级都是 1 根目录
编号为 3 的数据库基础 是软件开发的一部分
SELECT c1.categoryName "父级目录",c2.categoryName "子栏目"
FROM category c1 INNER JOIN category c2 ON c1.categoryId = c2.pid;
将一个查询语句的结果充当下一个查询语句的条件 |
核心在于通过小括号以提高优先级别 |
子查询中可以包含的关键字 IN NOT ALL |
子查询中可以包含的运算符 逻辑 + 算数 |
示例:
#查询大一的男生姓名以及家庭住址
#大一对应的班级编号 --- 1
SELECT GradeID FROM grade WHERE GradeName = '大一';
#以一年级一班对应的班级编号作为线索,去查找适配的学生信息
SELECT StudentName "姓名",Address "住址"
FROM student WHERE GradeID = (SELECT GradeID FROM grade WHERE GradeName = '大一');
#加入基础条件
SELECT StudentName "姓名",Address "住址"
FROM student WHERE GradeID = (SELECT GradeID FROM grade WHERE GradeName = '大一') AND sex = 1;
#查询班级名称是大一(学生信息 ==> 学号信息),科目是高等数学-1(科目编号)的学生的平均分
#根据班级名 找出班级 编号
SELECT GradeID
FROM grade WHERE GradeName = '大一';
#根据对应的班级编号 找到适配的学生学号
SELECT StudentNo
FROM student WHERE GradeID = (SELECT GradeID
FROM grade WHERE GradeName = '大一')
#根据科目名找到对应的科目编号
SELECT subjectNo
FROM subject WHERE subjectName = '高等数学-1';
#编辑最后的命令
SELECT AVG(result.StudentResult)
FROM result
WHERE result.SubjectNo = (SELECT subjectNo
FROM subject WHERE subjectName = '高等数学-1')
AND result.StudentNo IN (SELECT StudentNo
FROM student WHERE GradeID = (SELECT GradeID
FROM grade WHERE GradeName = '大一'));
聚合函数是指对一组值进行运算,最终返回的是单个值
也可以称为 组合函数
COUNT() | 统计目标行数量的函数 |
AVG() | 求平均值 |
SUM() | 求和 |
MIN() | 求最小值 |
MAX() | 求最大值 |
注意:
除COUNT 函数之外,其他的聚合函数都会忽略 NULL 值
当表 数据量较大 的时候,对表进行检索,COUNT(1) 时效要比 COUNT(*) 慢
当表 数据量较小 的时候,对表进行检索,COUNT(1) 时效要比 COUNT(*) 快
COUNT(1) 聚索引状
COUNT(*) 自动选择索引
结论:
这两个 通常 不予比较
COUNT(1) 会统计表中所有的记录数,包含了字段为 NULL 的记录
COUNT(字段) 会忽略当前字段中出现 NULL 的情况,如果出现 NULL 值,不统计这条记录
列名<===>主键列 | COUNT(字段) > COUNT(*) > COUNT(1) |
列名!<===>主键列 | COUNT(*) || COUNT(1) > COUNT(字段) |
表多列都无主键 | COUNT(1) > COUNT(*) > COUNT(字段) |
执行效率最高的
SELECT COUNT(主键列)......
函数名称 | 作用 |
ABS() | 求绝对值 |
SQRT() | 求平方根 |
POW() 或 POWER() | 返回参数的幂次方 |
MOD() | 求余数 |
CEIL() 或 CEILING() | 向上取整 |
FLOOR() | 向下取整 |
ROUND() | 四舍五入 |
RAND | 随机生成一个数字(0~1)之间 |
示例:
#随机生成 0~99999 的数字
#随机生成一个数字 (0~1) 之间
SELECT RAND();
#将生成的随机数 *100000
SELECT RAND()*100000;
#对结果进行 FLOOR 向下取整
SELECT FLOOR(RAND()*100000);
函数名称 | 作用 |
LENGTH() | 返回字符串长度 |
CHAR_LENGTH() | 返回字符串的字节长度 |
CONCAT() | 合并字符串长度,返回结果为连续后新生成的字符串,参数可以是一个或者多个 |
INSERT(str,pos,len,new,str) | 替换字符串函数 |
LOWER() | 将字符串内所有的字符转小写 |
UPPER() | 将字符串中所有的字符转大写 |
LEFT(str,len) | 从字符串左侧进行截取,返回字符串左边若干长度的字符 |
RIGHT(str,len) | 从字符串右侧进行截取,返回字符串右边若干长度的字符 |
TRIM() | 删除字符串两次空格 |
REPLACE(str,l1,l2) | 字符串替换函数,返回替换后的新字符串 |
SUBSTRING(str,s,len) | 截取字符串,返回从指定位置开始指定长度的字符串 |
REVERSE() | 字符串逆序函数,返回余元字符串顺序相反的字符串 |
STRCMP(str1,str2) | 比较两个表达式的顺序,如果str1小于str2返回 -1 0相等 1大于 |
LOCATE(substr,str) | 返回第一次出现目标字符串的索引位 |
INSTR(substr,str) | 返回最后一次出现目标字符串的索引位 |
函数名称 | 作用 |
---|---|
CURDATE() CURRENT_DATE() CURRENT_DATE |
返回当前系统的日期值 |
CURTIME() CURRENT_TIME() CURRENT_TIME |
返回当前系统的时间 |
NOW() SYSDATE() |
返回当前系统的日期及时间 |
DATE(PAREM) | 返回指定对象的日期部分 |
TIME(PAREM) | 返回指定对象的时间部分 |
YEAR(PAREM) | 返回指定对象的年份(1970--2069) |
MONTH(PAREM) | 返回指定对象的月份 |
DAY(PAREM) | 返回指定对象的日期 |
DAYOFWEEK(PAREM) | 获取指定日期对应的一周的索引位置值,也就是星期数,注意周日是开始日,为1 |
WEEK(PAREM) | 获取指定日期是一年中的第几周,返回值的范围是否为 0〜52 |
DATEDIFF(PAREM,PAREM) | 返回两个日期之间的相差天数 |
示例:
#查询A学生和当前时间的天数差
SELECT DATEDIFF(NOW(),(SELECT BornDate FROM student WHERE StudentName = '张三'));
#根据生日查询其年龄
SELECT FLOOR(DATEDIFF(NOW(),(SELECT BornDate FROM student WHERE StudentName = '张三'))/365) AS "时差";
函数名称 | 作用 |
---|---|
IF(条件,结果1,结果2) | 判断,如果条件=true 返回结果1 反之 返回结果2 |
CASE | 搜索函数 |
IFNULL(value1,value2) | 判断,如果value1不为NULL 则函数返回值就是value1 反之 返回value2 |
示例:
SELECT IF(12,2,3);
SELECT IF(1<2,'YES','NO');
SELECT IF(STRCMP('TEST001','TEST001'),'NO','YES');
条件内 结果 true(非0的自然数) false(0)
#分别显示学生信息,有邮箱和没有邮箱的备注信息
SELECT StudentName "学生姓名",IF(Email IS NULL,'没有邮箱','存在邮箱') "是否具有邮箱"
FROM student;
#使用IFNULL,函数入参两个,如果入参不为空则返回第一个值,否则返回第二个值
SELECT IFNULL(1,2),IFNULL(NULL,2),IFNULL(9/3,2);
SELECT StudentName "学生姓名",IFNULL(Email,'没有邮箱') "邮箱地址"
FROM student;
#示例
CASE<表达式>
WHEN<值1> THEN<结果1>
WHEN<值2> THEN<结果2>
WHEN<值3> THEN<结果3>
WHEN<值4> THEN<结果4>
ELSE <默认结果>
END
#需求 查询成绩表 限定考试科目 高等数学-1
# 要求如下 如果学号是1000 显示成绩为原成绩的 1.5倍
# 要求如下 如果学号是1001 显示成绩为原成绩的 1.3倍
# 要求如下 如果学号是1002 显示成绩为原成绩的 1.1倍
# 要求如下 其他学生成绩显示原成绩
#1---查出高数-1的科目编号
SELECT SubjectNo FROM subject WHERE SubjectName = '高等数学-1';
#2---通过科目编号找到学生的考试成绩
SELECT * FROM result WHERE SubjectNo = (SELECT SubjectNo FROM subject WHERE SubjectName = '高等数学-1');
#3---通过CASE语法修改并查看参数
SELECT StudentNo "学号",StudentResult "原成绩",
CASE StudentNo
WHEN 1000 THEN StudentResult*1.5
WHEN 1001 THEN StudentResult*1.3
WHEN 1002 THEN StudentResult*1.1
ELSE StudentResult
END "修改后的成绩"
FROM result
WHERE SubjectNo = (SELECT SubjectNo FROM subject WHERE SubjectName = '高等数学-1');