SQL概述:SQL全称是Structured Query Language,SQL用来和数据库打交道,完成和数据库的通信,SQL是一套标准,但是每一个数据库都有自己的特性,当使用这个数据库特性相关的功能,这是SQL语句可能就不是标准了(90%以上的SQL都是通用的)
什么是数据库?
数据库(Database,简称DB)通常是一个或一组文件,保存了一些复合特定规格的数据; 数据库软件称为数据库管理系统(DBMS, Database Management System),如MySQL,Oracle, SQL Server, DB2等
MySQL概述
是一个关系型数据库管理系统,不仅是最流行的开源数据库,而且是业内成长最快的数据库。2009年,Oracle收购了sun公司,使MySQL并入Oracle的数据库产品线。
什么是数据库?什么是数据库管理系统?什么是SQL?他们之间的关系是什么?
数据库(Database,简称DB)通常是一个或一组文件,保存了一些复合特定规格的数据;
数据库管理系统,简称DBMS,是专门用来管理数据库中数据的,DBMS可以对数据库中的数据进行增删改查;
SQL是结构化查询语言,程序员需要学习SQL语句,通过编写SQL语句,执行SQL语句,最终来完成数据库中数据的增删改查;
关系:DBMS通过执行SQL语句来对DB进行管理。
安装MySQL数据库,先安装“经典版”,一路下一步就行了。
注意:①MySQL默认端口号为3306。端口号是任何一个应用/软件都会有的,端口号是应用的唯一代表,通常和IP地址搭配使用,IP地址用来定位计算机,端口号Port用来定位计算机上某个服务;②MySQL的字符编码方式为UTF-8;③MySQL超级管理员用户名为root,不能修改。
卸载MySQL:第一步双击安装包进行卸载,第二步删除C:\ProgramData下面MySQL目录,并且删除C:\Program File(x86)下的MySQL目录。
MySQL服务的启动与停止
计算机–>右键–>管理–>服务和应用程序–>服务–>找到MySQL服务。默认是自启动状态,可以再服务上点击右键进行启动、重启服务、停止服务等操作。
使用命令来启动和关闭服务: net stop 服务名称; net start 服务名称
数据库中用表来存储数据:表比较直观。任何一张表都有行和列:行(row):被称为数据/记录 。列(column):被称为字段,每一个字段都有字段名,数据类型,约束等属性。
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常用命令
需求 | 命令 |
---|---|
查询一个字段 | 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. 字段是可以参加加减乘除运算的
select 字段1,字段2,..., from 表名 where 条件;
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的
select name fro emp where name like %o% //查出名字中带有o的员工名字
select name fro emp where name like %\_% //找出名字中带有下划线的名字,“\”为转义字符
//查询所有员工薪资,排序,默认是升序
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 (排序总是在最后执行!)
数据处理函数又称为单行处理函数
单行处理函数:一个输入对应一个输出
多行处理函数: 多个输入,对应一个输出
常见的单行处理函数:
函数 | 作用 |
---|---|
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的时候,工资上调%,其他正常。(注意:不修改数据库,只是将查询结果显示为工资上调)
多行处理函数: 输入多行,最终输出一行
注意:
COUNT(*):统计表当中的记录的总行(只要有一行数据COUNT就++,而且表中不存在一行数据所有列都为空)
COUNT(具体字段):统计该字段下所有不为NULL的记录的总数
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;-- 求城市的个数
在实际应用中,可能有这样的需求,需要先进行分组,然后对每一组的数据进行操作,这个时候就需要使用分组查询
SELECT
...
FROM
...
WHERE
...
GROUP BY
...
ORDER BY
...
执行顺序: FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY
从某张表中查询数据
先经过WHERE条件筛选出有价值的数据。
对这些有价值的数据进行分组
分组之后可以使用HAVING继续筛选
Note:
SELECT MAX(SAL),DEPT,JOB FROM EMP ORDER BY DEPT ,JOB;
找出每个部门不同工作岗位的最高薪资
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)
DISTINCT: 去除重复记录
SELECT DISTINCT NAME FROM CITY;
SELECT DISTINCT NAME, POPULATION FROM CITY;-- DISTINCT只能出现在所有字段的最前方
//DISTINCT在NAME, POPULATION 前面,表示两者联合去重
SELECT COUNT(DISTINCT NAME) FROM CITY;-- 统计城市的数量
1.连接查询的分类
1.1 根据语法的年代分类:
SQL92: 1992年的时候出现的语法
SQL99: 1999年出现的语法
1.2 根据连接的方式分类:
内连接:
等值连接
非等值连接
自连接
外连接:
左外连接(左连接)
右外连接(右连接)
全连接(基本不用)
SELECT
E.ENAME,D.DNAME
FROM
EMP E,DEPT D -- 表起别名很重要 效率问题
WHERE
E.DEPTNO = D.DEPTNO
//SQL92语法
-- 最终查询的结果虽然减少,但是匹配的过程中,匹配的次数并没有减少。
注意:通过笛卡尔积现象可以得出,表的连接次数越多,效率越低,我们应该尽量避免表的连接次数
例:查询每个员工所在部门名称,显示员工名和部门名
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
筛选条件
例:找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级
SELECT
E.ENAME, E.SAL , S.GRADE
FROM
EMP E
JOIN
SALGRADE S
ON
E.SAL BETWEEN S.LOSAL AND S.HISAL; -- 条件不是等量关系,称为非等值连接
自连接:自己连接自己
技巧:将一张表看成两张表
案例:查询员工的上级领导,要求显示员工名和对应的领导名。
查询结果为13条数据,因为KING的领导为NULL
SELECT
A.ENAME AS '员工名', B.ENAME AS '领导名'
FROM
EMP A
JOIN
EMP B
ON
A. MGR = B.EMPNO;
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;
案例:找出每个员工的部门名称以及 工资等级,要求显示员工名、部门名、薪资、薪资等级
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;
子查询:select语句中嵌套select语句,被嵌套的select语句称为子查询。
子查询可以出现的位置:
SELECT
..SELECT.
FROM
..SELECT.
WHERE
..SELECT.
案例:找出比最低工资高的员工姓名和工资
SELECT
ENAME,SAL
FROM
EMP
WHERE
SAL > (SELECT MIN(SAL) FROM EMP);
注意: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;
案例:找出每个员工的部门名称,要求显示员工名、部门名
注意:对于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
案例:查询工作岗位是MANAGER和SALEMAN的员工
注意:
法一:
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';
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
公式:
每页显示PageSize条记录
第PageNo页:limit (PageNo-1) * PageSize,PageSize