函数
例如 lower 函数把字符变成小写
upper 函数把字符变成大写
常用的函数 :
1) 时间加减
date_add(原始时间, 时间间隔)
时间间隔的语法: interval 数字 时间单位
数字可以是正数或负数
select date_add(now(), interval 1 day );
2) 提取时间的某个部分
extract(时间部分 from 原始时间)
select extract(year from now());
select extract(year_month from now());
返回的结果是一个数字类型
例:要获取1981年入职的员工
select * from emp where extract(year from hiredate)=1981;
3)类型转换
select cast('11' as signed)+1;
select cast('12.55555' as decimal(5,2));
4)拼接字符串
concat(值1, 值2, ... 值n)
select concat('a', 'b', 'c');
select concat('a', 18, 'c'); /*可以把其它类型当做字符串拼接*/
5) 求长度的函数
char_length 按字符为单位统计长度
length 按字节为单位统计长度
utf8mb4编码下,汉字一个字符占三个字节,英文一个字符占一个字节
6) 标准sql:
case
when 条件1 then 值1
when 条件2 then 值2
...
else 值n
end
整个case...end 最后返回一个值
select sal,
case
when sal>2000 then '高工资'
when sal between 1000 and 2000 then '中等'
else '低工资'
end from emp;
7) 组函数
最大值 max(列)
最小值 min(列)
和 sum(列)
个数 count(列) 会排除null值
count(*) 针对这次查询,看看一共有多少行
平均值 avg(列)
8) 去除重复
distinct
select distinct job from emp; /*去除重复后的职位有哪些*/
select count(distinct job) from emp; /*有几种职位*/
9) 查询帮助
? contents 总目录
分组语法 (group by 后的列取值相同的会被分为一组)
select ... from 表 group by 列1,列2... having 分组条件
select deptno,count(*),max(sal) from emp group by deptno;
把部门编号取值相同的分为一组, 配合组函数一起使用
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-07-13 | 3000.00 | NULL | 20 |
| 7876 | ADAMS | CLERK | 7788 | 1987-07-13 | 1100.00 | NULL | 20 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
查询分组后个数大于3的部门编号和个数
select deptno,count(*),max(sal) from emp
group by deptno having count(*)>3 order by max(sal);
分组后 select,order by 的限制
1) select,order by 中的列必须和group by中的列一样
2) 其它没有包含在 group by语句中的列,必须和组函数一起用
执行从先到后
where 进行一遍条件过滤 , 再执行 group by 分组, 再执行 having中的条件, 再执行select, 再执行order by, 执行limit
语法顺序
select ... from ... where ... group by ... having ... order by ... limit;
列别名问题
语法: select 列名 别名 ...
语法2: select 列名 as 别名 ...
select deptno 部门编号,count(*) 人数,max(sal) 最高工资 from emp
group by deptno having count(*)>3 order by max(sal);
select deptno 部门编号,count(*) 人数,max(sal) 最高工资 from emp
group by deptno having count(*)>3 order by 人数;
select empno "员工 编号" from emp; /*列别名中如果存在空格等特殊符号,需要用双引号包围列别名*/
表别名问题
语法 : select ... from 表 别名
select e.* from emp e;
多列分组
select deptno, job, count(*) from emp group by deptno, job;
/*按deptno和job这两列取值都相同的分为一组*/
连接查询
内 连接
select ... from 表1 inner join 表2 on 连接条件 WHERE ... group by ... HAVING ... ORDER BY ... limit ... (重点)
左 外
select ... from 表1 left [outer] join 表2 on 连接条件 (重点)
右 外
select ... from 表1 right [outer] join 表2 on 连接条件
全
select ... from 表1 full join 表2 on 连接条件 (mysql不支持全连接)
例:连接部门表和员工表
select * from emp a inner join dept b on a.deptno=b.deptno;
注意:
1) 内连接是将两张表中所有符合连接条件的数据列入结果,不符合连接条件的结果中没有,例如40号部门
2) 如果连接的两表中有同名的列,列前面要加表名(或表别名)来区分(否则会报歧义错误)
3) inner join ... on 的写法是符合SQL-92标准写法,其实还有一种内连接的写法:
select ... from 表1, 表2 where 连接条件;
例: 还是连接部门表和员工表 select * from emp a, dept b where a.deptno=b.deptno;
连接学生表成绩表
课程表连接老师表
课程表连接成绩表
例子:采用左外连接员工表和部门表
select * from emp a left join dept b on a.deptno = b.deptno;
例子:采用左外连接部门表和员工表
select * from dept b left join emp a on a.deptno = b.deptno;
左外连接,首先将符合连接条件的记录连在一起,作为结果,其次左边表中不符合连接条件的记录也会出现在结果中,只不过它对应的右边的列都是NULL
例子:右外连接
select * from emp a right join dept b on a.deptno = b.deptno;
注意:左外和右外与表的先后次序有关,而内连接与表的先后次序无关
多表连接
select * from 表1
inner join 表2 on 连接条件
inner join 表3 on 连接条件
...
例子
select * from student a inner join sc b on a.sid = b.sid
inner join course c on b.cid = c.cid
inner join teacher d on c.tid = d.tid
order by a.sid, b.cid;
等价写法:
select * from student a, sc b, course c, teacher d
where a.sid=b.sid and b.cid=c.cid and c.tid=d.tid;
左外多表连接:
select * from student a left join sc b on a.sid = b.sid
left join course c on b.cid = c.cid
left join teacher d on c.tid = d.tid
order by a.sid, b.cid;
注意:左外多表连接要全部使用left join,不能再出现inner join
性能上:连接的表越多,性能越低, 可以把连接查询变成分多次查询
自连接
一个表自己和自己连接
找到员工的姓名和上级的姓名
select a.empno,a.ename,a.mgr,b.empno,b.ename,b.mgr
from emp a left join emp b on a.mgr=b.empno;
以后经常用于树状结构的数据表示
陕西省
西安
雁塔区
高新区
咸阳
宝鸡
id name parent_id
1 陕西省 null
2 西安 1
3 雁塔区 2
子查询
把某个select结果当做一个值,或一张表做进一步的查询
情况1:找具有最高工资的员工信息(子查询作为值)
select max(sal) from emp; // 5000
select * from emp where sal = (select max(sal) from emp);
把select max(sal) from emp当成了一个值,代入到主查询当中,代入时需要在子查询的两边加()
情况2: 获取每个部门的平均工资和部门的名称(子查询作为表)
先查询平均工资
(select deptno,avg(sal) from emp group by deptno) a
再把子查询看做临时表,与其它表做表连接
select * from (子查询)a inner join dept b on a.deptno=b.deptno;
事务
DDL create alter drop truncate
DML insert update delete select
TCL start transaction, commit, rollback
start transaction 开始事务 (begin)
6.2 commit 提交事务
6.3 rollback 回滚事务
账户表account
ID balance(余额)
1 50000.0
2 0.0
create table account (
id int primary key,
balance decimal(12,2) not null
);
insert into account(id,balance)values(1,50000.0),(2,0.0);
以下两条sql必须作为一个整体执行, 要么都成功,其中有一条失败,前面成功的也得撤销
update account set balance=balance+10000.0 where id=2; /*2号账户转入10000元*/ 成功
update account set balance=balance-10000.0 where id=1; /*1号账户转出10000元*/
所谓的事务,就是指一个事务内,多条sql语句是作为一个整体执行的。
一个事务内的多条sql是作为一个原子操作,不可以被分割。要么都成功,要么都不成功。
start TRANSACTION;
UPDATE
UPDATE
INSERT
DELETE
如果这个事务内多条sql全部成功 COMMIT(让更改都生效)
如果这个事务内有sql失败了,Rollback(让更改都撤销)
事务内所有更改,在结束之前,对于其它用户来讲都是不可见的。
事务commit提交时,这些更改才会真正生效,其它用户才能看到你的更改。
事务执行中如果出现意外情况,这时候可以执行rollback,可以撤销事务内所有更改,恢复到事务开始的时刻
commit 和rollback都意味着事务结束
事务有四大特性
ACID
A 原子性, 指事务内多条sql是作为一个整体执行
C 一致性, 事务开始前后,整个数据的状态应当一致
I 隔离性, 指事务的隔离级别(未提交读,提交读,可重复读,序列化读)
1) 脏读(读取到了未提交的数据)
客户1 客户2
1 号账户余额 10000.0
begin;
update 1 号账户余额50000.0
select 1 号账户余额 50000.0 脏读
rollback;
select 1 号账户余额 50000.0
2)避免脏读现象, 将隔离级别升级为提交读
查询到的肯定是别人提交后的结果,提交读下不会有脏读, 但会有不可重复读现象:
客户1 更新 客户2查询
1 号账户余额 10000.0
begin;
select ... 10000.0
begin;
update 1 号账户余额50000.0;
commit;
select ... 50000.0
commit;
3) 为了避免不可重复和脏读的现象,可以将隔离级别升级可重复读(mysql默认隔离级别)
4) 幻读 (可以将隔离级别提高为序列化读,即可避免幻读现象)
客户1 新增 客户2查询
原始记录是10条
begin begin;
查询个数 10
insert 1
commit;
查询个数 11
commit;
5) mysql的【可重复读】隔离级别三种现象都可以避免
D 持久性, 事务中做的更改必须在事务结束后永久生效
增删改查(insert update delete select)
CRUD c insert 插入
r select 查询
u update 更新
d delete 删除
DCL 数据控制语言 (了解)
grant 授权
revoke 回收权限
create user 'user1'@'localhost' identified by 'user1';
登录之后执行use test3;
会报告 Access denied for user 'user1' 含义是用户无权访问.
使用root 给user1授权
grant all on test3.* to 'user1'@'localhost';
all 是代表所有权限:select,insert,update,delete...
test3.* 是权限的范围:test3库中所有对象
to 后面跟的是用户
使用root回收权限
revoke all on test3.* from 'user1'@'localhost';
更细的权限分配
grant select on test3.student to 'user1'@'localhost'; /*只让test1用户能够查询test3.student表*/