只此一篇,让你掌握Mysql所有语法及用法

一、Mysql总结思维导图:


二、SELECT

(一)基础语法

1.查询所有的列*

SELECT * FROM 表名;
SELECT * FROM emp;
SELECT * FROM dept;
SELECT * FROM salgrade;

2.查询指定的列

SELECT 列名1,列名2...列名N FROM 表名;
SELECT ename,job,sal FROM emp;
SELECT deptno,dname FROM dept;

3.使用算术运算符(+ - * /)

-- 给所有员工增加300的薪水

SELECT ename,sal,sal+300 FROM emp; 


-- 注意运算符的顺序,如果想要改变顺序使用()括号
-- 查询员工的年薪,且为每个人发500的过节费

SELECT ename,sal,sal*12+500 FROM emp;


-- 为每位员工涨薪 50 ,查询员工的年薪

SELECT ename,sal,(sal+50)*12 FROM emp;

4.空值NULL

-- 空值是指不可用,不知道,不适用的值
-- 空值不是0 也不是空格

-- 计算员工的总的佣金(薪水+提成)

SELECT ename,sal,comm,(sal+comm)*12 FROM emp;


-- 空值不参与运算,如果想要空值参与运算必须将其转化成具体的数据

5.别名

/*
列名 别名
列名 AS 别名
列名 “别名”  -- 别名含有特殊字符,或者空格,或者大小写敏感,使用“”
*/

SELECT ename,sal FROM emp;
SELECT ename AS `name`,sal AS salary  FROM emp;
SELECT ename `name`,sal  salary  FROM emp;
SELECT ename,sal,comm,(sal+comm)*12  "Nian Xian" FROM emp;
SELECT ename,sal,comm,(sal+comm)*12  'Nian Xian' FROM emp;


-- 别名用于识别列的结果

6.去重操作  DISTINCT 

-- 在emp表中,有多少个部门编号

SELECT * FROM emp;
SELECT deptno FROM emp;
SELECT DISTINCT deptno FROM emp;

-- 多列去重
-- 每个部门对应的职位信息

SELECT DISTINCT job,deptno FROM emp;


-- DISTINCT 只能放在列名开头的位置,DISTINCT对select子句中的列都生效

(二)限定和排序数据

/*
SELECT 列名1,列名2,...列名N
FROM 表名
WHERE  限定条件   -- where子句要放在from子句的后面
ORDER BY 排序
*/

1.WHERE子句

-- 获取部门编号为10的雇员信息

SELECT deptno,ename,empno,job,sal,comm 
FROM emp
WHERE deptno = 10;


-- 查询员工姓名,部门编号,职位是CLERK的员工

SELECT ename,deptno,job FROM emp
WHERE job = 'CLERK';-- MySQL大小写不敏感,支持混合查询,但只在windows中,linux不支持

-- where子句中的限定条件的列,可以不出现在select子句的后面(不推荐)
-- 查询员工的姓名,职位,且仅展示年薪大于30000的员工

SELECT * FROM emp;
SELECT ename,job FROM emp
WHERE sal*12 > 30000;
SELECT ename,job,sal*12 nianxian FROM emp
WHERE sal*12 > 30000;

-- 注意:WHERE子句中不使用别名
-- 错误案例

SELECT ename,job,sal*12 nianxian FROM emp
WHERE nianxian > 30000;

2. 比较运算符 = <,>,<=,>=,!=,<>

-- 查询提成比薪水还高的员工姓名,薪水和提成

SELECT ename,sal,comm FROM emp
WHERE sal<=comm;

-- 查询出不在30号部门工作的员工姓名,薪水和员工编号

SELECT ename,sal,empno,deptno FROM emp
WHERE deptno <> 30;

3.其他的比较运算符

(1) BETWEEN...  AND ...  在两个值之间

-- 查询薪水在1500 到3000之间的所有员工

SELECT ename,sal FROM emp
WHERE sal BETWEEN 1500 AND 3000;


-- 查询结果为空

SELECT ename,sal FROM emp
WHERE sal BETWEEN 3000 AND 1500;

(2)IN 列出匹配的值

-- 查询职位是CLERK ,或者是salesman的所有员工信息

SELECT ename,job FROM emp
WHERE job IN('CLERK','SALESMAN');

(3) LIKE模糊匹配字符

%  表示匹配0个或者多个字符
_  表示匹配1个字符

-- 查询以字母S开头的所有员工姓名

SELECT ename FROM emp WHERE ename LIKE'S%';

-- 查询包含字母S的所有员工姓名

SELECT ename FROM emp WHERE ename LIKE'%S%';

-- 查询名字的第二个字符是C的所有员工姓名

SELECT ename FROM emp WHERE ename LIKE'_C%';

(4)IS NULL 匹配空值

-- 要求查询没有上级的员工

SELECT ename FROM emp WHERE mgr IS NULL;

-- 查询没有提成的所有员工信息

SELECT * FROM emp
WHERE comm IS NULL;

4.逻辑运算符 AND OR NOT

-- AND  表示所有条件都满足才返回结果
-- 查询薪水大于1100,且职位是CLERK的员工编号,员工姓名,职位,薪水

SELECT ename,job,sal FROM emp
WHERE sal> 1100
AND job ='CLERK';

-- OR 表示满足其中任意条件就返回结果
-- 查询薪水大于1100,或者职位是SALESMAN的员工编号,员工姓名,职位,薪水

SELECT ename,job,sal FROM emp
WHERE sal> 1100
OR job ='SALESMAN';


-- NOT 不包含
-- 查询职位不包含CLERK,SALESMAN,ANALYST的所有员工姓名,职位,薪水

SELECT ename,job,sal FROM emp
WHERE job  NOT IN('CLERK','SALESMAN','ANALYST');


-- 注意:运算符的优先级
-- 比较运算符 高于 逻辑运算符(NOT 高于AND 高于OR)
-- 查询职位是salesman 或者职位是president 且薪水大于1500的员工姓名,职位,薪水

SELECT ename,job,sal FROM emp
WHERE job = 'SALESMAN'
OR job = 'PRESIDENT'
AND sal> 1500;


-- 等同于

SELECT ename,job,sal FROM emp
WHERE job = 'SALESMAN'
OR (job = 'PRESIDENT'AND sal> 1500);

-- 正确的做法

SELECT ename,job,sal FROM emp
WHERE (job = 'SALESMAN' OR job = 'PRESIDENT')
AND sal> 1500;

5.排序 ORDER BY

-- ASC 升序 缺省  
-- DESC 降序
-- 按照员工的入职日期进行排序

SELECT ename,hiredate FROM emp 
ORDER BY hiredate ASC;


-- 等同于 

SELECT ename,hiredate FROM emp 
ORDER BY hiredate ;


-- 降序

SELECT ename,hiredate FROM emp 
ORDER BY hiredate DESC;

-- 同where子句,order by的列不一定出现在select子句的后面(不推荐)
-- 查询员工的入职日期和姓名,按薪水从高到低

SELECT ename,hiredate FROM emp 
ORDER BY sal DESC;
SELECT ename,hiredate,sal FROM emp 
ORDER BY sal DESC;

-- order by子句中可以使用别名
-- 按照年薪由高到低排序

SELECT ename,hiredate,sal*12 nianxian FROM emp 
ORDER BY nianxian DESC;

-- 多列排序
-- 查询员工姓名,部门编号,薪水,先按照部门编号升序排列,再按照薪水降序排列

SELECT ename,deptno,sal FROM emp 
ORDER BY deptno ASC,sal DESC;


-- 排序的列需要注意先后顺序

SELECT ename,deptno,sal FROM emp 
ORDER BY sal DESC,deptno ASC;

(三) 单行函数

什么是函数?
-- 在编程语言中,函数是为了实现特定功能的小程序,在很多高级语言中,都有一些给定的函数,也可以自己编写函数
-- 单行函数:函数对每行数据生效
-- MySQL函数大全
-- 常用:数学函数、字符函数、日期函数、条件判断函数

1:数学函数

ROUND,TRUNCATE,FLOOR,MOD 函数

(1) ROUND(m,n)

-- ROUND(m,n) 将数字m精确到小数点后n位(四舍五入),n如果不写,默认为0,表示取整

SELECT ROUND(4.333,2),ROUND(4.336,2),ROUND(4.333),ROUND(4.533) FROM DUAL;


-- dual是一张虚表,可以用来做临时的存储
-- 当n取负数,n表示精确到小数点左边第N位(四舍五入)

SELECT ROUND(127.333,-1),ROUND(127.333,-2),ROUND(127.333,-3), ROUND(527.333,-3) FROM DUAL;

(2) TRUNCATE(m,n)

-- TRUNCATE(m,n) 将数字m精确到小数点后n位(不支持四舍五入),不能省略N

SELECT TRUNCATE(4.333,2),TRUNCATE(4.336,2) FROM DUAL;


-- 取整需要将n设置为0

SELECT TRUNCATE(4.333,0),TRUNCATE(4.336,0) FROM DUAL;


-- n取负数,表示精确到小数点左边第N位(不支持四舍五入)

SELECT TRUNCATE(127.333,-1),TRUNCATE(127.336,-2),TRUNCATE(127.336,-3)  FROM DUAL;

(3) FLOOR(n)

-- FLOOR(n) 向下取整,返回小于等于n的最大整数(不支持四舍五入)

SELECT FLOOR(4.3),FLOOR(4.6) ,FLOOR(0),FLOOR(0.6)FROM DUAL;

(4) MOD(m,n)

-- MOD(m,n)返回m除以n的余数

SELECT MOD(11,3),MOD(9,3),MOD(23.45,7.8);


2.字符函数

(1)大小写转换LOWER,UPPER

-- LOWER(x) 将字符串x转换成小写

SELECT ename,deptno,job FROM emp
WHERE job='clerk';
SELECT ename,deptno,job FROM emp
WHERE LOWER(job)='clerk';

-- UPPER(x)将字符串x转换成大写

SELECT ename,deptno,job FROM emp
WHERE job= UPPER('clerk');


-- 以上哪种方式效率最高? UPPER这种方式效率更高

(2)字符处理函数

a.  CONCAT(s1,s2,...)

返回连接参数产生的字符串,一个或多个待拼接的内容,任意一个为NULL则返回值为NULL
ename job

SELECT CONCAT(ename,' is a ',job) FROM emp;

b. CONCAT_WS(x,s1,s2,...)

返回多个字符串拼接之后的字符串,每个字符串之间有一个X

SELECT * FROM emp
SELECT CONCAT_WS('-',empno,ename,sal,'sal') FROM emp;

c. length(x)

length(x) 返回字符串的长度

SELECT LENGTH('abcdefg') FROM DUAL;
SELECT ename,LENGTH(ename) FROM emp;

-- 查询员工姓名只有5个字符的员工姓名,编号,职位,薪水

SELECT ename,empno,job,sal FROM emp
WHERE LENGTH(ename)=5;

d. SUBSTR(x,m,n)

-- SUBSTR(x,m,n) 从字符串x的第m位开始取值,取n位

SELECT SUBSTR('abcdefg',3,2) FROM DUAL;


-- n如果不写,表示取m位后面的所有字符

SELECT SUBSTR('abcdefg',3) FROM DUAL;

-- 获取每个员工ename的最后一个字符

SELECT ename,SUBSTR(ename,LENGTH(ename))FROM emp


-- 当m为负数时,则从右往左取M位

SELECT ename,SUBSTR(ename,-1)FROM emp

3.日期和时间函数

(1)NOW()

NOW() 返回当前日期和时间;

SELECT NOW();


-- 查询员工在公司工作了多少周,且结果向下取整?

SELECT ename, FLOOR((NOW()-hiredate)/7) AS weeks FROM emp; -- 错误案例

SELECT ename,hiredate FROM emp 

(2)curdate()

SELECT CURDATE();
SELECT ename, FLOOR((CURDATE()-hiredate)/7) AS weeks FROM emp;-- 错误案例,日期类型不能直接参与数学计算

-- 对于MySQL来讲,我们可以直接用字符串类型查询出日期的结果

SELECT ename,hiredate FROM emp WHERE hiredate='1980-12-17'; 


-- datediff(m,n) 计算日期m-n的差值

SELECT DATEDIFF(CURDATE(),hiredate) FROM emp
SELECT ename,hiredate,CURDATE(),
FLOOR(DATEDIFF(CURDATE(),hiredate)/7) AS weeks FROM emp

(3)YEAR(DATE)

-- YEAR(DATE) 返回日期所在的年份
-- month(date) 返回日期所在的月份
-- day(date) 返回日期所在的天

SELECT YEAR(CURDATE()),MONTH(CURDATE()),DAY(CURDATE());

-- 查询1981年入职的员工

SELECT ename ,hiredate FROM emp
WHERE YEAR(hiredate)=1981;

4.条件判断函数

(1) IF

 IF(条件判断,value1,value2)如果条件判断为真,则返回value1的值,否则返回value2的值
-- 判断员工的薪水,如果薪水高于等于3000 显示高富帅,低于3000 显示 穷屌丝

SELECT ename,sal,IF(sal>=3000,'高富帅','穷屌丝') FROM emp;

(2)IF 嵌套

-- 判断员工的薪水,如果薪水高于等于3000 显示高富帅,在3000以下1000以上 显示 上班族  1000以下 穷屌丝

SELECT ename,sal,IF(sal>=3000,'高富帅',IF(sal<1000,'穷屌丝','上班族')) AS jibie FROM emp;
SELECT ename,sal,IF(sal>=3000,'高富帅',IF(sal>=1000,'上班族','穷屌丝')) AS jibie FROM emp;

(3) IFNULL(value1,value2)

-- IFNULL(value1,value2),如果value1不为空则返回自己,如果为空则返回value2
-- 计算年薪(薪水+提成)

SELECT ename,sal,comm,(sal+comm)*12 FROM emp; 
SELECT ename,sal,comm,(sal+IFNULL(comm,0))*12 FROM emp; 

(4) CASE 表达式

/*
CASE 表达式
WHEN value1 THEN result1
WHEN value2 THEN result2
...
WHEN valueN THEN resultN
ELSE resultN+1
END
*/
-- 公司计划给员工涨薪
-- clerk 涨200
-- salesman 涨50
-- manager 涨500
-- 其他人不变

SELECT ename,sal,job,deptno,
(CASE job
WHEN 'CLERK' THEN sal+200
WHEN 'SALESMAN' THEN sal+50
WHEN 'MANAGER' THEN sal+500
ELSE sal
END) AS zhangxin
FROM emp;

(四)多表查询

1.笛卡尔积-- 笛卡尔积
-- 集合A和集合B中所有元素组成的有序对叫做笛卡尔积,记做A*B
-- 查询emp表中员工姓名在dept表中所对应的部门名称
SELECT ename,dname FROM emp,dept; -- 56 row=14*4 全排列组合
-- 笛卡尔积是多表查询的理论基础
-- 多表查询在进行连接时,要避免出现笛卡尔积,语法如下:

SELECT table1.colunm,table2.column
FROM table1,table2
WHERE table1.column=table2.column

SELECT emp.ename,dept.dname FROM emp,dept
WHERE emp.deptno = dept.deptno;


-- WHERE子句中可以写连接条件(当连接N张表时,至少需要N-1个连接条件)
-- 多表查询的分类

2.等值连接(内连接)

-- 用等号连接多张表
-- 查询员工编号,员工部门,以及部门地址

SELECT emp.empno,emp.deptno,dept.deptno,dept.dname
FROM emp,dept
WHERE emp.deptno = dept.deptno;


-- 使用别名化简查询  

SELECT e.empno,d.deptno,d.dname
FROM emp e,dept d
WHERE e.deptno = d.deptno;


-- 说明:别名的化简最好是有意义的单词或者字母
-- 使用AND运算符附加查询条件
-- 显示KING的员工编号,姓名,部门号,部门地址

SELECT e.empno,e.ename,d.deptno,d.loc
FROM emp e,dept d
WHERE e.deptno = d.deptno
AND e.ename='KING';

3.非等值连接(内连接)

-- 除等号以外的其他符号连接

SELECT * FROM salgrade;


-- 要求查询出每个员工薪水对应的级别(姓名,薪水,等级),员工KING除外

SELECT e.ename,e.sal,s.grade
FROM emp e, salgrade s
WHERE e.sal BETWEEN s.losal AND s.hisal
AND e.ename <> 'KING';

4.外连接

(1)左外连

-- 当需要显示某些不满足条件的连接条件时,可以使用外连接
-- 左外连接LEFT OUTER JOIN  ON  返回左边表中的所有数据

SELECT e.empno,d.deptno,d.dname
FROM emp e LEFT OUTER JOIN dept d
ON e.deptno = d.deptno;

(2)右外连

-- 右外连接RIGHT OUTER JOIN  ON  返回右边表中的所有数据

SELECT e.empno,d.deptno,d.dname
FROM emp e RIGHT OUTER JOIN dept d
ON e.deptno = d.deptno;

(3) 全外连

-- 全外连接FULL OUTER JOIN  左右两张表所有的数据都要展示(MYSQL中不支持)
-- 在Oracle还支持另外一种左右连接的语法

SELECT e.empno,d.deptno,d.dname
FROM emp e,dept d
WHERE e.deptno = d.deptno(+); -- 左连接,右表补齐
SELECT e.empno,d.deptno,d.dname
FROM emp e,dept d
WHERE e.deptno(+) = d.deptno; -- 右连接,左表补齐

5.自连接

-- 把一张表看做两张表,在单张表内进行关联
-- 请将每个员工自己的名字和上级的名字都找出来  例如 smith  works for  ford

SELECT mgr FROM emp WHERE  ename='SMITH';   -- mgr7902
SELECT ename FROM emp WHERE  empno=7902;    -- ford


-- 把emp看做是两张表
员工表(empno,ename,job,mgr,hiredate,sal,comm,deptno)  emp w
经理表(empno,ename,job,hiredate,sal,comm,deptno)    emp m

SELECT w.ename,'works for', m.ename
FROM emp w,emp m
WHERE w.mgr=m.empno ; -- 员工表中的mgr,等于经理表中的empno


(五)多行函数

-- 多行函数:针对表中的多行数据做运算,得到一个或者一组结果
-- 常用的多行函数:聚合函数,分组函数

1.常用的聚合函数

-- 查询emp表中所有员工的平均工资,工资之和,最高工资和最低工资

SELECT  AVG(sal),SUM(sal),MAX(sal),MIN(sal) FROM emp;


-- 普通列不能和聚合函数一起作为select子句的条件,否则可能会报错,或者得到错误的结果


-- 聚合函数进行计算时会自动忽略空值,要空值参与运算需要用ifnull转化成0
-- 求emp表中提成的平均值

SELECT AVG(comm) ,COUNT(comm)FROM emp;
SELECT AVG(IFNULL(comm,0)) ,COUNT(IFNULL(comm,0))FROM emp;

-- 注意:聚合函数可以和普通的函数嵌套使用

SELECT ROUND(AVG(sal),2) FROM emp

-- 注意: 聚合函数不可以和聚合函数嵌套(MySQL不支持)

-- 计算每个职位的最高工资,然后再求和
-- 错误案例

SELECT SUM(MAX(sal))FROM emp 
GROUP BY  job;


(1)AVG 求平均

-- 查询emp表中所有员工的平均工资,工资之和,最高工资和最低工资

SELECT  AVG(sal),SUM(sal),MAX(sal),MIN(sal) FROM emp;


-- 普通列不能和聚合函数一起作为select子句的条件,否则可能会报错,或者得到错误的结果

(2)SUM 求和

(3)MAX 求最大值

-- 查询emp表中SALES部门员工的平均工资,工资之和,最高工资和最低工资

SELECT  AVG(sal),SUM(sal),MAX(sal),MIN(sal) 
FROM emp 
WHERE job LIKE 'SALES%';

-- min,max 函数可以针对数字类型之外的其他类型
-- 查询最早入职的员工和最晚入职的员工信息

SELECT MIN(hiredate),MAX(hiredate) FROM emp;

(4)MIN 求最小值

(5)COUNT 计数

-- count() 返回表中的记录数

SELECT COUNT(*) FROM emp;  -- 不推荐使用


-- 推荐使用count(1)代替* 提高查询效率

SELECT * FROM emp;
SELECT 1 FROM emp;
SELECT empno FROM emp;
SELECT COUNT(1) FROM emp;  
SELECT COUNT(empno) FROM emp;  -- 也可以指定统计的某个列

2. GROUP BY 分组函数

/*
SELECT 列名1,列名2..列名N 
FROM 表名
WHERE 限定条件 
GROUP BY  分组条件
HAVING 分组限定
ORDER BY 排序
*/
-- 计算每个职位的最高工资

SELECT job,MAX(sal) FROM emp  -- job是分组函数指定的列,可以和聚合函数一并查询
GROUP BY  job;


-- 按部门计算每个部门的平均工资

SELECT AVG(sal) FROM emp
GROUP BY deptno


-- 分组条件可以不写在select子句中(不推荐)

SELECT deptno,AVG(sal) FROM emp
GROUP BY deptno

-- 分组函数也可以单独使用(不和聚合函数一起用)
-- 查看哪些部门的人数大于5人

SELECT deptno FROM emp 
GROUP BY deptno 
HAVING COUNT(1)>5

-- 多列分组
-- 按部门分组统计emp表中各个职位的工资总和

SELECT deptno,job , SUM(sal) FROM emp
GROUP BY  deptno,job;


-- 等同于

SELECT deptno,job , SUM(sal) FROM emp
GROUP BY  job,deptno;

3. HAVING 子句 (分组限定)

-- 求平均工资高于2000的部门
-- 错误案例

SELECT deptno,AVG(sal) FROM emp
WHERE AVG(sal) > 2000;
GROUP BY deptno


-- 不能使用where子句限定聚合函数,可以用having子句限定

SELECT deptno,AVG(sal) FROM emp
GROUP BY deptno 
HAVING AVG(sal) > 2000;


-- 查询平均工资大于2900的部门,并展示出该部门的最高工资

SELECT deptno,MAX(sal) FROM emp
GROUP BY deptno
HAVING AVG(sal) >2900


-- 注意:select子句后面的聚合函数可以和having子句的聚合函数不同

-- 查询最高工资不低于3000的部门的人数

SELECT deptno,COUNT(1)
FROM emp
GROUP BY deptno
HAVING  MAX(sal) >= 3000;

4.where与having

-- 使用WHERE子句进行限定普通的列
-- 查询emp表中各个职位的薪水总和,只查询薪水总和大于5000的职位,且职位不是SALES开头的,并按照薪水总和降序排列

SELECT  job,SUM(sal) FROM emp
WHERE job NOT LIKE 'SALES%'
GROUP BY job 
HAVING SUM(sal)> 5000
ORDER BY SUM(sal) DESC;

-- HAVING子句可以支持普通的列和聚合函数的列,但having子句必须和group by一起使用,不能独立使用(group by可以不加having,但是having必须加group by)

SELECT  job,SUM(sal) FROM emp
GROUP BY job 
HAVING SUM(sal)> 5000 
AND job NOT LIKE 'SALES%'
ORDER BY SUM(sal) DESC;

-- 查询emp表中各个职位的薪水总和,只查询薪水总和大于5000的职位,且销售部(dept表)除外,并按照薪水总和降序排列

SELECT job, SUM(sal)
FROM emp e,dept d
WHERE e.deptno = d.deptno
AND d.dname <> 'SALES'
GROUP BY job
HAVING SUM(sal) > 5000
ORDER BY SUM(sal) DESC;

(六)子查询

-- 找出工资高于JONES的员工信息

子查询:SELECT sal FROM emp WHERE ename='JONES';  -- 2975
主查询:SELECT * FROM emp WHERE sal > 2975;


-- 子查询的规则
/*
子查询要用()括起来
习惯上子查询语句放在比较运算符的右边
子查询的语句一般不使用order by 排序
*/


1.单行子查询

-- 子查询的结果只返回一行数据,使用单行比较运算符 = <  > <= >= != <>

SELECT * FROM emp WHERE sal > 
(SELECT sal FROM emp WHERE ename='JONES');


-- 查询同ALLEN部门编号和职位都相同的员工 

SELECT deptno FROM emp WHERE ename='ALLEN';  -- 30
SELECT job FROM emp WHERE  ename='ALLEN'; -- SALESMAN

SELECT * FROM emp
WHERE deptno = (SELECT deptno FROM emp WHERE ename='ALLEN')
AND job = (SELECT job FROM emp WHERE  ename='ALLEN')


-- 子查询的数据可以和主查询不在同一张表中
-- 查询ALLEN所在的部门的名称
-- 子查询

SELECT dname FROM dept
WHERE deptno = 
(SELECT deptno FROM emp WHERE ename='ALLEN')


-- ename='ALLEN'   emp表中有14行数据 ename需要匹配14次
-- deptno=30       dept表中4行数据,depno需要匹配4次
-- 14+4=18次

-- 多表查询

SELECT d.dname,e.ename
FROM dept d,emp e
WHERE e.deptno=d.deptno
AND e.ename='ALLEN'


-- e.deptno=d.deptno   emp表中有14行数据,同d.deptno匹配需要14次
-- e.ename='ALLEN'     emp表中有14行数据 ename需要匹配14次
-- 14+14=28次

总结
-- 如果查询的最终结果来自一张表,用子查询和多表查询都可以实现,推荐子查询
-- 如果查询的最终结果来自多张表时,只能用多表查询

-- 子查询使用聚合函数
-- 查询薪水最高的员工的姓名,薪水,职位

SELECT ename,sal,job FROM emp
WHERE sal =
(SELECT MAX(sal) FROM emp);

-- 使用GROUP BY HAVING语句
-- 查询部门的平均工资,只显示高于所有员工平均工资的部门

SELECT deptno,AVG(sal)
FROM emp
GROUP BY deptno 
HAVING AVG(sal) > (SELECT AVG(sal) FROM emp);


-- 查询薪水高于30号部门最低工资的,其他部门的最低工资

SELECT deptno,MIN(sal)
FROM emp
GROUP BY  deptno
HAVING MIN(sal)>
(SELECT MIN(sal) FROM emp WHERE deptno = 30)

2.多行子查询

-- 子查询的结果返回多个记录,使用多行比较运算符 IN,ANY,ALL
-- 查询每个部门最低薪水的员工编号和姓名
-- IN 匹配列中的多个数据

SELECT empno,ename ,sal,deptno FROM emp
WHERE sal IN
(SELECT MIN(sal) FROM emp GROUP BY deptno);

-- ANY
-- 查询职位比CLERK 最高薪水还少(小于最大值)的其他职位的员工信息

SELECT ename,job,sal FROM emp
WHERE sal < ANY
(SELECT  sal FROM emp WHERE job='CLERK');


-- 等同于

SELECT ename,job,sal FROM emp
WHERE sal <
(SELECT MAX(sal) FROM emp WHERE job='CLERK');

-- < ANY 小于最大值,> ANY 大于最小值

SELECT ename,job,sal FROM emp
WHERE sal > ANY
(SELECT  sal FROM emp WHERE job='CLERK');

-- <ALL 小于最小值,> ALL 大于最大值

SELECT ename,job,sal FROM emp
WHERE sal < ALL
(SELECT  sal FROM emp WHERE job='CLERK');
SELECT ename,job,sal FROM emp
WHERE sal > ALL
(SELECT  sal FROM emp WHERE job='CLERK');

3.多列子查询(多行多列子查询)

-- 使用IN进行匹配
-- 查询同ALLEN部门编号和职位都相同的员工 

SELECT * FROM emp
WHERE (deptno,job) IN (SELECT deptno,job FROM emp WHERE ename='ALLEN')


-- 子查询中的列必须和主查询中的列关系对应

4.将子查询的结果看作是一张表,再进行二次查询

-- 子查询语句直接放在FROM 的后面,当做一张表,取别名
-- 查询职位是CLERK的最低工作和最高工作之和

SELECT MIN(sal),MAX(sal) FROM emp
WHERE job='CLERK'
SELECT lo+hi FROM
(SELECT MIN(sal) lo ,MAX(sal) hi,job FROM emp
GROUP BY job) ssal
WHERE job='CLERK';

-- 等同于

SELECT MIN(sal)+MAX(sal) FROM emp
WHERE job='CLERK'

-- 查询每个部门的部门名称,所在地和人数,并且部门人数不低于5人

SELECT d.dname,d.loc,c.ct
FROM dept d, 
(SELECT deptno,COUNT(1) ct FROM emp
GROUP BY deptno) c
WHERE d.deptno=c.deptno
AND c.ct >= 5;

5.分页子查询

-- limit m,n 从第m+1行开始取数据,取n行结束
-- limit的位置是在整个select语句的最后

SELECT * FROM emp
LIMIT 3,4

-- 查询工资排名前三位的员工信息

SELECT * FROM emp
ORDER BY sal DESC
LIMIT 0,3   -- 0可以省略


-- 查询工资排名前三位的员工信息,如果有并列的也一并展示

SELECT * FROM emp
WHERE sal IN
(SELECT * FROM
(SELECT DISTINCT sal FROM emp
ORDER BY sal DESC
LIMIT 3) a);


(七)表的集合操作

-- 当查询条件比较复杂时,可以使用集合操作将多个查询语句进行组合
-- 将每个查询结果看作是多行数据的集合,集合与集合之间可以用UNION,UNION ALL连接

-- 查询薪水大于2500,或者职位是manager的员工

SELECT ename,sal,job FROM emp WHERE  sal > 2500
UNION
SELECT ename,sal,job FROM emp WHERE  job = 'MANAGER';


 
-- 等同于OR

SELECT ename,sal,job FROM emp WHERE  sal > 2500
OR job = 'MANAGER';

-- UNION ALL 展示两边查询的所有结果,不去重

SELECT ename,sal,job FROM emp WHERE  sal > 2500
UNION ALL
SELECT ename,sal,job FROM emp WHERE  job = 'MANAGER';


-- 查询工资排名前三的员工或者查询高于自己部门平均工资的员工的姓名,部门和职位

SELECT ename,deptno,job FROM emp
WHERE sal IN
(SELECT * FROM
(SELECT DISTINCT sal FROM emp
ORDER BY sal DESC
LIMIT 3) a)
UNION
SELECT e.ename,e.deptno,e.job FROM  emp e,
(SELECT deptno,AVG(sal) asal FROM emp GROUP BY deptno) a
WHERE e.deptno=a.deptno
AND e.sal > a.asal;

-- UNION 在连接两个select语句时,以第一个查询语句的列为准
-- UNION可以连接N张不同的表,只要列的数据类型和大小相同即可
-- 查询所有“女”教师和“女”同学的NAME、sex和birthday.  (学生信息表)

SELECT Tname,Tsex,Tbirthday FROM Teacher WHERE Tsex = '女'
UNION
SELECT Sname,Ssex,Sbirthday FROM Student WHERE Ssex = '女';


-- MySQL不支持 交集(INTERSECT) 差集(minus) 
-- 交集:只取两个查询语句都满足的记录
-- 差集:查询出第一个查询条件中存在,但在第二个查询结果中不存在的数据


86期SQL语句板书(select部分).sql

事务TCL

COMMIT 提交
ROLLBACK 回滚
SAVEPOINT  设置回滚点

SET autocommit = 0; 表示手动提交事务,=1则表示自动提交事务(默认值)

参见: 1.INSERT 插入 (扩展)

什么是事务?

-- 包含SQL语句的一个执行整体,对DML操作语句生效(对其他操作语句无效)
-- MySQL默认自动提交事务,可以通过命令来修改默认值

-- 实际应用场景
ATM转账   A卡向B卡转账,结果A卡扣款成功,B卡到账失败  ——回滚A卡的数据
电商订单  确认订单后,商品库存被扣减,如果下订单失败,则商品库存需要回滚到下订单之前

示例

-- 在emp表中插入一条记录

INSERT INTO employees.emp 
    (empno, 
    ename, 
    job, 
    mgr, 
    hiredate, 
    sal, 
    comm, 
    deptno
    )
    VALUES
    (6666, 
    'XIAOMING', 
    'DEVELOPMENT', 
    '7788', 
    CURDATE(), 
    '2000', 
    NULL, 
    50
    );
SELECT * FROM emp;
SAVEPOINT A;
INSERT INTO employees.emp 
    (empno, 
    ename, 
    job, 
    mgr, 
    hiredate, 
    sal, 
    comm, 
    deptno
    )
    VALUES
    (7777, 
    'XIAOMING', 
    'DEVELOPMENT', 
    '7788', 
    CURDATE(), 
    '2000', 
    NULL, 
    50
    );


-- 要求还原到上一组插入的数据,如何回滚?

ROLLBACK TO SAVEPOINT A;
SELECT * FROM emp;

ROLLBACK ;  -- 直接回滚则是回滚到最初设置事务的位置

SELECT * FROM emp;


-- 事务一旦提交,则直接对数据库服务器中的数据生效,不能再次回滚

三、非SELECT

(一)语言基础

1.分类

-- 按照SQL92、99标准 分为4大类
1:数据操作语言(DML) SELECT 查询,INSERT 插入,UPDATE 更新,DELETE 删除, 
2:数据定义语言(DDL) CREATE 创建,ALTER修改结构,DROP 删除 ,TRUNCATE 删除 等语句
3:事务处理语言(TCL) COMMIT 提交,ROLLBACK 回滚事务 等语句
4:数据控制语言(DCL) GRANT 授权,REVOKE 解除授权,

说明:也可以把SELECT 作为数据操作语言(DQL)

2.SQL语句的语法规范

- SQL语句的语法规范
 1. SQL语句的所有表名、字段名全部小写,系统保留字、内置函数名、SQL保留字大写。
 2. 连接符OR、IN、AND、以及=、<=、>=等前后加上一个空格。
 3. 对较为复杂的SQL语句、存储过程、函数加上注释,说明算法、功能。
-- 单行注释
/*
多行注释
*/ 
 4. SQL语句的缩进风格
 1) 一行有多列,超过80个字符时,基于列对齐原则,采用下行缩进 
 2) WHERE子句书写时,每个条件占一行,语句另起一行时,以保留字或者连接符开始,连接符右对齐。 
 5. 多表连接时,使用表的别名来引用列。

3.其他注意事项

1. SQL 命令大小写不敏感
2. SQL 命令可写成一行或多行
3. 一个关键字不能跨多行或缩写
4. 子句通常位于独立行,以便编辑,并易读 
5. SQL语句用分号作为分隔符,系统读取到分号才会执行语句

(二) 表管理DDL语句

数据定义语言(DDL) CREATE 创建,ALTER修改结构,DROP 删除 ,TRUNCATE 删除 等语句

1.新建表

CREATE TABLE 表名
(
列名1 数据类型 [DEFAULT 默认值][列级约束1,列级约束2 ……],
列名2 数据类型 [DEFAULT 默认值][列级约束1,列级约束2 ……],
...,
列名n 数据类型 [DEFAULT 默认值][列级约束1,列级约束2 ……],
[CONSTRAINT 约束名称 约束类型(列名)],
[CONSTRAINT 约束名称 约束类型(列名)],
...
);

表名的命名规则

1)必须以字母开头
2)可包括数字
3)只能包含A-Z, a-z, 0-9, _, $, AND #
4)不要使用MySQL的保留字
5)同一用户的表对象不能同名

数据类型

CHAR(10): 定长字符串    输入LUCY ,结果将占有10个字符
VARCHAR(10):变长字符串  输入LUCY,结果将占有4个字符
ENUM('男','女')

插入一条数据

CREATE TABLE student
(
学号 INT(5),
姓名 VARCHAR(20),
年龄 TINYINT(2),
性别 CHAR(1),
系名 VARCHAR(10),
身份证号 VARCHAR(18),
专业号 INT(4)
)
CHARACTER SET = utf8; -- 创建表时数据支持中文字符样式

SELECT * FROM student;-- 查看表数据
DESC student; -- 查看表结构

-- 插入一条数据

INSERT INTO student
VALUES(20204,'王小明',19,'女','经济系','510839199810106670',1001);

INSERT INTO student(学号,姓名,系名)
VALUES(20305,'黄大鹏','管理系');

INSERT INTO student
VALUES
(20506,'张文斌',18,'女','外语系','510639199905183452',1005),
(20507,'张文',18,'男','外语系','510639199905183433',1005),
(20508,'张文',19,'男','外语系','510639199905183499',1005);

2.修改表结构

-- 不推荐在建表完成后去修改表结构,特别是表中已经有数据的情况
-- 修改默认值
ALTER TABLE 表名 ALTER COLUMN 列名 SET DEFAULT 默认值;
-- 删除默认值
ALTER TABLE 表名 ALTER COLUMN 列名 DROP DEFAULT 默认值;

ALTER TABLE student ALTER COLUMN 性别 SET DEFAULT '女';

INSERT INTO student(学号,姓名,系名)
VALUES(20601,'黄小明','表演系');

SELECT * FROM student;

添加/删除列

ALTER TABLE 表名 ADD 列名 数据类型;
ALTER TABLE 表名 DROP 列名;

ALTER TABLE student  ADD 联系电话 VARCHAR(11);
ALTER TABLE student  DROP 联系电话;

修改列名

ALTER TABLE 表名 CHANGE COLUMN 旧列名 新列名 新列的数据类型;-- 添加/修改列
ALTER TABLE 表名 MODIFY COLUMN 列名 数据类型;-- 修改数据类型

ALTER TABLE student CHANGE COLUMN 系名 院系名 VARCHAR(20);
ALTER TABLE student MODIFY COLUMN 姓名 VARCHAR(40);
DESC student;

3.删除表

TRUNCATE TABLE 表名;-- 删除表中所有的数据,不能删除部分数据,全部删除
DROP TABLE 表名;--  删除整张表结构,含数据

TRUNCATE TABLE student;
SELECT * FROM student;
DROP TABLE student;

(三)表的约束

-- 约束的种类
DEFAULT -- 默认值
PRIMARY KEY -- 主键约束
FOREIGN KEY -- 外键约束
NOT NULL -- 非空约束
UNIQUE -- 唯一约束
AUTO_INCREMENT  -- 自增约束

1.在创建表时增加约束

CREATE TABLE student2
(
学号 INT(5) PRIMARY KEY,
姓名 VARCHAR(20) NOT NULL,
年龄 TINYINT(2) DEFAULT 18,
性别 ENUM('男','女') NOT NULL  DEFAULT '女',
系名 VARCHAR(10),
身份证号 VARCHAR(18),
专业号 INT(4)
)
CHARACTER SET = utf8;

SELECT * FROM student2;
DESC student2;

-- 创建course表

CREATE TABLE course
(
专业号 INT(5) PRIMARY KEY AUTO_INCREMENT,
专业名称 VARCHAR(20) NOT NULL
)
CHARACTER SET = utf8;

SELECT * FROM course;

2.建表后增加约束

-- AUTO_INCREMENT默认从1开始自增,可以通过赋值改变初始值

ALTER TABLE  course AUTO_INCREMENT = 1001;
INSERT INTO  course(专业名称)
VALUES ('金融学');
INSERT INTO  course(专业名称)
VALUES ('国际金融与贸易');

-- 为student2表添加一个非空约束
ALTER TABLE 表名  MODIFY  列名 数据类型 NOT NULL;

ALTER TABLE student2 MODIFY 系名 VARCHAR(10) NOT NULL;
DESC student2

-- 为student2表添加一个唯一约束
ALTER TABLE 表名  ADD UNIQUE(列名);
ALTER TABLE student2  ADD UNIQUE(身份证号);

INSERT INTO student2
VALUES(20204,'王小明',19,'女','经济系','510839199810106670',1001);

INSERT INTO student2
VALUES(20205,'王小明',19,'女','经济系','510839199810106670',1001);

INSERT INTO student2
VALUES(20205,'王小明',19,'女','经济系','510839199810106671',1001);

INSERT INTO student2
VALUES(20205,NULL,19,'女','经济系','510839199810106671',1001);

SELECT * FROM student2;


-- 为student2表中的专业号设置外键约束
ALTER TABLE 从表名 ADD CONSTRAINT 外键名
FOREIGN KEY(从表的外键字段) REFERENCES 主表(主键字段);--  student2 表是从 ,course表是主表

ALTER TABLE student2 ADD CONSTRAINT FK_student2_course
FOREIGN KEY(专业号) REFERENCES course(专业号);

DESC student2


-- 查看表中的各种约束条件

SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE constraint_schema = 'studentinfo2';


-- 查看创建的表的整体结构
SHOW CREATE TABLE 表名;

SHOW CREATE TABLE student2;
CREATE TABLE `student2` (
  `学号` INT(5) NOT NULL,
  `姓名` VARCHAR(20) NOT NULL,
  `年龄` TINYINT(2) DEFAULT '18',
  `性别` ENUM('男','女') NOT NULL DEFAULT '女',
  `系名` VARCHAR(10) NOT NULL,
  `身份证号` VARCHAR(18) DEFAULT NULL,
  `专业号` INT(4) DEFAULT NULL,
  PRIMARY KEY (`学号`),
  UNIQUE KEY `身份证号` (`身份证号`),
  KEY `FK_student2_course` (`专业号`),
  CONSTRAINT `FK_student2_course` FOREIGN KEY (`专业号`) REFERENCES `course` (`专业号`)
) ENGINE=INNODB DEFAULT CHARSET=utf8


(四)表的操作(DML语句)

1.INSERT 插入

-- 全量数据插入,插入的数据,顺序必须和建表时的顺序一致
INSERT INTO 表名
VALUES(value1,value2...valueN);
-- 按照自定义的列进行数据的插入
INSERT INTO 表名(列名1,列名2,列名3...列名N)
VALUES(value1,value2...valueN);
-- 批量插入数据,插入的数据,顺序必须和建表时的顺序一致
INSERT INTO 表名
VALUES
(value1,value2...valueN),
(value1,value2...valueN),
(value1,value2...valueN);

SELECT * FROM dept;
-- 要求在部门表中插入一条记录
INSERT INTO dept
VALUES(50,'DEVELOPMENT','BEIJING');
-- dept表按指定列再次插入一行数据
INSERT INTO dept(deptno,dname)
VALUES(60,'MIS');
-- 注意空值的处理
INSERT INTO dept
VALUES(70,'TESTTEAM',NULL);

参见: 事务TCL (扩展)

从其他表中插入数据到当前表insert + select

-- 把有提成的员工信息,导入到bonus表中

CREATE TABLE bonus
(
ename VARCHAR(10),
job VARCHAR(9),
sal FLOAT(7,2),
comm FLOAT(7,2)
)
SELECT * FROM bonus;

-- INSERT INTO 表名 SELECT 完整查询语句

INSERT INTO bonus
SELECT ename,job,sal,comm FROM emp 
WHERE comm IS NOT NULL;

DESC emp

2. UPDATE 修改

UPDATE 表名
SET 列名1=value1,列名2=value2....列名N=valueN
WHERE 限定条件

-- 调整dept表中50号部门的地址

UPDATE dept
SET loc='CHENGDU' WHERE deptno = 50;
SELECT * FROM dept

-- 想要给emp表中所有员工+200元 其中KING不加薪水

UPDATE emp
SET sal=sal+200 WHERE ename <> 'KING';
SELECT * FROM emp;

-- UPDATE语句中的set和where后面都可以使用子查询语句,但不能是对同一张表的操作
-- 将所有工资比ALLEN高的员工,薪水改成和ALLEN一样
-- 错误案例

UPDATE emp 
SET sal = (SELECT sal FROM emp WHERE ename = 'ALLEN') 
WHERE sal > (SELECT sal FROM emp WHERE ename = 'ALLEN');

UPDATE emp d,(SELECT e.sal FROM emp e WHERE e.ename='ALLEN') a SET d.sal = a.sal
WHERE d.sal >a.sal;

-- 将RESEARCH部门所有员工的上级改为King

UPDATE emp
SET mgr = (SELECT empno FROM (SELECT empno FROM emp WHERE ename='KING') a)
WHERE deptno= (SELECT deptno FROM dept WHERE dname= 'RESEARCH')


-- 另一种解法

UPDATE emp e,dept d SET mgr = 7902 WHERE e.deptno=d.deptno
AND d.dname='research';

SELECT * FROM emp WHERE deptno=20 

ROLLBACK;

3. DELETE 删除

DELETE [FROM] 表名
WHERE 限定条件 -- 如果delete不加where条件,则表示删除表中的所有数据

SELECT * FROM bonus;
DELETE FROM bonus;
COMMIT;

-- 删除dept表中50,60,70号部门

DELETE FROM dept WHERE deptno IN(50,60,70) ;
SELECT * FROM dept;
COMMIT;

-- 使用子查询删除数据
-- 删除sales部门的所有员工信息

DELETE FROM emp
WHERE deptno = (SELECT deptno FROM dept WHERE dname='SALES');
SELECT * FROM emp;
ROLLBACK;

注意:请先关闭自动提交事务功能 SET autocommit=0;

(五)常用数据库对象

1.视图

-- 视图是查询数据的快捷方式,视图不存储数据,存储的是一个查询语句
/*
CREATE VIEW 视图名称
(别名1,别名2,别名3...别名N)
AS
SELECT -- 一个完整的查询语句


1)新建视图

【用法一】针对不同的用户,提供不同的权限(权限控制)

-- HR,BOSS 想要查看每个员工的薪水

SELECT empno,ename,sal FROM emp;

-- 20号部门的经理,要求只能查询自己部门的员工薪水

SELECT empno,ename,sal FROM emp WHERE deptno = 20;

CREATE VIEW v_dept20
AS
(SELECT * FROM emp WHERE deptno = 20);

SELECT * FROM v_dept20   -- 视图和表的用法相同


-- 对视图进行操作,为SMITH涨薪水 200

UPDATE v_dept20
SET sal=sal+200
WHERE ename='SMITH';

Q: 请问emp表SMITH的薪水是多少? -- 1000 修改视图的数据等于修改原表的数据 

SELECT empno,ename,sal FROM emp WHERE ename='SMITH'; 

【用法二】简化复杂的查询语句

-- 通过部门名称查询该部门的平均工资

SELECT AVG(e.sal)
FROM emp e,dept d
WHERE e.deptno=d.deptno
AND d.dname='SALES';

-- 视图

CREATE VIEW v_avgsal
AS
(SELECT e.*,d.dname,d.loc FROM emp e,dept d WHERE e.deptno=d.deptno);

SELECT * FROM v_avgsal;
SELECT AVG(sal) FROM v_avgsal WHERE dname='SALES'

2)删除视图

-- DROP VIEW 视图名称

DROP VIEW  v_dept20;  -- 删除视图,实际上只是删除了一个select语句,不会影响到原表的数据
DROP VIEW  v_avgsal;  
SELECT * FROM emp

2.索引 INDEX

Q:什么是索引?
-- 索引(INDEX)类似书的目录,是供服务器在表中快速查找和操作行的数据库结构
-- 索引是以列为单位建立的,经常作为查询条件的列,可以创建索引来提高查询效率

Q:索引设计原则
-- 经常出现在where,order by,group by后面的列可以创建索引
-- 有大量空值的列,数据频繁改动的列,不经常作为查询条件的列不要创建索引
-- 当某个数据具有唯一性特征时,可以指定唯一索引,以确保数据的完整性,提高查询速度

Q:优点
-- 可以大大提高数据的查询速度,这是建索引的主要原因
-- 索引的内部结构由系统自动创建,每次对数据的修改索引也会自动更新
-- 在创建主键约束和唯一约束时,会自动创建主键索引和唯一索引,保证每行数据的唯一性

Q:不足
-- 索引虽然提高了查询速度,同时却会降低更新表的速度,因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。
-- 建立索引会占用磁盘空间的索引文件,每个表至少支持16个索引(依据存储引擎的不同而有所区别)

1)普通索引

普通索引——允许在定义的索引列中插入重复的值/空值
-- 创建普通索引
CREATE INDEX 索引名称 ON 表名(列名(`length`)); -- 如果是BLOB,TEXT数据类型,必须制定length
-- 为ename字段创建索引

CREATE INDEX ind_ename ON emp(ename);


-- 添加索引

ALTER TABLE emp ADD INDEX ind_mgr(mgr);

-- 查看索引

SHOW INDEX FROM emp

-- 在建表时添加索引

CREATE TABLE  mytable
(
id INT PRIMARY KEY,
myname VARCHAR(20),
INDEX ind_myname(myname)
);

SELECT * FROM mytable;

2)唯一索引唯一索引——索引的列数据必须唯一,但允许有空值NULL,如果是组合索引,则列值的组合必须唯一
-- 创建索引
CREATE UNIQUE INDEX 索引名称 ON 表名(列名(`length`));
-- 添加索引
ALTER TABLE 表名 ADD UNIQUE INDEX 索引名称(列名(`length`));
-- 在建表时添加索引

CREATE TABLE  mytable1
(
id INT PRIMARY KEY,
myname VARCHAR(20),
UNIQUE ind_myname(myname)
);

SHOW INDEX FROM mytable1

-- 当经常使用多个组合条件进行查询时使用组合索引

CREATE INDEX ind_job_deptno ON emp(job,deptno);
SHOW INDEX FROM emp


-- 如果查询条件只有job,该索引生效
-- 如果查询条件是job和deptno 该索引生效
-- 如果查询条件是deptno 该索引不生效

3) 删除索引

DROP  INDEX 索引名称 ON 表名;

DROP  INDEX ind_job_deptno ON emp;
DROP  INDEX ind_mgr ON emp;
DROP  INDEX ind_ename ON emp;

【注意】索引的限制条件
A.MyISAM存储引擎支持的索引引键长度不超过1000字节
B.MySQL目前不支持函数索引
C.使用!= ,<> 不能使用索引

SELECT * FROM emp
WHERE ename <> 'ALLEN';

SELECT * FROM emp
WHERE ename < 'ALLEN'
OR ename > 'ALLEN'

D. LIKE不能以%开头,无法使用索引

(六)存储过程  Stored PROCEDURE (SP)

-- 简单来说,存储过程是一条或者多条SQL语句的集合
-- 存储过程能够实现较复杂的数据处理
-- MYSQL中的编程主要是在存储过程中实现的

-- 实际应用场景
-- 业务场景,部分业务逻辑被写入了SP中 举例:电商业务中,生成一张订单:插入数据到订单表;商品信息表修改商品数量,插入一条日志信息
-- 构建一整套测试数据  举例: 准备100个注册用户信息;准备N条日志测试翻页

DELIMITER //
CREATE PROCEDURE 存储过程名称(参数列表)
BEGIN 
程序主体;
END //
DELIMITER ;

-- DELIMITER //是告诉系统不要将分号作为分隔符,而是将//作为分隔符
-- DELIMITER ;是告诉系统请使用分号作为后续的分隔符

-- 参数列表
IN 参数名称 参数类型  -- 输入参数
OUT 参数名称 参数类型 -- 输出参数
INOUT 参数名称 参数类型 -- 也可以输入也可以输出的参数(不推荐)
-- 调用存储过程
CALL 存储过程名称(参数列表)

1.示例

-- 查看该表的存储过程

SELECT * FROM information_schema.ROUTINES

-- 删除存储过程
DROP PROCEDURE 存储过程名称

DROP PROCEDURE pro_empno;
DROP PROCEDURE pro_hello;
DROP PROCEDURE pro_empno_avgsal;

编写一个存储过程,输出 hello kitty

DELIMITER //
CREATE PROCEDURE pro_hello()
BEGIN 
SELECT "hello kitty";
END //
DELIMITER ;

CALL pro_hello();

编写一个带参数的存储过程

-- 输入一个员工编号,查询出该员工的薪水

DELIMITER //
CREATE PROCEDURE pro_empno(IN paramA INT)
BEGIN 
SELECT sal FROM emp
WHERE empno = paramA ;
END //
DELIMITER ;
CALL pro_empno(7839);

-- 输入一个员工编号,返回其所在部门的平均工资
-- SELECT ... INTO... 给变量/参数赋值

DELIMITER //
CREATE PROCEDURE pro_empno_avgsal(IN paramA INT,OUT paramB FLOAT)
BEGIN 
SELECT AVG(sal) INTO paramB FROM emp
WHERE deptno =
(SELECT deptno FROM emp WHERE empno = paramA);
END //
DELIMITER ;

-- @+变量名称声明一个会话变量,作用域是整个会话

CALL pro_empno_avgsal(7788,@sal);
SELECT @sal;

2.控制结构

(1)IF 条件控制

/*
IF 条件判断1 then 执行语句1;
elseif  条件判断2 then 执行语句2;
...
elseif  条件判断N then 执行语句N;
else 执行语句N+1;
END IF;
*/

示例

-- 输入一个部门编号,计算出该部门的平均工资
-- 如果平均工资低于1800,给该部门的员工涨薪300

DELIMITER //
CREATE PROCEDURE pro_sal(IN paramA INT)
BEGIN 
DECLARE avgsal FLOAT(7,2); -- 声明一个变量

SELECT AVG(sal) INTO avgsal FROM emp
WHERE deptno = paramA;

IF avgsal < 1800 THEN  UPDATE emp SET sal=sal+300 WHERE deptno = paramA;
END IF;

END //
DELIMITER ;

-- DECLARE 变量名 数据类型 [default 默认值] 
-- 该变量值只能在存储过程中使用 ,称为存储过程变量

CALL pro_sal(30);
SELECT AVG(sal) FROM emp WHERE deptno = 30;
SELECT * FROM emp WHERE deptno = 30;

ROLLBACK;
-- DROP PROCEDURE pro_sal;

(2)循环控制

/*
while 进入循环的条件 DO
循环体;
end while;
*/

示例-- 创建一张表reg,用来存储用户的注册信息
-- 包含2个列 uname作为主键,upass 不能为空
-- 往表中插入100条数据

CREATE TABLE reg
(
uname VARCHAR(20) PRIMARY KEY,
upass VARCHAR(20) NOT NULL
);

SELECT * FROM reg

DELIMITER //
CREATE PROCEDURE pro_testdate(IN username VARCHAR(20),IN passwd VARCHAR(20), IN n INT)
BEGIN 

DECLARE varA INT DEFAULT 0;

WHILE varA < n DO
INSERT INTO reg
VALUES(CONCAT(username,varA),CONCAT(passwd,varA));

SET varA=varA+1;
END WHILE;

END //
DELIMITER ;

CALL pro_testdate('test','pass',100);

SELECT * FROM reg

-- drop table reg;
-- DROP PROCEDURE pro_testdate;
-- SELECT * FROM information_schema.ROUTINES


86期SQL语句板书(非select部分).sql

四、函数大全

Mysql函数大全_进击的雷神的博客-CSDN博客

数据库中的中英文术语大全_进击的雷神的博客-CSDN博客

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MySQL是一种流行的关系型数据库管理系统,广泛应用于企业级应用程序和网站等领域。在进行数据查询时,MySQL提供了多种语句和操作,本篇实验总结将介绍在MySQL中如何进行数据查询。 1. 数据库连接 在进行数据查询前,需要先连接到数据库。可以使用以下命令: ``` mysql -u username -p ``` 其中,`-u`参数指定用户名,`-p`参数提示输入密码。成功登录后,将看到MySQL的命令行提示符。 2. 数据库选择 连接到MySQL后,需要选择要查询的数据库。可以使用以下命令: ``` use database_name; ``` 其中,`database_name`为要查询的数据库名称。成功选择数据库后,将看到MySQL的命令行提示符显示当前所在的数据库。 3. 数据查询 在MySQL中,可以使用`SELECT`语句进行数据查询。以下是`SELECT`语句的基本语法: ``` SELECT column_name1, column_name2, ... FROM table_name WHERE condition; ``` 其中,`column_name`为要查询的列名,`table_name`为要查询的表名,`condition`为查询条件。可以使用`*`表示查询所有列。 例如,以下命令将查询`students`表中的所有数据: ``` SELECT * FROM students; ``` 以下命令将查询`students`表中`name`和`age`两列的数据: ``` SELECT name, age FROM students; ``` 4. 数据过滤 在MySQL中,可以使用`WHERE`子句进行数据过滤。以下是`WHERE`子句的基本语法: ``` SELECT column_name1, column_name2, ... FROM table_name WHERE condition; ``` 其中,`condition`为过滤条件。常用的比较运算符包括`=`、`<>`、`>`、`>=`、`<`和`<=`。可以使用`AND`、`OR`和`NOT`等逻辑运算符组合多个过滤条件。 例如,以下命令将查询`students`表中年龄大于18岁的数据: ``` SELECT * FROM students WHERE age > 18; ``` 5. 数据排序 在MySQL中,可以使用`ORDER BY`子句对查询结果进行排序。以下是`ORDER BY`子句的基本语法: ``` SELECT column_name1, column_name2, ... FROM table_name ORDER BY column_name [ASC|DESC]; ``` 其中,`column_name`为要排序的列名,`ASC`表示升序排列,`DESC`表示降序排列。 例如,以下命令将查询`students`表中年龄大于18岁的数据,并按照年龄降序排列: ``` SELECT * FROM students WHERE age > 18 ORDER BY age DESC; ``` 6. 数据聚合 在MySQL中,可以使用聚合函数对查询结果进行聚合。常用的聚合函数包括`COUNT`、`SUM`、`AVG`、`MAX`和`MIN`等。 例如,以下命令将查询`students`表中年龄大于18岁的学生人数: ``` SELECT COUNT(*) FROM students WHERE age > 18; ``` 7. 分组查询 在MySQL中,可以使用`GROUP BY`子句对查询结果进行分组。以下是`GROUP BY`子句的基本语法: ``` SELECT column_name1, column_name2, ... FROM table_name GROUP BY column_name1, column_name2, ...; ``` 其中,`column_name`为要分组的列名。可以使用聚合函数对每个分组进行聚合计算。 例如,以下命令将查询`students`表中每个年龄段的学生人数: ``` SELECT age, COUNT(*) FROM students GROUP BY age; ``` 8. 多表查询 在MySQL中,可以使用`JOIN`关键字对多张表进行查询。以下是`JOIN`关键字的基本语法: ``` SELECT column_name1, column_name2, ... FROM table_name1 JOIN table_name2 ON condition; ``` 其中,`table_name1`和`table_name2`为要查询的表名,`condition`为连接条件。常用的连接方式包括`INNER JOIN`、`LEFT JOIN`、`RIGHT JOIN`和`FULL OUTER JOIN`等。 例如,以下命令将查询`students`表和`scores`表中的数据,并按照学生姓名进行匹配: ``` SELECT students.name, scores.score FROM students JOIN scores ON students.id = scores.student_id; ``` 以上是MySQL的基本数据查询操作,通过实验可以更深入地了解MySQL查询语句的使用方法,为后续的数据处理和分析提供基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的雷神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值