九天猎人 发表于 2024-6-13 21:06:09

数据库的基本操作

基础知识

   1. 数据库是什么?

   步伐在运行的过程中,数据都是在内存中存储的
   https://img-blog.csdnimg.cn/img_convert/7553df70e9bd7ef82f28bc34797729ed.png
   ,但是内存一旦断电就会丢失数据。因此需要持久生存的数据会转交给硬盘。
   https://img-blog.csdnimg.cn/img_convert/6885713253d5b25b1f56673dfe0be6da.png
   在编程领域,最常用的方式是使用数据库批量的存储大量数据到硬盘。也就是说,数据库是一种电子化的资料柜。
   数据库产物非常多,主流的包括:MySQL、SQLite、Oracle......这些不同的数据库都是由不同的软件公司开辟而来,每种数据库各有差异。IBM公司针对市面上各种不同厂家的数据库推出了统一的操作语言——SQL语言(语句)。
   嵌入式领域中最常用的数据库产物是SQLite,本次学习的数据库就是SQLite。
   SQLite是一款轻量级的数据库
   https://img-blog.csdnimg.cn/img_convert/5dd63ccc42cc4d26005e772ae3e5605c.png
   ,只需要数兆的体积,免安装即可使用,因此许多嵌入式相关的技术框架都会内置SQLite数据库。
   2. 操作环境

   本次学习为了简化操作,使用SQLiteSpy软件作为开辟环境,软件的布局如下。
   https://img-blog.csdnimg.cn/img_convert/71495a441e140c17b0e57b979aae26d4.png
   SQLite数据库是以单文件进行存储的,一个数据库就是一个文件,文件的格式是.db或.db3,只需要使用SQLiteSpy软件打开.db或.db3文件即可。
   https://img-blog.csdnimg.cn/img_convert/725a7cc292bad6138a5f040588905dbf.png
   打开之后可以看到有四张表:dept、emp、salgrade和bonus。
   如果把数据库文件看做是excel文件,上面的四张表就相当于excel中的sheet。
   3. 数据库操作类型

   IBM把SQL语句分为以下几类:
   

[*]DML(数据操作语言)
   主要指的是数据的查询(DQL)和更新(增编削)操作,这是本次学习的重点。
   

[*]DDL(数据界说语言)
   用于界说数据库对象,主要用于筹划数据库表的布局。
   

[*]DCL(数据控制语言)
   用于控制数据库操作权限,一样平常用于高级的数据库,会由公司的数据库管理员负责。
   4. 查看数据表

   在SQLiteSpy软件中,只需要双击表名,就可以查询到表中的内容。
   下面依次先容四张表。
   4.1 dept表

   存储公司的部门信息。
   https://img-blog.csdnimg.cn/img_convert/0cd238b422db5718adf36ee417e5ff1e.png
   整理表布局如下所示。
   https://img-blog.csdnimg.cn/img_convert/48e40777434ef971a510ab17ef4d88bc.png
   SQLiteSpy软件双击表名查询内容,现实上是实行了下面的语句。
   
   SELECT * FROM dept;
   
   把上面的语句粘贴到SQLiteSpy实行区域,手动实行也会有相同的效果。
   https://img-blog.csdnimg.cn/img_convert/964f551bab44c58a97880e481c74b893.png
   编写SQL语句也可以在其它软件中进行,例如Notepad++,只需要切换到SQL模式即可。
   https://img-blog.csdnimg.cn/img_convert/86c9c204635ed4b02a10cfff847ab71d.png
   4.2 emp表

   emp表是雇员表,记录了公司里员工的信息。
   https://img-blog.csdnimg.cn/img_convert/37f607f2752d7a3c0ba8b93ab0f262d4.png
   整理表布局如下所示。
   https://img-blog.csdnimg.cn/img_convert/dcab8eea3e58358aaebaa861a2bf8a7c.png
   4.3 salgrade表

   salgrade表是工资品级表。
   https://img-blog.csdnimg.cn/img_convert/8c4ef3b151c8e6e5e626f00acef26701.png
   https://img-blog.csdnimg.cn/img_convert/e07e110be0cc140280fad1b6376053ff.png
   4.4 bonus表

   bonus表是奖金表。
   https://img-blog.csdnimg.cn/img_convert/bf6509f725ca1791e90c01ec45b5cef3.png
   bonus表是一张空表,只有表布局,没有内容。
   5. 需要记着的内容

    内容
掌握程度
表名
英汉互译
列名
英汉互译
员工的职位job对应的值
英译汉
   
      一、单表查询

这个篇章主要解说的是在一个表中进行数据查询。
1. 简单查询(列查询)

简单查询的效果中包罗全部的条目(行),依次展示每条数据,唯一能做的是限制表中出现的列。
https://img-blog.csdnimg.cn/img_convert/1f6c70b82702d585b17414eaa4e497e0.png
语法布局如下。
https://img-blog.csdnimg.cn/img_convert/95d924ebd558e85f204d091a6823cc99.png
其中[]表示可选填内容
DISTINCT表示去掉重复行的数据
*表示查询全部的列,如果不想查询全部列,则编写详细的列名称。
【例子】查询全部雇员的编号(empno)、姓名(ename)、职位(job)、基本工资(sal)。

SELECT empno,ename,job,sal FROM emp
;

https://img-blog.csdnimg.cn/img_convert/b2cfc507c39fb39bb5e1bcf90f548b79.png
【例子】查询每个雇员的编号、姓名和基本年薪(基本月薪x12)

SELECT empno,ename,sal*12 FROM emp
;

也可以更改显示的表名,如下所示。

SELECT empno 编号,ename 姓名,sal*12 年薪 FROM emp
;

https://img-blog.csdnimg.cn/img_convert/171c6d94ad3633a21ce54fc7e1dc85bc.png

【例子】查询每个雇员的编号、姓名、职位、年薪,每个雇员每个月有200元餐补、200元交通补助、夏天四个月有每月300元高温补贴,年底多发3个月基本工资。

SELECT empno,ename,job,12*(sal+400)+4*300+3*sal income
FROM emp
;

https://img-blog.csdnimg.cn/img_convert/7d0f3165d9c781618687b47e7a318d19.png
【例子】查询全部雇员的职位有哪些。
可能会写出这样的语句。

SELECT job FROM emp
;

https://img-blog.csdnimg.cn/img_convert/2a279c836411d9926895fad1cd3a5413.png
现实上此题消除重复项更为合适,可以增长DISTINCT。

SELECT DISTINCT job FROM emp
;

https://img-blog.csdnimg.cn/img_convert/6a9378a701f7086ee67ead0128fb9e65.png
需要注意的是,只有全部内容都重复才算重复项。
2. 限定查询

限定查询是在简单查询的基础上限制显示的条数(行数),其语法格式如下。
https://img-blog.csdnimg.cn/img_convert/9140fde495bad0276d169a86e435894d.png
主要通过WHERE子句限制行数,支持六种运算:


[*]关系运算
[*]取值范围运算
[*]基数范围运算
[*]暗昧查询
[*]空判断
[*]逻辑运算
2.1 关系运算

关系运算是最简单的运算符号,包括:
>、<、>=、<=、!=、<>(不等于)、==
【例子】查询公司工资高于2000的员工信息。

SELECT * FROM emp
WHERE sal>2000;

https://img-blog.csdnimg.cn/img_convert/d80f3bcfc9f1cc04485ed85700f2bf88.png
【练习】
1.查询基本工资小于1600的全部雇员信息

SELECT * FROM emp
WHERE sal<1600;

2.查询姓名是SMITH的雇员信息

SELECT * FROM emp
WHERE ename=='SMITH';

文本数据要使用双引号或单引号包裹,建议在数据库中使用单引号,在编程中时使用双引号。
3.查询全部职位不是贩卖人员的信息

SELECT * FROM emp
WHERE job != 'SALESMAN';

2.2 取值范围运算

取值范围运算使用BETWEEN...AND...
可以表示两个数的范围区间,这个区间是闭区间,包罗两头。
【例子】查询全部在1981年雇佣的雇员信息。
分析:1981年1月1日-1981年12月31日

SELECT * FROM emp

WHERE hiredate BETWEEN '1981-01-01' AND '1981-12-31';

https://img-blog.csdnimg.cn/img_convert/ab8ee980545387109cf9df35581f80aa.png
【练习】查询工资范围在1200-3000之间的雇员姓名和职位。

SELECT ename,job FROM emp
WHERE sal BETWEEN 1200 AND 3000;

2.3 基数范围运算

基数范围运算使用IN关键字,表示符合给定的多个数字之一。
【例子】查询出雇员编号为7369、7566、7839、8899(不在)的雇员信息。

SELECT * FROM emp
WHERE empno IN (7369,7566,7839,8899);

https://img-blog.csdnimg.cn/img_convert/01a774519eaf6d8626279682e068af8b.png
如果一个数据没有,可以使用NULL表示,IN给的待选数据中不允许出现NULL,NULL是一种特殊的数据状态,需要使用专用语句进行判断。
2.4 暗昧查询

暗昧查询可以制定查询的格式,无需进行完备的内容匹配,主要使用LIKE关键字,共同两个符号进行标志。


[*]_
英文下划线,表示恣意一个字符。


[*]%
百分号,表示恣意多个(0,1,2,......,n)字符。
【例子】查询全部姓名是A开头的雇员信息。

SELECT * FROM emp
WHERE ename LIKE 'A%';

https://img-blog.csdnimg.cn/img_convert/dc24047e232373d245d01bd2056c5dc6.png
【练习】
1. 查询全部姓名第二个字母是A的全部雇员信息

SELECT * FROM emp
WHERE ename LIKE '_A%';

2. 查询姓名中包罗A的全部雇员的信息

SELECT * FROM emp
WHERE ename LIKE '%A%';

2.5 空判断

NULL是一种特殊的数值,使用IS NULL来进行判断。
在数据库中,反转逻辑效果使用NOT关键字,IS NULL的反转格式有两种:


[*]NOT IS NULL
[*]IS NOT NULL
【例子】查询不领取佣金(comm)的雇员信息。

SELECT * FROM emp
WHERE comm IS NULL;

https://img-blog.csdnimg.cn/img_convert/4611d7e66335c5880b839a62932abad7.png
【例子】查询领取佣金的雇员信息。

-- 注意NOT的位置
SELECT * FROM emp
WHERE NOT comm IS NULL;


SELECT * FROM emp
WHERE comm IS NOT NULL;

https://img-blog.csdnimg.cn/img_convert/1e9652c804a0ef67570da21b74285056.png
2.6 逻辑运算

计算机中都有逻辑运算:与或非。
与:全部的条件都满足,效果才满足,在数据库中与使用AND表示。
或:只要满足一个条件,效果就满足,在数据库中或使用OR表示。
非:效果反转,在数据库中非使用NOT表示。
【例子】查询全部工资高于1300的贩卖信息。
分析:需要同时满足职位是贩卖 且 工资大于1300

SELECT * FROM emp
WHERE job='SALESMAN' AND sal>1300;

https://img-blog.csdnimg.cn/img_convert/f3c681a8fe87dcb5d5cd51170ef177e6.png
【练习】
1. 查询出工资范围不在1200~1300(闭区间)之间的员工信息。

SELECT * FROM emp
WHERE sal NOT BETWEEN 1200 AND 1300;

2. 查询出10部门的经理信息。

SELECT * FROM emp
WHERE deptno=10 AND job='MANAGER';

3. 查询出工资高于3000,或者职位是柜员的全部雇员信息。

SELECT * FROM emp
WHERE job='CLERK' OR sal>3000;

4. 查询出全部职位不是柜员的信息

SELECT * FROM emp
WHERE NOT job='CLERK';

3. 查询排序

SQLiteSpy提供了一键排序的功能,只需要点击表名就可以切换次序或倒序排序的方式。
https://img-blog.csdnimg.cn/img_convert/1418a17e9efe9516a0ebd9e71920b634.png
由于以后数据库是在代码中操作的,因此仍然需要学习语法规则,查询排序的语法布局如下所示。
https://img-blog.csdnimg.cn/img_convert/a9cb8c8cd16bb94aed89571a8206ebeb.png
两种排序的方式:


[*]升序 ASC
[*]降序 DESC
【例子】查询全部雇员的信息,要求按照工资从高到低排序。
分析:只要是排序题,排序永世是最后一步。

SELECT * FROM emp
ORDER BY sal DESC
;


https://img-blog.csdnimg.cn/img_convert/e97137fdc1e194d74ebfecf0fdfb1530.png
可以看到有的人工资是一样,排序支持多个字段排序,如果第一字段值相同,则使用第二字段值的排序规则。
【例子】查询全部雇员的信息,要求按照工资从高到低排序,如果工资相同,则按照雇佣日期从早到晚排序。

SELECT * FROM emp
ORDER BY sal DESC
,hiredate ASC;

https://img-blog.csdnimg.cn/img_convert/5618724412c8aeeca7552bf28eb08023.png
【练习】
1. 查询全部雇员的信息,效果按照年薪(基本工资x12)排序,年薪越高的越靠前。
注意:SELECT中出现了*之后,不允许写其他列名。

SELECT empno,ename,job,mgr,hiredate,sal*12 sal,comm,deptno
FROM emp
ORDER BY sal DESC


2. 查询全部柜员的信息,同时按照工资从高到低排序。

SELECT * FROM emp
WHERE job='CLERK' ORDER BY sal DESC
;

3. 查询全部20部门的雇员信息,要求按照雇员日期从晚到早排序。

SELECT * FROM emp
WHERE deptno=20 ORDER BY hiredate DESC;

4. 查询全部10部门和30部门的雇员信息,要求按照雇员编号降序排序。

SELECT *
FROM emp

WHERE deptno=10 OR deptno=30
ORDER BY empno DESC;

4. 练习


--1. 查询部门30的所有员工信息。
SELECT * FROM emp
WHERE deptno=30;

--2. 列出所有柜员(CLERK)的姓名、编号和部门编号。
SELECT ename,empno,deptno FROM emp
WHERE job='CLERK';

--3. 找出部门30中所有经理和部门20中所有柜员的详细资料。
SELECT * FROM emp

WHERE deptno=30 AND job='MANAGER' OR deptno=20 AND job='CLERK';

--4. 收取佣金的职位有哪些?
SELECT DISTINCT job FROM emp
WHERE comm IS NOT NUll;

--5. 查询不收取佣金或佣金低于100的员工信息。
SELECT * FROM emp
WHERE comm IS NULL OR comm<100;

5. 分页查询

为了更好地显示大量的数据,可以一次性只展示一部分数据,采用多页的形式,这种查询就是分页查询。
SQLite中使用LIMIT子句与OFFSET子句限制查询的返回数量,实现分页查询,语法格式如下。
https://img-blog.csdnimg.cn/img_convert/7d6c32033b24363bb44aedfdd71d2fac.png
其中LIMIT表示效果的数量,OFFSET表示扬弃前几条记录,可以视环境使用。
【例子】
1. 查询前五个雇员的信息。

SELECT * FROM emp
LIMIT 5;

https://img-blog.csdnimg.cn/img_convert/c0d29aab838d2004e4a4b4a38e2342f8.png
2. 查询工资薪水最高的三个雇员信息。
分析:讲课过程中不会把分页查询加入到最基础的子句次序中,但是现实上其实行次序在ORDER BY之后,全部分页查询题可以先不考虑分页的问题。
此题可以先变为“查询全部人的信息,按照工资降序排布”

SELECT * FROM emp
ORDER BY sal DESC
;


最后,筛选出前三个数据。

SELECT * FROM emp
ORDER BY sal DESC
LIMIT 3;

3. 查询公司前一半雇佣(早期雇佣)的雇员信息。

SELECT * FROM emp
ORDER BY hiredate ASC LIMIT 7;

此题能做出的条件是已知14人,如果对总人数未知,则需要先获得总人数。总人数的获取在后续课程中会先容相关的函数。
4. 查询公司薪金第四名到第八名的雇员信息。

--查询公司全部雇员的信息,按照薪金从高到底排序。SELECT * FROM emp
ORDER BY sal DESC
;

--生存五个人SELECT * FROM emp
ORDER BY sal DESC
LIMIT 5;--向后移动三个人SELECT * FROM emp
ORDER BY sal DESC
LIMIT 5 OFFSET 3;
【练习】
1. 查询公司员工编号前5个员工的员工编号和姓名。

SELECT empno,ename FROM emp
ORDER BY empno ASC LIMIT 5;

2. 查询全部雇员的信息,要求显示工资最低的三个人。

SELECT * FROM emp
ORDER BY sal ASC LIMIT 3;

3. 查询公司最早雇佣的三个人的信息。

SELECT * FROM emp
ORDER BY hiredate LIMIT 3;

4. 查询公司工资第6-10名的雇员信息。

SELECT * FROM emp
ORDER BY sal DESC
LIMIT 5 OFFSET 5;

真正要使用分页查询可以基于以下的公式:
设每页显示的条数为n,当前页码为m,得分页查询公式为:

SELECT * FROM 表名 LIMIT n OFFSET (m-1)*n;

【例子】每页显示6条数据,查询第二页的内容。
分析:n=6,m=2

SELECT * FROM emp
LIMIT 6 OFFSET 6;

【练习】
1. 每页显示3条数据,查询第五页的内容。

SELECT * FROM emp
LIMIT 3 OFFSET 12;

2. 每页显示5条数据,分别查询每一页的内容。

SELECT * FROM emp
LIMIT 5;
SELECT * FROM emp
LIMIT 5 OFFSET 5;SELECT * FROM emp
LIMIT 5 OFFSET 10;
3. 取出emp表中9-12行的数据。

SELECT * FROM emp
LIMIT 4 offset 8;

4. 假设京东显卡的数据库表名为xianka,每页显示60条数据,查询第12页的数据。

SELECT * FROM xianka LIMIT 60 offset 660;
       二、函数

   函数是计算步伐中一段预先设置好的功能,可以满足反复调用的需求。SQLite中提供了众多函数,本次选取一些常见的函数进行解说。
   https://img-blog.csdnimg.cn/img_convert/6204bcee545cb87ea091ab5320ca7edb.png
   一个函数只需要关注三个部分:
   

[*]输入参数:需要什么数据
[*]函数名称:如何处置惩罚数据
[*]返回值:处置惩罚后的效果是什么
   1. 字符串函数

   用于处置惩罚TEXT类型的数据。
   1.1 巨细写转换函数

   

[*]UPPER
   输入参数:英文的字符串
   函数名称:转换大写
   返回值:转换大写后的字符串
   

[*]LOWER
   输入参数:英文的字符串
   函数名称:转换小写
   返回值:转换小写后的字符串
   【例子】
   1. 把'Hello'转换为全大写和全小写。
   
   SELECT UPPER('Hello'),LOWER('Hello');
   
   https://img-blog.csdnimg.cn/img_convert/4898cd48504e02ad07906a008df90443.png
   2. 查询全部雇员的姓名,要求姓名全小写。
   分析:先查询全部雇员的姓名,最后套用转大写函数。
   
   SELECT LOWER(ename) FROM emp
;
   
   https://img-blog.csdnimg.cn/img_convert/f601e25053e9f9a998cbb543e9b284e7.png
   【练习】
   1. 查询全部雇员的姓名和职务,要求全部字母小写。
   
   SELECT LOWER(ename),LOWER(job) FROM emp
;
   
   2. 查询全部部门的名称,要求全部字母小写。
   
   SELECT LOWER(dname) FROM dept;
   
   1.2 去除左右空格

   TRIM
   

[*]输入参数:字符串
[*]函数名称:去除字符串前后的空格
[*]返回值:处置惩罚后的字符串
   【例子】去除' hello world '前后的空格。
   
   SELECT TRIM('       hello world       ');
   
   https://img-blog.csdnimg.cn/img_convert/07b7cb4df5ce57f39de56c5756b813d7.png
   2. 数字函数

   2.1 四舍五入

   ROUND
   

[*]输入参数1:数字
[*]输入参数2:生存的小数位,可省略,省略默认为生存整数位
[*]函数名称:四舍五入
[*]返回值:四舍五入后的数字
   【例子】将123.456四舍五入生存两位小数。
   
   SELECT ROUND(123.456,2);
   
   https://img-blog.csdnimg.cn/img_convert/e7d2cb6f81d282c9f11a7aee05beb353.png
   2.2 取模

   可以简单地认为取模运算就是取余。
   MOD
   输入参数1:被除数
   输入参数2:除数
   函数名称:求模
   返回值:计算后的数字
   【例子】求出10对4取模的效果。
   分析:即求出10除以4的余数。
   
   SELECT MOD(10,4);
   
   https://img-blog.csdnimg.cn/img_convert/56106feb20d6c50158729aba3a77c1e1.png
   2.3 绝对值

   ABS
   输入参数:数字
   函数名称:绝对值
   返回值:取绝对值之后的数字
   【例子】求出-23的绝对值
   
   SELECT ABS(-23);
   
   https://img-blog.csdnimg.cn/img_convert/b0e36a49a933d4dd72ea79c4952546d3.png
   3. 日期函数

   3.1 提取函数

   DATE
   

[*]输入参数:符合格式的日期时间字符串
[*]函数名称:只提取日期
[*]返回值:只包罗日期的字符串
   【例子】查询全部雇员的雇用日期,要求不显示时间。
   
   SELECT DATE(hiredate) FROM emp
;
   
   https://img-blog.csdnimg.cn/img_convert/3ee37db7205ae5540b2c68c61f867fb8.png
   同理,也可以只显示时间,使用下面的函数。
   TIME
   

[*]输入参数:符合格式的日期时间字符串
[*]函数名称:只提取时间
[*]返回值:只包罗时间的字符串
   也可以都显示,使用下面的函数。
   DATETIME
   

[*]输入参数:符合格式的日期时间字符串
[*]函数名称:提取时间和日期
[*]返回值:包罗日期和时间的字符串
   3.2 获取本地时间

   也可以使用DATETIME、DATE或TIME提取本地时区的当前时间和日期。
   函数还是3.1中的三个函数,但是参数换为以下两个参数
   输入参数1:'now'
   输入参数2:'localtime'
   【例子】获得当前时区的时间和日期。
   
   SELECT DATE('now','localtime'),TIME('now','localtime'),DATETIME('now','localtime');
   
   https://img-blog.csdnimg.cn/img_convert/354d28a287a8c35cfa14b7a7965c5da2.png
   上面的函数还可以省略第二个参数'localtime',表示基于国际尺度时间(格林威治时间)。
   
   SELECT DATE('now'),TIME('now'),DATETIME('now') FROM emp
;
   
   https://img-blog.csdnimg.cn/img_convert/2ef7b063cb5ed00135072b57986156a4.png
   3.3 儒略日

   儒略日(Julian Day)是公元前4713年1月1日。
   JULIANDAY
   输入参数:'now'或一个日期
   函数名称:计算机输入日期与儒略日的差值,单位天
   返回值:相差的天数,精确到小数
   【例子】求出每个雇员的姓名和雇佣年龄。
   
   SELECT ename,(JULIANDAY('now')- JULIANDAY(hiredate))/365 FROM emp
;
   
   https://img-blog.csdnimg.cn/img_convert/d3e5218abec33ce25675d090fe9f15bf.png
   也可以直接使用日期作差:
   
   SELECT ename,DATE('now')-DATE(hiredate) FROM emp
;
   
   3.4 时间格式化

   可以通过STRFTIME函数提取需要的时间或日期数据。
   输入参数1:格式,如下所示。
   https://img-blog.csdnimg.cn/img_convert/824edc069183d7df28112e45d54e6d3f.png
   输入参数2:基于哪个日期时间
   返回值:提取的数据,需要注意返回的数据是文本,例如'12'
   【例子】查询1月雇佣的雇员信息。
   分析:先提取月份,再比对。
   
   -- 注意STRFTIME返回值的TEXT,文本与文本比对,更改为'01'
SELECT * FROM emp
WHERE STRFTIME('%m',hiredate)='01';
   
   
   -- 也可以把等式左边的数值转换为数字
SELECT * FROM emp
WHERE CAST(STRFTIME('%m',hiredate) AS DECIMAL)=1;
   
   【练习】
   1. 现在是几点几分(可以使用任何时区)。
   
   SELECT STRFTIME('%H:%M',TIME('now','localtime'));
   
   2. 查询在上半年雇佣的雇员信息。
   
   SELECT * FROM emp

WHERE STRFTIME('%m',HIREDATE) IN ('01','02','03','04','05','06');
   
   
   SELECT * FROM emp
WHERE STRFTIME('%m',hiredate) <= '06';
   
   3. 查询在每个月1号雇佣的雇员信息。
   
   SELECT * FROM emp

WHERE CAST(STRFTIME('%d',hiredate)AS DECIMAL)=01;
   
   4. 查询在1981年雇佣的雇员信息。
   
   SELECT * FROM emp
WHERE STRFTIME('%Y', hiredate)= '1981';
   
   
   SQLite数据库相比于其它数据库,处置惩罚日期和时间的能力较弱。
   4. 空值函数

   【例子】查询全部雇员的姓名和月收入(薪金+佣金)。
   
   SELECT ename,sal+comm FROM emp
;
   
   https://img-blog.csdnimg.cn/img_convert/3bb12d236280a0981e865fe1d47548c3.png
   可以发现,任何数字与NULL进行数学计算,效果都会同化为NULL。空值函数IFNULL就是用来处置惩罚这种问题的,可以把NULL等效为某个数字。
   输入参数1:可能为空的数据
   输入参数2:等效数字
   函数名称:如果参数1为NULL,则更换为参数2的等效数字;如果参数1不为NULL,不进 行更换。
   返回值:处置惩罚后数值(要么是NULL等效后的数字,要么原数字)
   
   给当前上面的SQL语句套入空值处置惩罚函数,如下所示。
   
   SELECT ename,sal+IFNULL(comm,0) FROM emp
;
   
   【练习】
   计算全部雇员的姓名和年薪,如果不领取佣金,则每个月发400的补助。
   
   SELECT ename,(sal+IFNULL(comm,400))*12 FROM emp
;
                           

      
      
             
       5. 统计函数

       常用的统计函数包括:
      

[*]计数
       COUNT
      

[*]求和
       SUM
      

[*]均匀值
       AVG
      

[*]最大值
       MAX
      

[*]最小值
       MIN
       这五个函数的输入参数都是一些数据列(通常为数字类型,COUNT可以支持非数字类型),返回值都是统计后的数字。
       【例子】查询公司的均匀工资、人数、每个月员工基本工资成本,最高工资和最低工资,工资只算基础工资。
      
       SELECT AVG(sal),COUNT(*),SUM(sal),MAX(sal),MIN(sal) FROM emp
;
      
       https://img-blog.csdnimg.cn/img_convert/102aef0cd2b517f0c89f1c3c39c7f119.png
       练习:
       1. 求出公司最早和最晚的雇佣日期。
      
       SELECT MIN(hiredate),MAX(hiredate) FROM emp
;
      
       2. 求出公司20部门最高的工资。
      
       SELECT MAX(sal) FROM emp
WHERE deptno=20;
      
       3. 求出全部经理中最高的工资。
      
       SELECT MAX(sal) FROM emp
WHERE job='MANAGER';
      
       4. 求出全部贩卖的均匀基本工资。
      
       SELECT AVG(sal) FROM emp
WHERE job='SALESMAN';
      
       5. 求出全部柜员的数量。
      
       SELECT COUNT(*) FROM emp
WHERE job='CLERK';
      
       【例子】COUNT(*)、COUNT(列名)、COUNT(DISTINCT 列名)的区别。
       COUNT(*)表示使用全部列作为一条数据有效性的依据,即一条数据只要有任何一列有数据,就到场计数。
       COUNT(列名)不会对输入列出现NULL的环境计数,重复的数据分别计数。
       COUNT(DISTINCT 列名)只会统计输入列且不重复的次数,重复的数据只管帐数一次。
      
      
      
                                       四、多表查询

      之前的查询都是基于一张表进行的,本章多表查询指的是基于多张表进行查询,主要是针对FROM子句进行拓展。
      更改之前的语法格式为:
      https://img-blog.csdnimg.cn/img_convert/05b7ab19fcad463c6d7700c066492c9a.png
      1. 原理

      【例子】分别统计emp表和dept表的数据量。
      
      SELECT COUNT(*) FROM emp
;
      
      https://img-blog.csdnimg.cn/img_convert/edc2efd09d3d986fb67390bd8f8c12fa.png
      
      SELECT COUNT(*) FROM dept;
      
      https://img-blog.csdnimg.cn/img_convert/e857ecfb54d4c6f141492abeb4bc9932.png
      【例子】同时对emp表与dept表统计数据量。
      
      SELECT COUNT(*) FROM emp
,dept;
      
      https://img-blog.csdnimg.cn/img_convert/7d86a9e4dc72c6cbd6d34a1814b8e250.png
      可以看到56=14x4,两张表相乘了,这种环境被称为笛卡尔积。
      https://img-blog.csdnimg.cn/img_convert/a3750b626b850ae2be4340585808471f.png
      每个雇员的数据在内部都会尝试跟各个部门的数据联合,但是在联合的过程中,由于雇员只能有一个部门,因此只有一个联合是有效的,其它三个联合的数据都是无效数据。
      直接进行两个表的查询,可以看到这些联合的数据。
      https://img-blog.csdnimg.cn/img_convert/d3c7497a7bb2723c4dece3b3074dfa53.png
      多表查询一定要消除无效的笛卡尔积,使用WHERE子句通过关联列的等值关系可以消除无效数据,在上面的例子中这个关联列就是部门号deptno,即只需要判断两个表的deptno是否相等即可。
      
      SELECT * FROM emp
,dept WHERE emp.deptno=dept.deptno;
      
      https://img-blog.csdnimg.cn/img_convert/c572a0fa9b135186546ec9f0374c7d74.png
      也可以通过下面的写法进行改善。
      
      -- 起别名
SELECT * FROM emp
e,dept d
WHERE e.deptno=d.deptno
;
      
      【例子】查询全部雇员的编号,姓名,职位,工资,部门编号,部门名称,部门位置。
      分析:
      第一步,确定FROM子句。
      emp表:empno,job,sal,deptno
      dept表:dname,loc
      
      FROM emp
e,dept d
      
      第二步,如果是多表查询,确定多表之间的关系,消除笛卡尔积。
      
      WHERE e.deptno=d.deptno
      
      第三步,查看全部人还是一部分人,如果是一部分人,则继承使用WHERE子句筛选。
      第四步,确定SELECT子句。
      
      SELECT empno,job,sal,deptno,dname,loc
      
      第五步,确定ORDER BY子句。
      第六步,拼接SQL语句,拼接时注意多表的公共列。
      
      SELECT empno,job,sal,e.deptno,dname,locFROM emp
e,dept d
WHERE e.deptno=d.deptno
;      
      https://img-blog.csdnimg.cn/img_convert/2cbe98d5a23e1b8a6178fcdd6304d508.png
      

                      3. 非等式关联

    多表之间建立关联并非一定需要等式关系。
    【例子】查询出每个雇员的编号,姓名,职位,基本工资,雇佣日期,工资品级,效果按照基本工资从高到低排序。
    分析:
    第一步,确定FROM子句。
    emp表:empno,ename,job,sal,hiredate
    salgrade表:grade
   
    FROM emp
e,salgrade s
   
    第二步,如果是多表查询,确定多表之间的关系,消除笛卡尔积。
   
    WHERE e.sal BETWEEN s.losal AND s.hisal
   
    第三步,查看全部人还是一部分人,如果是一部分人,则继承使用WHERE子句筛选。
    第四步,确定SELECT子句。
   
    SELECT empno,ename,job,sal,hiredate,grade
   
    第五步,确定ORDER BY子句。
   
    ORDER BY sal DESC
   
    第六步,拼接SQL语句,拼接时注意多表的公共列。
   
    SELECT empno,ename,job,sal,hiredate,grade
FROM emp
e,salgrade s
WHERE e.sal BETWEEN s.losal AND s.hisal
ORDER BY sal DESC
;   
    https://img-blog.csdnimg.cn/img_convert/ce52d7701976951616df7384c086c37e.png
    【思考】查询每个雇员的编号、姓名、职位、雇佣日期、工资、工资品级、所在部门以及位置。
    分析:
    第一步,确定FROM子句。
    emp表:empno,ename,job,hiredate,sal,deptno
    salgrade表:grade
    dept表:loc
   
    FROM emp
e,salgrade s
,dept d   
    第二步,如果是多表查询,确定多表之间的关系,消除笛卡尔积。
   
    WHERE sal BETWEEN losal AND hisal AND e.deptno=d.deptno
   
    第三步,查看全部人还是一部分人,如果是一部分人,则继承使用WHERE子句筛选。
    第四步,确定SELECT子句。
   
    SELECT empno,ename,job,hiredate,sal,deptno,grade,loc
   
    第五步,确定ORDER BY子句。
    第六步,拼接SQL语句,拼接时注意多表的公共列。
   
    SELECT empno,ename,job,hiredate,sal,e.deptno,grade,locFROM emp
e,salgrade s
,dept dWHERE sal BETWEEN losal AND hisal AND e.deptno=d.deptno
;   
    https://img-blog.csdnimg.cn/img_convert/bc696966b0f328c40fdc2b3ed2b64c7c.png
    4. 连接方式

    多表查询有不同的连接方式,可以分为:
    https://img-blog.csdnimg.cn/img_convert/3bd80299427eb73fd450b718c904474e.png
    但是SQLite数据库有些功能不支持:
    右外连接与全外连接是不支持
    4.1 内连接

    之前的篇章使用的多表查询就是内连接,且使用的基于SQL89尺度的语法,除此之外常用的写法还有SQL99尺度。
    【例子】查询全部雇员的姓名和部门名称。
   
    -- SQL89SELECT ename,dname FROM emp
e,dept d
WHERE e.deptno=d.deptno
;   
   
    -- SQL99
SELECT ename,dname FROM emp
e JOIN dept d ON e.deptno=d.deptno;
   
    4.2 外连接

    为了更好地观察内连接与外连接的区别,需要在emp表增长一个没有部门的雇员。
   
    INSERT INTO emp(empno,ename,job,hiredate,sal)
VALUES(6666,'JASON','MANAGER',DATETIME('now'),10000);
   
    https://img-blog.csdnimg.cn/img_convert/0846ee48ceb84281936e372b45b4904b.png
    emp表中就有15个雇员了。
    此时再次实行4.1节中的内连接语句。
    https://img-blog.csdnimg.cn/img_convert/06f02b943ed25f5c7271d42762559414.png
    可以发现少了一个人的数据,由于JASON的deptno为NULL,所以不满足部门号相等的条件。为了让没有部门的雇员显示,需要改为外连接。
    SQLite只支持基于SQL99尺度的左外连接:
   
    -- LEFT表示让左边的表完整显示
SELECT ename,dname FROM emp
e LEFT JOIN dept d ON e.deptno=d.deptno;
   
    https://img-blog.csdnimg.cn/img_convert/ff07cb0fc9fd9e68e1819a71bf685826.png
    【练习】
    查询全部雇员的姓名、月综合收入(sal+comm)与位置,要求显示全部雇员的信息。
   
    SELECT ename,sal+IFNULL(comm,0),loc
FROM emp
LEFT JOIN dept ON emp.deptno=dept.deptno;
             4.3 自连接

   自连接是一种特殊环境,表示多表查询的过程使用多次同一张表。
   【例子】查询每个雇员的编号、姓名、职位、领导姓名。
   分析:
   第一步,确定FROM子句。
   emp表(雇员表):empno,ename,job
   emp表(领导表):ename
   
   FROM emp
e JOIN emp m
   
   第二步,如果是多表查询,确定多表之间的关系,消除笛卡尔积。
   https://img-blog.csdnimg.cn/img_convert/f24caefdd005a2ca0816eeced8f2d981.png
   
   ON e.mgr=m.empno
   
   第三步,查看全部人还是一部分人,如果是一部分人,则继承使用WHERE子句筛选。
   第四步,确定SELECT子句。
   
   SELECT empno,ename,job,ename
   
   第五步,确定ORDER BY子句。
   第六步,拼接SQL语句,拼接时注意多表的公共列,自连接的每列都是公共列。
   
   SELECT e.empno,e.ename,e.job,m.enameFROM emp
e JOIN emp m
ON e.mgr=m.empno
;   
   https://img-blog.csdnimg.cn/img_convert/458d992781300edb0c4d0a8a2a3f2a9b.png
   第七步,确定是否使用外连接。
   
   SELECT e.empno,e.ename,e.job,m.enameFROM emp
e LEFT JOIN emp m ON e.mgr=m.empno
;   
   https://img-blog.csdnimg.cn/img_convert/1d3179a86c62a3619de361a84d72bb60.png
   【思考】查询全部雇员的姓名、工资品级,以及他们的领导的姓名。
   
   SELECT e.ename,grade,m.enameFROM emp
e LEFT JOIN salgrade s ON e.sal BETWEEN s.losal AND s.hisalLEFT JOIN emp m ON e.mgr=m.empno
;   
   5. 其它连接写法

   5.1 交叉连接

   能够产生笛卡尔积,以下两种写法等效。
   
   SELECT * FROM emp
CROSS JOIN dept;
SELECT * FROM emp
,dept;
   
   5.2 天然连接

   可以主动找到多表之间的关联字段消除笛卡尔积,属于内连接。
   
   -- 自动建立emp与dept的等值连接
SELECT * FROM emp
NATURAL JOIN dept;
   
   https://img-blog.csdnimg.cn/img_convert/615038c2c140f1af85bc6f2bb1a80092.png
   5.3 USING指定关联字段

   使用USING指出多表查询的关联字段。
   
   SELECT * FROM emp
JOIN dept USING(deptno);
   
   https://img-blog.csdnimg.cn/img_convert/a99449f493dd944d811086152ef4e928.png
   5.4 交集与并集

   https://img-blog.csdnimg.cn/img_convert/e908fbd25a80ddc3474917b9697691af.png
   5.4.1 并集(不显示重复记录)

   使用UNION关键字,可以将两个查询效果合并,且不显示重复记录(橙色区域只显示一遍)。
   【例子】查询全部20部门或者工资高于1500的雇员信息。
   分析:
   查询一:查询全部20部门的雇员信息。
   
   SELECT * FROM emp
WHERE deptno=20;
   
   查询二:查询全部工资高于1500的雇员信息。
   
   SELECT * FROM emp
WHERE sal>1500;
   
   并集。
   
   SELECT * FROM emp
WHERE deptno=20UNIONSELECT * FROM emp
WHERE sal>1500;
   
   https://img-blog.csdnimg.cn/img_convert/756905a995bb751f70d343809cb511d1.png
   5.4.2 并集(显示重复记录)

   使用UNION ALL关键字,可以将两个查询效果合并,且显示重复记录(橙色区域显示两遍)。
   以5.4.1的例题为例,改为使用UNION ALL合并。
   
   SELECT * FROM emp
WHERE deptno=20UNION ALLSELECT * FROM emp
WHERE sal>1500;
   
   https://img-blog.csdnimg.cn/img_convert/812399df6586e5ed9f68c85168bd93d7.png
   5.4.3 交集

   使用INTERSECT可以获得两个查询效果的交集。
   【例子】查询部门20且工资高于1500的雇员信息。
   
   SELECT * FROM emp
WHERE deptno=20INTERSECTSELECT * FROM emp
WHERE sal>1500;
   
   https://img-blog.csdnimg.cn/img_convert/83632499cc35c1186fd40d1e488d6a07.png
   
   交集与并集的使用需要注意让两个查询的格式相同,查询效果的列能逐一对应。
   

   删除之前添加的数据。
   
   DELETE FROM emp
WHERE empno=6666;
   
                               五、分组查询

      什么环境需要分组?
      班级里男生一组,女生一组;公司研发部一组、市场组一组、测试部一组......
      分组的条件是某些举动和特点具有同一性,好比在emp表中job和deptno等字段可以进行分组。一条数据也能独占一组,但是每组都是一条数据则毫无意义。
      1. 概念

      分组查询使用关键字GROUP BY实现,语法规则如下:
      https://img-blog.csdnimg.cn/img_convert/27236630be4ca6d6d6008a542f2076e0.png
      【例子】按照职位分组,查询每个职位的均匀工资、最高工资、最低工资和人数。
      分析:
      第一步,确定FROM子句。
      emp:sal,sal,sal,empno
      
      FROM emp
      
      第二步,如果是多表查询,确定多表之间的关系,消除笛卡尔积。
      第三步,查看全部人还是一部分人,如果是一部分人,则继承使用WHERE子句筛选。
      第四步,确定GROUP BY子句。
      
      GROUP BY job
      
      第五步,确定SELECT子句。
      
      SELECT job,AVG(sal),MAX(sal),MIN(sal),COUNT(empno)
      
      第六步,确定ORDER BY子句。
      第七部,拼接SQL语句。
      
      SELECT job,AVG(sal),MAX(sal),MIN(sal),COUNT(empno)
FROM emp
GROUP BY job
;      
      https://img-blog.csdnimg.cn/img_convert/80856f27934249026faf32b4d5356ed6.png
      【练习】
      1. 统计全部部门的均匀工资和最高工资。
      
      SELECT deptno,AVG(sal),MAX(sal)FROM emp
GROUP BY deptno;      
      2. 统计10部门和20部门中各个职位的人数。
      
      SELECT job,COUNT(empno) FROM emp
WHERE deptno=10 OR deptno=20GROUP BY job
;      
      3. 统计公司全部部门的均匀工资,按照均匀工资降序排序。
      
      SELECT deptno,AVG(sal)FROM emp
GROUP BY deptnoORDER BY AVG(sal) DESC;      
      
      可以看到之前学习的统计函数与分组查询密切相关。
      2. 多表+分组

      多表查询和分组查询可以一起使用。
      【例子】查询出每个部门的名称、部门人数、均匀工资。
      
      -- 推荐使用题目中需要显示的内容作为分组字段
SELECT dname,COUNT(empno),AVG(sal)
FROM dept d LEFT JOIN emp e ON d.deptno=e.deptno

GROUP BY dname;
      
      
      -- 这种写法在SQLite中也可以,但是其它数据库中可能失败
SELECT dname,COUNT(empno),AVG(sal)
FROM dept d LEFT JOIN emp e ON d.deptno=e.deptno

GROUP BY e.deptno
;
      
      【思考】查询出每个部门的编号、部门名称、位置、部门人数、均匀工资。
      
      SELECT d.deptno,dname,loc,COUNT(ename),AVG(sal)
FROM dept d LEFT JOIN emp e ON e.deptno=d.deptno
GROUP BY e.deptno
;
                                              3. 作业

         1. 查询公司工资品级在3以上(包罗3),的雇员编号和姓名。
         SELECT empno,ename
         FROM emp
,salgrade
         WHERE sal BETWEEN losal AND hisal AND grade>=3;
         
         SELECT empno,ename
         FROM emp
JOIN salgrade ON sal BETWEEN losal AND hisal
         WHERE grade>=3;
         
         2. 查询公司全部雇员的姓名,雇员编号,部门名称,要求部门名称小写且显示全部部门。
         SELECT ename,empno,LOWER(dname)
         FROM dept d
         LEFT JOIN emp e ON e.deptno=d.deptno;
         
         3. 要求算出部门30的全部人员的姓名、雇佣年限(要求四舍五入到一位小数)、部门位置。
         SELECT ename, ROUND((JULIANDAY('now')-JULIANDAY(hiredate))/365,1),loc
         FROM emp
e JOIN dept d ON e.deptno=d.deptno
         WHERE e.deptno=30;
         
         4. 查询出全部雇员和其领导的姓名和年薪。
         SELECT e.ename,m.ename,(m.sal+IFNULL(m.comm,0))*12
         FROM emp
e LEFT JOIN emp m ON e.mgr=m.empno
;
         
         5. 统计贩卖和经理的职位的均匀月综合收入、最高月综合收入、职位人数。
         SELECT job, AVG(sal+IFNULL(comm,0)),MAX(sal+IFNULL(comm,0)),COUNT(empno)
         FROM emp
e WHERE job='MANAGER' OR job='SALESMAN'
         GROUP BY job
;
         
         4. HAVING子句——分组后筛选

         【思考】按照职位分组,统计每个职位的均匀工资,显示均匀工资高于2000的职位。
         分析:按照之前的做法,可能会写出下面的SQL语句。
         
         SELECT job,AVG(sal)FROM emp
WHERE AVG(sal)>2000GROUP BY job
;         
         实行后,直接报错。
         https://img-blog.csdnimg.cn/img_convert/6968a46b0ec43be0114365f82ea04a12.png
         意思是WHERE子句中不允许使用AVG函数,现实上WHERE中不允许出现任何统计函数,由于WHERE是在GROUP BY之前实行的,如果是在分组后进行筛选,应该引入HAVING子句来完成这个功能。
         增长HAVING子句到实行次序中,语法格式如下。
         https://img-blog.csdnimg.cn/img_convert/5145a41f145c86fe0a85bd7fdb11272d.png
         修改上一道题的答案为:
         
         SELECT job,AVG(sal)FROM emp
GROUP BY job
HAVING AVG(sal)>2000;         
         https://img-blog.csdnimg.cn/img_convert/4aeb9fb74d94a16267dba58f6bdad5b4.png
         
         再次分析一下WHERE和HAVING的区别。
         https://img-blog.csdnimg.cn/img_convert/9492eadca78273fae79650b37597d3f9.png
         总结:
         

[*]WHERE是在分组之前对个体进行筛选,HAVING是分组之后对群体进行筛选。
[*]WHERE可以独立存在,HAVING必须依靠于GROUP BY子句。
[*]WHERE通常不实用统计函数,HAVING通常使用统计函数
         【练习】
         查询每个部门的名称、部门人数、最高工资和最低工资,要求显示最低工资高于1000的部门信息。
         分析:
         第一步,确定FROM子句。
         
         FROM dept d JOIN emp e
         
         第二步,确定关联字段。
         
         ON d.deptno=e.deptno
         
         第三步,确定WHERE子句,是否有针对个体的筛选。
         第四步,确定GROUP BY子句。
         
         GROUP BY e.deptno
         
         第五步,确定HAVING子句,是否有针对组的筛选。
         
         HAVING MIN(sal)>1000   
         
         第六步,确定SELECT子句。
         
         SELECT dname,COUNT(empno),MAX(sal),MIN(sal)   
         
         第七步,确定ORDER BY子句。
         第八步,拼接并检查。
         
         SELECT dname,COUNT(empno),MAX(sal),MIN(sal)FROM dept d JOIN emp e
ON d.deptno=e.deptno
GROUP BY e.deptno
HAVING MIN(sal)>1000;         
         https://img-blog.csdnimg.cn/img_convert/81f492fa0f2d85c2d59488a389471c13.png
         【练习】查询公司各个工资品级的人数与均匀工资,要求显示均匀工资高于1500的职位信息,且按照均匀工资降序排布。
         
         SELECT grade,COUNT(empno),AVG(sal)
FROM salgrade JOIN emp ON sal BETWEEN losal AND hisal
GROUP BY grade
HAVING AVG(sal)>1500
ORDER BY AVG(sal) DESC;
         
         https://img-blog.csdnimg.cn/img_convert/96a986e8674b5adec701f8200391ea48.png
         【思考】统计出公司领取佣金和不领取佣金的人数与均匀工资(sal)。
         分析:如果按照通例分组来做,如下所示。
         https://img-blog.csdnimg.cn/img_convert/7b76d1cda0f79199a10009f001b6d270.png
         可以看到效果不符合题意,这种环境下需要手动分组,使用UNION子句。
         
         -- 公司领取佣金的人数与均匀工资SELECT COUNT(empno),AVG(sal) FROM emp
WHERE comm IS NOT NULL;-- 公司不领取佣金的人数与均匀工资SELECT COUNT(empno),AVG(sal) FROM emp
WHERE comm IS NULL;         
         手动合并分组效果。
         
         SELECT '领取佣金',COUNT(empno),AVG(sal) FROM emp
WHERE comm IS NOT NULLUNIONSELECT '不领取佣金',COUNT(empno),AVG(sal) FROM emp
WHERE comm IS NULL;                                                             六、子查询

            子查询指的是在一个查询中嵌入多个小的查询,即查询的嵌套,子查询一定要出现()
            子查询在绝大多数环境下符合如下规律:
            

[*]子查询返回的效果是单行单列(一个数据):HAVING、WHERE
[*]子查询返回的效果是单行多列(一行):WHERE
[*]子查询返回的效果是多行多列(一个表):FROM
            其它子句使用子查询的环境较少。
            1. 在WHERE子句中使用子查询

            WHERE子句的功能是控制显示的行数,支持以下几种子查询:
            

[*]单行单列
[*]多行单列
[*]多行多列
            1.1 返回单行单列

            【例子】统计出全部高于公司均匀工资的雇员信息。
            分析:
            第一步,求出公司的均匀工资。
            
            SELECT AVG(sal) FROM emp
;            
            第二步,把第一步的效果嵌入到WHERE子句中。
            
            SELECT * FROM emp
WHERE sal>(SELECT AVG(sal) FROM emp
);            
            https://img-blog.csdnimg.cn/img_convert/c6dd99c4828b4db863db0a0751c6f369.png
            【练习】统计出公司最早雇佣的雇员信息(使用子查询完成)。
            
            SELECT * FROM emp
WHERE hiredate=(SELECT MIN(hiredate) FROM emp
);                                                                            1.2 返回单行多列

               【例子】显示出公司雇佣最早且工资最低的雇员(刚好存在)。
               分析:
               第一步,统计出公司最早的雇佣日期和最低的工资。
               
               SELECT MIN(hiredate) FROM emp
;SELECT MIN(sal) FROM emp
;               
               第二步,将上面的两个效果嵌套在WHERE子句中显示满足条件的信息。
               
               SELECT * FROM emp
WHERE hiredate=(SELECT MIN(hiredate) FROM emp
)AND sal=(SELECT MIN(sal) FROM emp
);               
               https://img-blog.csdnimg.cn/img_convert/ecc07cc4af718a4d3074e491084f5085.png
               【练习】求出与SCOTT工资相同且职位相同的雇员信息。
               
               SELECT * FROM emp
WHERE job=(SELECT job FROM emp
WHERE ename='SCOTT') AND sal=(SELECT sal FROM emp
WHERE ename='SCOTT')AND ename!='SCOTT';               
               1.3 返回多行单列

               相当于提供了一些查询范围,通常与IN这种操作联合使用。
               【例子】显示工资跟各个经理相同的雇员信息(包罗各个经理本身)。
               分析:
               第一步,查询出各个经理的工资。
               
               SELECT sal FROM emp
WHERE job='MANAGER';               
               第二步,将上面的SQL语句嵌入到WHERE子句中搭配IN操作使用。
               
               SELECT * FROM emp
WHERE sal IN (SELECT sal FROM emp
WHERE job='MANAGER');               
               https://img-blog.csdnimg.cn/img_convert/7b256d992a3ab89d6297568030b2e1c1.png
               【例子】显示工资跟各个贩卖不相同的雇员信息。
               
               SELECT * FROM emp
WHERE NOT sal IN (SELECT sal FROM emp
WHERE job='SALESMAN');               
               2. HAVING子查询

               如果有HAVING子句,就一定分组统计。
               HAVING子句中出现的子查询只能是单行单列的。
               【例子】查询出高于公司均匀工资的部门编号和这些部门的均匀工资。
               分析:
               第一步,计算出公司的均匀工资。
               
               SELECT AVG(sal) FROM emp
;               
               第二步,分组后在HAVING子句中嵌入第一步的SQL语句。
               
               SELECT deptno,AVG(sal)FROM emp
GROUP BY deptnoHAVING AVG(sal)>(SELECT AVG(sal) FROM emp
);               
               https://img-blog.csdnimg.cn/img_convert/c5b2b645030ef9ec13e14876e88d1cac.png
               【思考】查询均匀工资最低的职位的信息(此职位的名称、人数与此职位的均匀工资)
               分析:
               第一步,查询每个职位的均匀工资。
               
               SELECT AVG(sal) FROM emp
GROUP BY job
;               
               第二步, 查询均匀工资最低的职位的均匀工资。
               
               SELECT MIN(asal)FROM (SELECT AVG(sal) asal FROM emp
GROUP BY job
);               
               注意需要起别名asal才能在外部使用。
               第三步,使用上一步的效果作为HAVING子句中子查询的条件。
               
               SELECT job,COUNT(empno),AVG(sal)FROM emp
GROUP BY job
HAVING AVG(sal)=(    SELECT MIN(asal)    FROM (SELECT AVG(sal) asal FROM emp
GROUP BY job
));               
               别的,此题还可以使用其他解法。
               
               SELECT job,COUNT(empno),AVG(sal) FROM emp
GROUP BY job
HAVING sal ORDER BY AVG(sal) ASC LIMIT 1;               
               3. SELECT子查询

               出现频率较低,使用需求较低。
               【例子】显示全部雇员的姓名、职位、部门名称与部门位置。
               分析:
               正常解法就是一个平凡的多表查询。但是此处也可以使用SELECT子查询完成。
               
               SELECT e.ename,e.job,(SELECT dname FROM dept WHERE deptno=e.deptno),(SELECT loc FROM dept WHERE deptno=e.deptno)FROM emp
e;               
               https://img-blog.csdnimg.cn/img_convert/fbba5b64d96a2f352589bd344df57d47.png
               这种方法无需掌握。
               4. FROM子查询

               FROM子查询通常返回的是多行多列,可以把子查询返回的效果看做是一张单独的表。
               【例子】查询出每个部门的编号、名称、位置、部门人数、均匀工资。
               实现方式一:直接使用之前的多表查询。
               
               SELECT d.deptno,dname,loc,COUNT(empno),AVG(sal)FROM dept d LEFT JOIN emp e ON d.deptno=e.deptno
GROUP BY d.deptno;               
               实现方式二:FROM子查询
               第一步,单独查询出全部部门的部门号(两个表都有),部门人数(
               emp表),均匀工资(emp表)
               
               SELECT deptno,COUNT(empno),AVG(sal)FROM emp
GROUP BY deptno;               
               https://img-blog.csdnimg.cn/img_convert/494d15b15500c7129279076c838fbc01.png
               第二步,把上一步查询的效果作为一张表与dept表进行多表查询。
               
               SELECT d.deptno,dname,loc,temp.rs,temp.asalFROM dept d LEFT JOIN(    SELECT deptno,COUNT(empno) rs,AVG(sal) asal    FROM emp
    GROUP BY deptno)temp ON d.deptno=temp.deptno;               
               https://img-blog.csdnimg.cn/img_convert/5e8fe726d61de538d6aa4c5bd3539be4.png
               https://img-blog.csdnimg.cn/img_convert/11bc6a82f79d27fcca5d690f1992ab61.png
               只管搞明确,实在搞不懂的必须掌握实现方式一。
               
               现实的开辟中,有可能会遇到巨大的数据量,不妨把当前emp与dept表的数据量扩大100倍,即emp表中有1400条数据,dept表中有400条数据。
               

[*]实现方式一的数据量
               直接使用多表查询,会在背景天生笛卡尔积,其数量为1400*400=560000
               

[*]实现方式二的数据量
               第一步(内嵌的子查询):操作数据量为1400,返回的数据量为最多为400
               第二步(子查询与dept表多表查询):400*400=160000
               总数据量 = 160000+1400 = 161400
               
               实现方式二的理论性能是实现方式一的1/3,结论是:
               小的数据量使用实现方式一,大的数据量使用实现方式二。
                                                                                                                         5. 作业

               1. 列出至少有四个员工的全部部门编号、部门名称、部门人数
               SELECT d.deptno,dname,COUNT(empno)
               FROM emp
e JOIN dept d ON e.deptno=d.deptno
               GROUP BY d.deptno
               HAVING COUNT(empno)>=4;
               
               2. 列出雇佣日期早于其领导的全部员工的编号,姓名,部门名称,领导名称。
               SELECT e.empno,e.ename,d.dname,p.ename
               FROM emp
e LEFT JOIN emp p ON e.mgr=p.empno JOIN dept d ON e.deptno=d.deptno
               WHERE p.hiredate>e.hiredate;
               
               3. 列出各个部门的CLERK(柜员)的最低薪金。
               SELECT deptno,MIN(sal)
               FROM emp

               WHERE job='CLERK'
               GROUP BY deptno;
               
               4. 列出工资比SMITH多的全部员工
               SELECT * FROM emp
WHERE sal>(
               SELECT sal FROM emp
WHERE ename='SMITH'
               );
               
               
               5. 列出在部门“SALES”工作的员工姓名和工资
               SELECT ename,sal
               FROM emp
e JOIN dept d ON e.deptno=d.deptno
               WHERE d.dname="SALES";
               
               
               6. 求出部门名称中带‘S’字符的部门,其员工的工资合计和部门的人数
               SELECT dname,SUM (sal),COUNT(e.deptno)
               FROM emp
e JOIN dept d ON e.deptno=d.deptno
               GROUP BY dname
               HAVING dname LIKE '%S%';
                                                         
                                                                                                               七、数据更新操作

               针对DML(数据操作语言)分为两类:查询(DQL)和更新,更新分为三种操作:
               

[*]增长 INSERT
[*]修改 UPDATE
[*]删除 DELETE
               数据更新操作会直接更改数据库中的数值,为了防止emp表的原始数据被粉碎,在学本章知识点之前,先复制一份emp表,新的emp表叫myemp,实行如下操作:
               
               CREATE TABLE myemp AS SELECT * FROM emp
;               
               https://img-blog.csdnimg.cn/img_convert/d9df7abec1e8669033f76a9bfa883b52.png
               myemp只是数据与emp完全相同,但是一些束缚关系不相同。
               本章后续的操作都基于myemp表。如果不鉴戒粉碎了emp表,可以去群文件中重新下载scott.db文件。
               1. 插入数据

               插入数据的语法格式如下所示:
               
               INSERT INTO 表名[(列1,列2,...)] VALUES(值1,值2,...)
               
               针对目前已经打仗过的数据类型:
               

[*]字符串:要求使用英文半角的单引号或双引号包括内容
[*]数字:直接写数字
[*]日期和时间               

[*]如果是当前日期时间,可以使用DATETIME('now')等写法,如果是本地日期和时间别忘了第二个参数增长'localtime'
[*]也可以使用固定格式的字符串,例如'1992-01-06 02:33:33'

               【例子】在myemp表中增长一条数据。
               实现方式一:使用完备的格式
               
               INSERT INTO myemp(empno,ename,job,mgr,hiredate,sal,deptno)
VALUES(8888,'张三','厨师',7839,DATETIME('now','localtime'),10000,40);
               
               https://img-blog.csdnimg.cn/img_convert/cc6d57e3e1170d5d11aebf542362c0ac.png
               https://img-blog.csdnimg.cn/img_convert/663b9ea768c12a6d1bae3aa82a1a9e26.png
               实现方式二:使用简易格式
               
               INSERT INTO myemp VALUES(1000,'罗翔','律师',8888,'2000-03-30 09:44:34',1,NULL,10);
               
               第二种方式需要注意,如果列数据为NULL,需要手动写上插入的数据为NULL。
               
               推荐使用第一种方式。
               【练习】
               分别使用两种方式插入自己和同桌的信息。
               
               INSERT INTO myemp(empno,ename,job,mgr,hiredate,sal,deptno)
VALUES(6666,'IKUN','唱跳rap篮球',7839,DATETIME('now','localtime'),135,11);

INSERT INTO myemp VALUES(230,'小黑子','鸡你太美',6666,'2022-09-30 09:44:34',123,NULL,10);
               
               2. 修改数据

               修改数据的语法如下:
               
               UPDATE 表名 SET 列名1=值1,列名2=值2,...
               
               需要注意的是,如果不写WHERE子句表示更新全部数据。
               
               【例子】将‘SMITH’的工资修改为5000,佣金修改为2000
               
               UPDATE myemp SET sal=5000,comm=2000 WHERE ename='SMITH';
               
               【例子】将全部贩卖的工资修改为2000
               
               UPDATE myemp SET sal=2000 WHERE job='SALESMAN';
               
               https://img-blog.csdnimg.cn/img_convert/1724603c585c724d08ed3131c2eceeb3.png
               
               【练习】
               1. 将公司最早雇佣的员工的工资增长20%
               
               UPDATE myemp SET sal=1.2*sal ORDER BY hiredate ASC LIMIT 1;
               
               
               UPDATE myemp SET sal=1.2*sal WHERE hiredate=(SELECT MIN(hiredate) FROM emp
);               
               2. 将公司全部雇员的雇佣日期改为现在。
               
               UPDATE myemp SET hiredate=DATETIME('now');
               
               https://img-blog.csdnimg.cn/img_convert/f1fe657fd1650411ee1dd3bf81c26f2e.png
               3. 删除数据

               删除数据的语法格式如下:
               
               DELETE FROM 表名
               
               需要注意的是,如果不写WHERE子句,表示删除全部数据!
               
               【例子】删除全部30部门的雇员。
               
               DELETE FROM myemp WHERE deptno=30;
               
               第一次实行,显示
               https://img-blog.csdnimg.cn/img_convert/7e1c1d4e316269d781d47541ba266980.png
               ;再次实行,显示,由于这些数据已经被删除了。
               
               【练习】
               1. 删除公司工资最高的雇员。
               
               DELETE FROM myemp WHERE sal=(SELECT MAX(sal) FROM myemp);
               
               2. 删除没有领导的雇员。
               
               DELETE FROM myemp WHERE mgr IS NULL;
               
               3. 删除全部雇员。
               
               DELETE FROM myemp;
               
               
               在现实的开辟中,为了保护数据,随时可以恢复数据,通常实行逻辑删除,而不实行物理删除。
               物理删除就是使用DELETE语句进行删除;
               逻辑删除指的是,在筹划表时可以增长一列,用这一列的数据表示当前的数据的可用性(例如1为数据可用,0为数据不可用)。那么在查询的时间多增长一个判断为1的条件,表示查询全部数据。删除时,可以把这一列的数据置为0,使用UPDATE操作来进行逻辑删除。
               
               
                                                                                 八、表的创建与管理

                  之前的全部学习都是以DML(数据操作语言)为主,如果想对表本身进行维护,则需要使用DDL(数据界说语言),DDL通常在项目的初期使用。
                  1. 数据类型

                  大多数数据库使用的都是静态数据类型,即值的类型由它的容器(存储值的列)决定。但是SQLite使用的是动态数据类型,值本身决定数据类型,不与容器相关。
                  SQLite常用的存储类有:
                  https://img-blog.csdnimg.cn/img_convert/fb99f1330c6bee133edc5b9671e25176.png
                  存储类又可以动态地细分为不同的亲和类型,仅做相识。
                  https://img-blog.csdnimg.cn/img_convert/bbb97dad012433fccb410eff0faaa629.png
                  2. 创建表

                  创建一张表的语法格式如下:
                  
                  CREATE TABLE 表名(
    列名1    类型    ,
    列名2    类型    ,
    ...,
        列名n    类型   
);
                  
                  如果创建表的语句较短,也可以写成一行:
                  
                  CREATE TABLE 表名(列名1 类型 ,列名2 类型 ,...,列名n 类型 );
                  
                  【例子】创建一张表。
                  
                  CREATE TABLE hqyj23032(
    id    INTEGER,
    nameTEXT    DEFAULT    '佚名',
    birth TEXT    DEFAULT    CURRENT_DATE,
    sal   REAL    DEFAULT    0
);
                  
                  https://img-blog.csdnimg.cn/img_convert/9598d1ea7361725b3270a45a94d88669.png
                  可以对这个表进行正常的增编削查。
                  https://img-blog.csdnimg.cn/img_convert/e27e8a009351fb7f018898b7a0290e62.png
                  可以使用下面的语句删除表。
                  
                  DROP TABLE 表名;
                  
                  3. 束缚

                  束缚是在表的数据列中增长欺压实行的规则,例如上一节中的默认值,如果一列没有默认值束缚且不手动添加数值,则会使用NULL表示这个数据。
                  除了默认值以外,还有其它的束缚,这些束缚可以保障数据表的准确性和可靠性。
                  一共有如下束缚类型:
                  https://img-blog.csdnimg.cn/img_convert/85a07a3667c8005dc44b9a812b34b435.png
                  3.1 非空束缚

                  【例子】创建一个表,包罗非空束缚的列,并测试。
                  
                  CREATE TABLE member(id INTEGER,name TEXT NOT NULL);
                  
                  尝试插入数据,使name列的数值为NULL。
                  
                  INSERT INTO member VALUES(1,NULL);
INSERT INTO member(id) VALUES(2);
                  
                  https://img-blog.csdnimg.cn/img_convert/3b66f5a9b12fe5a077f8b26a85976fbc.png
                  插入失败。
                  3.2 唯一束缚

                  【例子】创建一个表,包罗唯一束缚的列,并测试。
                  
                  CREATE TABLE member(id INTEGER,name TEXT UNIQUE);
                  
                  
                  -- 可以执行
INSERT INTO member VALUES(1,'张三');
-- 不可以执行
INSERT INTO member VALUES(2,'张三');
                  
                  https://img-blog.csdnimg.cn/img_convert/3d5ce2a0d4f6bdba90c2ac9b079b4a3c.png
                  当重复时显示
                  3.3 主键束缚

                  主键束缚 ≈ 非空束缚+唯一束缚
                  作为每个记录的唯一标识,通常把第一列(序号)作为主键。
                  与其它数据库不同的是,为了非空特性,当强行插入NULL时,会主动添补序列。
                  【例子】创建一个表,包罗主键束缚的列,并测试。
                  
                  -- 先删除
DROP TABLE member;
-- 再建表
CREATE TABLE member(id INTEGER PRIMARY KEY,name TEXT);

-- 正确
INSERT INTO member VALUES(1,'张三');
-- 错误:id列重复了
INSERT INTO member VALUES(1,'李四');
                  
                  https://img-blog.csdnimg.cn/img_convert/e73e9f9ef5929ae5756f24f22492cae7.png
                  上面第9行代码会报错。
                  
                  -- 自动填充序列
INSERT INTO member VALUES(NULL,'王五');
                  
                  https://img-blog.csdnimg.cn/img_convert/840ea66fcf4f9a11c735d887f35af7de.png
                  主键束缚还可以增长AUTOINCREMENT关键字,设置为自增长。
                  
                  -- 先删除
DROP TABLE member;
-- 再建表,id列自增长
CREATE TABLE member(id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT);

-- 测试
INSERT INTO member(name) VALUES('张三');
INSERT INTO member(name) VALUES('李四');
INSERT INTO member(name) VALUES('王五');
                  
                  https://img-blog.csdnimg.cn/img_convert/e1cf13e4f3c23cec1b09e92a30fd65db.png
                  3.4 条件检查束缚

                  【例子】创建一个表,包罗条件检查束缚的列,并测试。
                  
                  -- 先删除
DROP TABLE member;
-- 再建表
CREATE TABLE member(id INTEGER,sal INTEGER CHECK(sal>1000));

-- 测试:成功
INSERT INTO member VALUES(1,1001);
-- 测试:失败
INSERT INTO member VALUES(2,999);
                  
                  https://img-blog.csdnimg.cn/img_convert/71904183b5dd8868233acbe744d69a3e.png
                  
                  其它内容可以自学:
                  https://img-blog.csdnimg.cn/img_convert/656e80058aa0098e3ef5f3be74ed6ec5.png
                  https://img-blog.csdnimg.cn/img_convert/c6ab4a3ac901a8ee70bbb001b8f7a84d.png
                  
                                                                                                                                                   

                                             
                                          
                                                                                       
      

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 数据库的基本操作