数据库基础知识

  • 1. 数据库概述
  • 1.1 入门
  • 1.2 DQL(数据查询语言)
  • 1.2.1 简单查询
  • 1.2.2 条件查询
  • 1.2.3 排序
  • 1.2.4 数据处理函数(单行处理函数)
  • 1.2.5 分组函数(多行处理函数)
  • 1.2.5.1 分组查询(重要*****)
  • 1.2.6 去除重复记录
  • 1.2.7 连接查询
  • 1.2.7.1 内连接之等值连接
  • 1.2.7.2 内连接之非等值连接
  • 1.2.7.3 内连接之自连接
  • 1.2.7.4 外连接
  • 1.2.7.5 多表之间的连接
  • 1.2.8 子查询
  • 1.2.8.1 where子句中的子查询
  • 1.2.8.2 from子句中的子查询
  • 1.2.8.3 select子句中的子查询(了解即可)
  • 1.2.9 union可以合并集合
  • 1.2.9 limit可以将查询结果的一部分取出来
  • 1.2.10 分页


1. 数据库概述

1.1 入门

  1. SQL概述:SQL全称是Structured Query Language,SQL用来和数据库打交道,完成和数据库的通信,SQL是一套标准,但是每一个数据库都有自己的特性,当使用这个数据库特性相关的功能,这是SQL语句可能就不是标准了(90%以上的SQL都是通用的)
  2. 什么是数据库?
    数据库(Database,简称DB)通常是一个或一组文件,保存了一些复合特定规格的数据; 数据库软件称为数据库管理系统(DBMS, Database Management System),如MySQL,Oracle, SQL Server, DB2等
  3. MySQL概述
    是一个关系型数据库管理系统,不仅是最流行的开源数据库,而且是业内成长最快的数据库。2009年,Oracle收购了sun公司,使MySQL并入Oracle的数据库产品线。
  4. 什么是数据库?什么是数据库管理系统?什么是SQL?他们之间的关系是什么?
    数据库(Database,简称DB)通常是一个或一组文件,保存了一些复合特定规格的数据;
    数据库管理系统,简称DBMS,是专门用来管理数据库中数据的,DBMS可以对数据库中的数据进行增删改查;
    SQL是结构化查询语言,程序员需要学习SQL语句,通过编写SQL语句,执行SQL语句,最终来完成数据库中数据的增删改查;
    关系:DBMS通过执行SQL语句来对DB进行管理。
  5. 安装MySQL数据库,先安装“经典版”,一路下一步就行了。
    注意:①MySQL默认端口号为3306。端口号是任何一个应用/软件都会有的,端口号是应用的唯一代表,通常和IP地址搭配使用,IP地址用来定位计算机,端口号Port用来定位计算机上某个服务;②MySQL的字符编码方式为UTF-8;③MySQL超级管理员用户名为root,不能修改。
  6. 卸载MySQL:第一步双击安装包进行卸载,第二步删除C:\ProgramData下面MySQL目录,并且删除C:\Program File(x86)下的MySQL目录。
  7. MySQL服务的启动与停止
    计算机–>右键–>管理–>服务和应用程序–>服务–>找到MySQL服务。默认是自启动状态,可以再服务上点击右键进行启动、重启服务、停止服务等操作。
    使用命令来启动和关闭服务: net stop 服务名称; net start 服务名称
  8. 数据库中用表来存储数据:表比较直观。任何一张表都有行和列:行(row):被称为数据/记录 。列(column):被称为字段,每一个字段都有字段名,数据类型,约束等属性。
  9. SQL语句的分类:
    数据查询语言(DQL-Data Query Lanauage):代表关键字select
    数据操纵语言(DML-Data Manipulation Language):insert,delete,update
    数据定义语言(DDL- Data Definition Language):create,drop,alter
    事务控制语言(TCL-Transactional Control Language):commit,rollback
    数据控制语言(DCL-Data Control Lanauage ):grand,revoke

MySQL常用命令

  • 登录:mysql.exe -h主机地址 -P端口 -u用户名 -p密码
    1、通常端口都可以默认:mysql的监听端口通常都是3306
    2、mysql 或者mysql.exe
    3、密码的输入可以先输入-p,直接换行,然后再以密文方式输入密码(安全)
    4、-h 主机名,可以使用该参数指定主机名或Ip,如果不指定,默认是localhost
  • 退出:exit
  • 查看数据库版本: select version();
  • 查看都有哪些数据库:show databases;
  • 创建数据库:create ***;
  • 使用某个数据库:use ***;
  • 查看某个数据库下有哪些表: show tables;
  • 查询某个表的所有数据: select * from 表名;
  • 查看表结构:desc 表名;
  • 中止某条命令的输入:\c

1.2 DQL(数据查询语言)

1.2.1 简单查询

需求

命令

查询一个字段

select 字段名 from 表名;

查询多个字段

select 字段1,字段2 from 表名;(用逗号隔开)

查询所有字段

select * from 表名;(或用逗号隔开所有字段)

给某个字段起别名

select 旧名 as 新名 from 表名;

select 旧名 新名 from 表名;

select 旧名 ‘new name’ from 表名;(名字里有空格)

列参与数学运算

select 字段名*12 from 表名;

Note:
1.使用as关键字起别名的时候,只是将显示的查询结果列明显示为“新名”,数据库中的原表列名还是“旧名”,因为select语句只负责查询,不会对表格进行修改操作。
2.as关键字是可以省略的:select 旧名 新名 from 表名;假设起的别名里有空格,用单引号(或双引号,但是双引号在oracle数据库中用不了,数据库中的字符串标准都是使用单引号括起来,双引号不是标准的)把别名括起来
3. 如果别名是中文的,也需要使用单引号括起来
4. 字段是可以参加加减乘除运算的

1.2.2 条件查询

select 字段1,字段2,..., from 表名 where 条件;

条件:

Mysql 输入字段like 数据库字段_字段


注意:

  1. 在数据库中null不能使用等号进行衡量。需要使用 is null,因为数据库中的null代表什么也没有,它不是一个值,所以不能使用“=”衡量。
  2. where后面如果and,or的条件, 则or自动会把左右的查询条件分开,即先执行and,再执行or。原因就是:and的优先级最高。
  3. in
select name,sal from emp where sal = 800 or sal = 5000;
相当于
select name,sal from emp where sal in(800,5000);
//这不是表示800-5000的都找出来,而是表示只找800和5000的
  1. like 称为模糊查询,支持%或下划线匹配
    %匹配任意多个字符,下划线匹配任意一个字符
select name fro emp where name like %o% //查出名字中带有o的员工名字
select name fro emp where name like %\_% //找出名字中带有下划线的名字,“\”为转义字符

1.2.3 排序

//查询所有员工薪资,排序,默认是升序
select name,sal from emp order by sal;
//查询所有员工薪资,降序,descend
select name,sal from emp order by sal desc;
//查询所有员工薪资,升序,ascend
select name,sal from emp order by sal asc;
//查询所有员工薪资,薪资一样时,才会考虑按照名字升序排
select name,sal from emp order by sal asc, name asc;
//了解:按照查询结果进行排序(根据字段的位置进行排序,开发中不建议这样写,不健壮)
select name,sal from emp order by 2;

//关键顺序不能变:
select
	...
from
	...
where
	...
order by
	...
以上语句的执行顺序必须掌握:
	第一步: from
	第二步: where
	第三步: select
	第四步: order by (排序总是在最后执行!)

1.2.4 数据处理函数(单行处理函数)

数据处理函数又称为单行处理函数
单行处理函数:一个输入对应一个输出
多行处理函数: 多个输入,对应一个输出
常见的单行处理函数:

函数

作用

lower

转换小写

upper

转换大写

substr

取子串(substr(被截取的字符串,起始下标,截取的长度))

length

取长度

trim

去空格

str_to_date

将字符串转换成日期,格式: str_to_date(‘字符串日期’,‘日期格式’)

data_format

格式化日期(把日期转换成具有特定格式的字符串)

format

设置千分位

round

四舍五入

rand()

生成随机数

ifnull

可以将null转换成一个具体值

case…when…then…when…then…else…end

SELECT LOWER(NAME) FROM CITY;
SELECT UPPER(NAME) FROM CITY;
SELECT UPPER(NAME) AS NAME1 FROM CITY;
SELECT SUBSTR(NAME, 1, 1) FROM CITY-- SUBSTR的起始下标从1开始,没有0
SELECT NAME FROM CITY WHERE SUBSTR(NAME, 1, 1) = 'A'-- 查询首字母是A的城市名
SELECT CONCAT(UPPER(SUBSTR(NAME,1,1)),SUBSTR(NAME,2,LENGTH(NAME)-1)) AS RESULT FROM CITY;-- 将name列的首字母大写
SELECT LENGTH(NAME) FROM CITY;
SELECT * FROM CITY WHERE NAME ='   HERAT';-- 查不到数据
SELECT * FROM CITY WHERE NAME =TRIM('  HERAT ');
SELECT 'ABC' FROM CITY;-- SELECT后面直接跟“字面量/字面值”,会生成和该表的记录一样个数的ABC;
SELECT 'ABC' FROM CITY;-- 会生成和该表的记录一样个数的1000(因为1000是字面值);
mysql的日期格式: %Y 年, %m 月,%d 日, %h 时, %i 分, %s 秒
insert into t_user(id, name, birth) values(1,zhangsan, str_to _date('01-10-1990','%d-%m-%Y'));
-- str_to_date函数可以把字符串varchar转换成日期类型的数据。通常使用在插入insert语句中,因为插入的时候需要一个日期类型的数据,需要通过该函数将字符串转换成date。
insert into t_user(id, name, birth) values(1,zhangsan, '1990-10-11');
-- 注意:如果提供的日期字符串的格式为%Y-%m-%d,namestr_to_date函数就不需要了。
select id,name,birth from t_user;
-- 以上的SQL语句实际上是进行了默认的日期格式化,自动将date类型转换成varchar类型,并且采用mysql的默认日期格式:'%Y-%m-%d'
select id,name,date_format(birth,'%Y/%m/%d') as birth from t_user;
-- 该句是将日期格式化为想要的格式
SELECT ROUND(1234.567, 0) FROM CITY;-- 会生成和该表的记录一样个数的1235,括号里的0表示保留到整数位
SELECT ROUND(1234.567, -1) FROM CITY;-- 会生成和该表的记录一样个数的1230,括号里的-1表示保留到十位
SELECT ROUND(RAND()*100,0) FROM CITY;-- 生成和该表的记录一样个数的100以内的随机数
-- Note:SELECT后面可以跟某个表的字段名(可以理解为java中的变量名),也可以跟字面量/字面值(数据)
SELECT IFNULL(Population,0) FROM CITY;-- 如果人口为NULL,就把它当0
-- 注意,NULL只要参与运算,最终结果一定是NULL.为了避免这个现象,需要使用ifnull函数。ifnull函数用法:ifnull(数据,被当做哪个值),如果“数据”为NULL的时候,把这个当做哪个值 。
CASE...WHEN...THEN...WHEN...THEN...ELSE...END
SELECT NAME,JOB,SAL AS OLDSAL, (CASE JOB WHEN 'MANAGER' THEN SAL*1.1 WHEN 'SALESMAN' THEN SAL*) ELSE SAL END) AS NEWSAL FROM EMP;
-- 当员工的工作岗位是MANAGER的时候,工资上调%,当工作岗位是SALESMAN的时候,工资上调%,其他正常。(注意:不修改数据库,只是将查询结果显示为工资上调)

1.2.5 分组函数(多行处理函数)

多行处理函数: 输入多行,最终输出一行
注意:

  1. 分组函数在使用时必须先分组,然后才能用,如果没有对数据进行分组,整张表默认为一组
  2. 分组函数会自动忽略NULL,不需要提前对NULL进行处理
  3. 分组函数中COUNT(*)和COUNT(具体字段)的区别:
COUNT(*):统计表当中的记录的总行(只要有一行数据COUNT就++,而且表中不存在一行数据所有列都为空)
	COUNT(具体字段):统计该字段下所有不为NULL的记录的总数
  1. 分组函数不能直接使用在where子句中
    因为分组函数在使用的时候必须先分组再使用,WHERE在执行的时候还没有进行分组(SQL执行顺序:FROM -> WHERE -> GROUP BY -> SELECT -> ORDER BY),所以WHERE后面不能出现分组函数
  2. 所有分组函数可以组合起来一起使用
SELECT MAX(Population),Min(Population),AVG(Population),SUM(Population),COUNT(NAME) FROM CITY;

函数名

作用

COUNT

计数

SUM

求和

AVG

求平均值

MAX

最大值

MIN

最小值

SELECT MAX(Population) FROM CITY;-- 求人口的最大值
SELECT Min(Population) FROM CITY;-- 求人口的最小值
SELECT AVG(Population) FROM CITY; -- 求人口的平均值
SELECT SUM(Population) FROM CITY;-- 求人口的总和
SELECT COUNT(NAME) FROM CITY;-- 求城市的个数

1.2.5.1 分组查询(重要*****)

在实际应用中,可能有这样的需求,需要先进行分组,然后对每一组的数据进行操作,这个时候就需要使用分组查询

SELECT
	...
FROM
	...
WHERE
	...
GROUP BY
	...
ORDER BY
...
执行顺序: FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY
从某张表中查询数据
先经过WHERE条件筛选出有价值的数据。
对这些有价值的数据进行分组
分组之后可以使用HAVING继续筛选

Note:

  1. 在一条select语句中,如果有group by语句的话,select后面只能跟:参加分组的字段,分组函数。其他的一律不能跟(mysql中不会报错,但没有意义,别的语言如oracle中则会报错)
SELECT MAX(SAL),DEPT,JOB FROM EMP ORDER BY DEPT ,JOB;
找出每个部门不同工作岗位的最高薪资
  1. WHERE和HAVING,优先选择WHERE,WHERE实在完成不了,在选择having,因为where比having执行效率高。
SELECT DEPT,MAX(SAL) FROM EMP WHERE SAL > 3000 GROUP BY DEPT;-- 找出每个部门最大薪资,要求只显示最大薪资大于3000的
或
SELECT DEPT,MAX(SAL) FROM EMP GROUP BY DEPT HAVING MAX(SAL) > 3000;

SELECT DEPT,AVG(SAL) FROM EMP GROUP BY DEPT HAVING AVG(SAL) > 2500;-- 要求找出每个部门平均薪资大于2500的(此时无法使用WHERE)

1.2.6 去除重复记录

DISTINCT: 去除重复记录
SELECT DISTINCT NAME FROM CITY;
SELECT DISTINCT NAME, POPULATION FROM CITY;-- DISTINCT只能出现在所有字段的最前方
//DISTINCT在NAME, POPULATION 前面,表示两者联合去重
SELECT COUNT(DISTINCT NAME) FROM CITY;-- 统计城市的数量

1.2.7 连接查询

1.连接查询的分类

1.1 根据语法的年代分类:
SQL92: 1992年的时候出现的语法
SQL99: 1999年出现的语法
1.2 根据连接的方式分类:

  • 内连接:
    等值连接
    非等值连接
    自连接
  • 外连接:
左外连接(左连接)
 右外连接(右连接)
  • 全连接(基本不用)
  1. 当两张表进行连接查询,没有任何条件限制的时候,最终查询结果条数是两张表条数的乘积,这种现象被称为:笛卡尔积现象。要避免笛卡尔积现象,就需要加条件。
SELECT
	E.ENAME,D.DNAME
FROM 
	EMP E,DEPT D -- 表起别名很重要 效率问题
WHERE
	E.DEPTNO = D.DEPTNO
//SQL92语法
-- 最终查询的结果虽然减少,但是匹配的过程中,匹配的次数并没有减少。
注意:通过笛卡尔积现象可以得出,表的连接次数越多,效率越低,我们应该尽量避免表的连接次数
1.2.7.1 内连接之等值连接
例:查询每个员工所在部门名称,显示员工名和部门名
SQL92语法:
SELECT
	E.ENAME,D.DNAME
FROM 
	EMP E,DEPT D
WHERE
	E.DEPTNO = D.DEPTNO
SQL92的缺点:表结构不清晰,表的连接条件和后期进一步筛选的条件都放在WHERE后面。
SQL99语法:
SELECT
	E.ENAME,D.DNAME
FROM 
	EMP E
INNER JOIN -- INNER可以省略,带着INNER可读性更好,更容易看出来是内连接
	DEPT D -- 表起别名很重要 效率问题
ON
	E.DEPTNO = D.DEPTNO -- 条件是等量关系,所以被称为等值连接

SQL99优点:表连接的条件是独立的,连接后如果还需要进一步筛选,再往后继续添加where子句。
SQL99语法:
SELECT
	...
FROM 
	A
JOIN 
	B
ON
	A和B的连接条件
WHERE
	筛选条件
1.2.7.2 内连接之非等值连接

Mysql 输入字段like 数据库字段_mysql_02

例:找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级

SELECT
	E.ENAME, E.SAL , S.GRADE
FROM 
	EMP E
JOIN 
	SALGRADE S
ON
	E.SAL BETWEEN S.LOSAL AND S.HISAL; -- 条件不是等量关系,称为非等值连接
1.2.7.3 内连接之自连接

自连接:自己连接自己
技巧:将一张表看成两张表
案例:查询员工的上级领导,要求显示员工名和对应的领导名。
查询结果为13条数据,因为KING的领导为NULL

SELECT
	A.ENAME AS '员工名', B.ENAME AS '领导名'
FROM 
	EMP A
JOIN 
	EMP B
ON
	A. MGR = B.EMPNO;
1.2.7.4 外连接
  • right:表示将join关键字右边的这张表看成主表,主要是为了将这张表中的数据全部查出来,捎带这关联查询左边的表。 在外连接中,两张表连接,产生了主次关系。
  • 带有right的是右外连接,又叫右连接;带有left的是左外连接,又叫左连接。
  • 任何一个右连接都有对应的左连接的写法,任何一个左连接也有对应的右连接的写法。
  • 外连接的查询结果条数一定 >= 内连接的查询结果条数
SELECT
	E.ENAME , D.DNAME
FROM 
	EMP E
RIGHT OUTER JOIN -- OUTER是可以省略的,带着可读性更强
	DEPT D
ON
	E.DEPTNO = D.DEPTNO;
上面等价于:
SELECT
	E.ENAME , D.DNAME
FROM 
	DEPT D
LEFT OUTER JOIN -- OUTER是可以省略的,带着可读性更强
	EMP E
ON
	E.DEPTNO = D.DEPTNO;

案例:查询每个员工的上级领导,要求显示所有员工的名字和领导名

SELECT
	A.ENAME AS '员工名', B.ENAME AS '领导名'
FROM 
	EMP A
LEFT OUTER JOIN 
	EMP B
ON
	A. MGR = B.EMPNO;
1.2.7.5 多表之间的连接

案例:找出每个员工的部门名称以及 工资等级,要求显示员工名、部门名、薪资、薪资等级

Mysql 输入字段like 数据库字段_sql_03

SELECT
	E.ENAME AS '员工名', D.DNAME AS '部门名', E.SAL AS '薪资' , S.GRADE AS '薪资等级'
FROM 
	EMP E
JOIN 
	DEPT D
ON
	E.DEPTNO = D.DEPTNO
JOIN 
	SALGRADE S
ON 
	E.SAL BETWEEN S.LOSAL AND S.HISAL;

1.2.8 子查询

子查询:select语句中嵌套select语句,被嵌套的select语句称为子查询。
子查询可以出现的位置:

SELECT
	..SELECT.
FROM
	..SELECT.
WHERE
	..SELECT.
1.2.8.1 where子句中的子查询

案例:找出比最低工资高的员工姓名和工资

SELECT 
	ENAME,SAL
FROM
	EMP
WHERE
	SAL > (SELECT MIN(SAL) FROM EMP);
1.2.8.2 from子句中的子查询

注意:from后面的子查询,可以将子查询的查询结果当成一张临时表
案例:找出每个工作岗位的平均工资的薪资等级

SELECT A.JOB,S.GRADE
FROM
 (SELECT JOB , AVG(SAL) FROM EMP E GROUP BY JOB) A
JOIN
	SALGRADE S
ON
 	A.AVG(SAL) BETWEEN S.LOSAL AND HISAL;
执行失败:> 1630 - FUNCTION a.AVG does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual
//上面的执行失败是因为avg是关键字,没有起别名
正确的如下:
SELECT A.JOB,S.GRADE
FROM
 (SELECT JOB , AVG(SAL) AS AVGSAL FROM EMP E GROUP BY JOB) A
JOIN
	SALGRADE S
ON
 	A.AVGSAL BETWEEN S.LOSAL AND HISAL;
1.2.8.3 select子句中的子查询(了解即可)

案例:找出每个员工的部门名称,要求显示员工名、部门名
注意:对于select后面的子查询来说,这个子查询只能一次返回1条记录,多于一条,就报错了

SELECT
	E.ENAME,E.DEPTNO,(SELECT D.DNAME FROM DEPT D WHERE E.DEPTNO = D.DEPTNO) AS DNAME
FROM
	EMP E;

错误示例:
SELECT
	E.ENAME,E.DEPTNO,(SELECT DNAME FROM DEPT ) AS DNAME
FROM
	EMP E;
报错:	
> Subquery returns more than 1 row
1.2.9 union可以合并集合

案例:查询工作岗位是MANAGER和SALEMAN的员工
注意:

  • UNION在mysql中使用的时候要求两个结果的列数相同;在oracle中语法严格,要求不仅要列数相同,还需要列的数据类型也一样。
法一:
SELECT ENAME, JOB FROM EMP WHERE JOB IN('SALESMAN','MANAGER');
法二:
SELECT ENAME, JOB FROM EMP WHERE JOB = 'SALESMAN' OR JOB = 'MANAGER';
法三:
SELECT ENAME, JOB FROM EMP WHERE JOB = 'SALESMAN'
UNION
SELECT ENAME, JOB FROM EMP WHERE JOB = 'MANAGER';

1.2.9 limit可以将查询结果的一部分取出来

limit可以将查询结果的一部分取出来,通常使用在分页查询中(例如百度查询,默认一页显示10条记录)。分页的作用是为了提高用户体验,因为一次将全部数据查出来,用户体验差。
案例:查询工资最高的前五名
LIMIT完整用法: limit StartIndex, length (StartIndex是起始下标,从0开始, length是长度)
limit在order by之后执行

SELECT
	ENAME, SAL
FROM
	EMP
ORDER BY 
	SAL DESC
LIMIT 5; -- 起始下标省略的话,默认取前五,相当于LIMIT 0,5

1.2.10 分页

公式:
每页显示PageSize条记录
第PageNo页:limit (PageNo-1) * PageSize,PageSize