一.sql的分类
DML:数据操纵语言 date manipulation language,
语法包括:select、insert、delete、update
记忆方法:使用sql操作数据的增删改查,对数据产生改变,对表不会产生改变
DDL:数据定义语言 date definition language
语法包括:alter,create、drop、rename truncate
记忆方法:只会对表产生改变,对数据不会产生改变
DCL:数据控制语言 date control language
语法包括:grant、revoke
transaction:事务
rollback、savepoint
 
二.sql基础
--添加注释
--给表添加注释
alter table table_name comment = "表的注释";
--给列添加注释
alter table table_name add column test varchar(10) not null comment "测试" after empno
 
--distinct
--去除重复数据
select distinct column_name from emp;
--多字段去除重复数据,只要一点不一样就算不一样
select distinct column1,column2 from emp;
 
--加别名
--在查询过程中可以给列加别名,同时也可以给表加别名
select e.empno 员工编号,e.job 员工工作 from emp e where e.deptno = '10';
--列可以加as,也可以不加,表不能加
select e.empno as 员工编号,e.job as 员工工作 from emp e where e.deptno = '10';
--当别名中有空格等字样需要用""引上
select e.empno as "员工 编号",e.job as "员工 工作" from emp e where e.deptno = '10';
 
--符号条件判断
--=
select * from emp where deptno = '20';
--<>
select * from emp where deptno <> '20';
--!=与上相同
select * from emp where deptno !='20';
--< 小于
select sal from emp where sal < '1500';
--> 大于
select sal from emp where sal > '1500';
-- 小于等于
select sal from emp where sal <='1500';
-- 大于等于
select sal from emp where sal >='1500';
--any 大于任何一个值 前面都是成立的
select sal from emp where sal > any(1500,1000,3000);
--some 与any同一效果
select sal from emp where sal > some(1500,1000,3000);
--all 大于所有的值 前面才成立
select sal from emp where sal > all(1500,1000,3000);
--is , is not null 在sql中null != null, null是一个特殊的字符,不能使用 = 判断,需要使用is, is not
select * from emp where comm is not null;
select * from emp where comm is null;
--between...and... 包含边界值
select sal from emp where sal between 1500 and 3000;
--<,>联合使用,效果同上,切记不能 1500<sal<3000使用
select sal from emp where sal >= 1500 and sal <= 3000;
--in 匹配在括号中的值,匹配上则查到结果
select * from emp where deptno in (10,20);
-- not in
select * from emp where deptno not in(10,20);
--or的效果与in一样相同
select * from emp where deptno = 10 or deptno = 20;
--当or和and同时出现时,and的优先级高于or的优先级
--所以当and和or同时出现时,且要先执行or语句,需要将or语句加上()
 
/*
exists(sub-query),当exists中的子查询语句能查到对应结果的时候,
意味着条件满足,相当于双层for循环
--现在要查询部门编号为10和20的员工,要求使用exists实现
*/
select * from emp where deptno in (10,20);
--错误
select * from emp where exists(select deptno from dept where deptno = 10 or deptno = 20);
--正确,需要通过外循环来规范内循环
select *
from emp e
where exists (select deptno
from dept d
where (d.deptno = 10 or d.deptno = 20)
and e.deptno = d.deptno);
 
--like模糊查询 _ , % ,escape, \ , \%
/*
在like使用中,需要使用占位符或者通配符
_ 某个字符或数字出现一次或多次
%某个字符或数字出现任意次数
escape 使用转换字符,可以自定义转换字符
使用like的时候要谨慎,因为like的效率比较低
使用like可以参考使用索引,但是要求不能以%开头
涉及到大文本的检索的时候,可以使用某些框架,luence solr electric search
*/
--以S开头的
select * from emp where ename like('S%');
--以S开头倒数第二个为T的
select * from emp where ename like('S%T_');
--以s开头且后面包含T的
select * from emp where ename like('S%T%');
--名字中包含%的
select * from emp where ename like('%\%%') escape('\');
--escape()中的符号可以根据需求变换,用于转义%
select * from emp where ename like('%a%%') escape('a');
 
--order by
/*
是为了进行排序操作
asc 是默认的排序方式,升序
desc 降序排序
 
排序是按照自然顺序排序的
如实数值,按照数值大小排序
如实字符,按照字典排列排序
 
在排序的时候可以指定多个字段,切多个字段可以使用不同的排序方式,
在前的先进行排序
 
每次在执行order by的时候是相当于全排序
比较耗时间,切占内存,不要在繁忙时候进行
*/
select * from emp order by sal;
select * from emp order by sal desc;
select * from emp order by sal,ename;
select * from emp order by sal desc,ename asc;
 
--字符串连接符 concat
--concat
select concat('my name is ',ename) from emp;
--计算所有员工的年薪
--错误
select ename,(e.sal+e.comm)*12 "income" from emp e;
--正确
--当null + 任何数值,运算后还是null
--所以引用nvl(args1,args2),当args1为null时,取args2的值
select ename,(e.sal+nvl(e.comm,0))*12 "income" from emp e;
--nvl例子
select 100+null from dual;--任何值+null结果都为null
 
扩展
1)select * from (select ename,(e.sal+nvl(e.comm,0))*12 as income from emp e) order by income;
2)表的执行顺序
from -- join --on --where --group by --avg(),sum()--having -- select -- distinct--
order by--limit
 
三、sql函数
/*
组函数又称为聚合函数
输入多个值最终返回一个值
组函数仅可用于选择列表或查询的having子句
单行函数
输入一个值,输出一个值
*/
--sum 查询所有员工薪水的总和
select sum(sal) from emp;
--查看表中有多少记录
select deptno,count(*) from emp group by deptno having count(*) > 3;
--将字符串字母的首字母大写
select initcap(ename) from emp;
 
--字符函数
--concat
select concat('my name is ',ename) from emp;
--upper
select upper(ename) from emp;
--lower
select lower(ename) from emp;
--lpad填充字符串
select lpad(ename,10,'*') from emp;
--rpad
select rpad(ename,10,'-') from emp;
--trim
select trim(' aaa ') from dual;
--ltrim
select ltrim(' aaa ')from dual;
--rtrim
select rtrim(' aaa ') from dual;
--instr 查找字符的位置
select instr('AABBCACDD','A',3) from dual;
--length
select length(ename) from emp;
--substr
select substr(ename,0,2) from emp;
--replace
select replace('abcdabc','a','') from emp;
 
 
--数值函数
--round四舍五入
select round(123.123, 2) from dual;
--截断数据,按照位数去进行截取,不会四舍五入
select trunc(123.1283,2) from dual;
--取模操作
select mod(10,4) from dual;
select mod(-10,4) from dual;
--向上取整
select ceil(12.12) from dual;
--向下取整
select floor(13.99) from dual;
--取绝对值
select abs(-100) from dual;
--获取正负值负值为-1
select sign(-100) from dual;
--x的y次幂
select power(2,3) from dual;
 
--日期函数
--当前日期
select current_timestamp();
select current_date();
select current_time();
--添加指定的月份
select ADDDATE(CURDATE(),INTERVAL '2' month);
--返回输入日期所在月份的最后一天
select LAST_DAY(CURDATE())
--提取日期
select
extract(MONTH from current_timestamp),
extract(hour from current_timestamp),
extract(second from current_timestamp),
extract(minute from current_timestamp),
extract(day from current_timestamp),
extract(year from current_timestamp);
 
/*
函数转换
隐式转换是指字符串可以转换为数值或日期
显示转换:
date_format:当由数值或者日期转成字符串的时候,必须要规定格式
*/
--隐式转换
select '999'+1;
--显示转换例子
--date_format
select DATE_FORMAT(current_timestamp,'%Y-%m-%d %H:%i:%s');;
--时间转字符串
select date_format(now(), '%Y-%m-%d');
--时间转时间戳
select unix_timestamp(now());
--字符串转时间
select str_to_date('2020-10-4 10:20:30','%Y-%m-%d %H:%i:%s');
--字符串转时间戳
select unix_timestamp('2020-10-4');
--时间戳转时间
select from_unixtime(1601740800);
--时间戳转字符串
select from_unixtime(1601740800,'%Y-%m-%d');
 
--条件函数
常用行转列
--测试表格初始化
create table test(
id number(10) primary key,
type number(10) ,
t_id number(10),
value varchar2(5)
);
insert into test values(100,1,1,'张三');
insert into test values(200,2,1,'男');
insert into test values(300,3,1,'50');
 
insert into test values(101,1,2,'刘二');
insert into test values(201,2,2,'男');
insert into test values(301,3,2,'30');
 
insert into test values(102,1,3,'刘三');
insert into test values(202,2,3,'女');
insert into test values(302,3,3,'10');
 
 
select * from test;
/*
需求
将表的显示转换为
姓名 性别 年龄
--------- -------- ----
张三 男 50
*/
 
sql表达式:
SELECT
max(CASE type WHEN 1 THEN VALUE END) 姓名,
max(CASE type WHEN 2 THEN VALUE END) 性别,
max(CASE type WHEN 3 THEN VALUE END) 年龄
FROM
test
GROUP BY
t_id;
注意:以t_id为组,以type为column,以为t_id代表一个人和属性,type为value数据的种类
 
--组函数
/*
组函数,一般情况下,组函数都要和groupby组合使用
组函数一般用于选择列或者having条件判断
常用的组函数有5个
avg() 平均值,只用于数值类型的数据
min() 最小值,适用于任何类型
max() 最大值,适用于任何类型
count() 记录数没处理的时候会跳过空值而处理非控制
sum() 求和,只适合数值类型的数据
*/
select avg(sal) from emp;
select min(sal) from emp;
select max(sal) from emp;
select count(sal) from emp;
select sum(sal) from emp;
--group by,按照某些相同的值去进行分组操作
--group进行分组操作的时候,可以指定一个列或者多个列,但是当使用了groupby 之后,
--选择列表中只能包含组函数的值或者group by 的普通字段
--求每个部门的平均薪水
select deptno,avg(sal) from emp where sal is not null group by deptno having avg(sal)>2000;
--部门下雇员的工资>2000 人数
select deptno,count(sal) from emp where sal > 2000 group by deptno;
 
--部门薪水最高
select deptno,max(sal) from emp group by deptno;
--部门里面 工龄最小和最大的人找出来,知道姓名
select deptno,max(hiredate),min(hiredate) from emp group by deptno;
--方法一
select deptno, ename
from emp
where hiredate in (select max(hiredate) from emp group by deptno)
or hiredate in (select min(hiredate) from emp group by deptno);
--方法二
select mm.deptno,e.ename,e.hiredate from emp e,
(select deptno, max(hiredate) maxd, min(hiredate) mind
from emp
group by deptno) mm
where (e.hiredate = mm.mind or e.hiredate = mm.maxd)
and mm.deptno = e.deptno
 
四、数据的更新
/*
插入操作:
元组值的插入
查询结果的插入
*/
 
--最基本的插入方式
--insert into tablename values(value1,value2,....)
--insert into tablename(column1,column2...) values(value1,value2,...)
 
insert into emp values(2222,'haha','clerk',7902,str_to_date('2020-9-11','YYYY-MM-DD'),1000,555,10);
select * from emp;
insert into emp(empno,ename)values(3333,'wangwu');
 
--创建表的其他方式
--复制表的同时复制数据,不会复制约束
create table emp2 as select * from emp where deptno = 20;
--复制表的同时赋值不复制数据,不会复制约束
create table emp3 as select * from emp where 1=2;
 
--删除操作
--delete from table name where condition
select * from emp2;
--删除满足条件的数据
delete from emp2 where deptno =20;
 
--清空数据表的操作
delete from emp2;
--truncate,跟delete不同,delete在进行删除时经过事务,而truncate不经过事务,一旦删除就永久删除,不具备回滚的操作
--效率比较高,但容易发生误操作,所以不建议使用
truncate table emp2;
 
--修改数据:
--update tablename set col1=val1,col2=val2 where condition
--可以更新或者修改满足条件的一个列或者多个列
--更新单列
update emp set ename = 'heihei' where ename = 'haha';
--更新多列
update emp set ename = 'hehe',deptno = 20 where ename = 'heihei';
 
/*
增删改是数据库的基本操作,在进行操作的时候都需要“事务”的保证,也就是说每次在sql中执行sql语句中需要完成commit的操作
事务变得非常关键
最主要的目的是为了数据的一致性
如果同一份数据,在同一个时刻只能有一个人访问,就不会数据错乱的问题,但是在现在的项目中,更多的是并发访问
并发访问的同事带来的就是数据的不安全,也就是不一致
如果要保证数据的安全,最主要的就是枷锁的额方式mvcc
数据库的延伸
最基本的数据库事务
声明式事务
分布式事务
为了提高效率有可能多个操作会在同一个事务中执行,那么就有可能部分成功,部分失败,基于这样的情况,急需要事务的控制
select * from emp where id = 7902 for update
select * from emp where id = 7902 lock in share mode.
如果不保证事务的话,会造成脏读,不可重复读,幻读。
*/
五、sql语法的连接
--cross join:
--产生一个笛卡尔积
--笛卡尔积就是检索出的行数是第一个表中的行数乘以第二个表中的行数
--家所处的列的数目是第一个表中的列数加上第二个表中的列数
select * from emp cross join dept
--natural join:
--两个表中有相同的列产生连接,即相同的列名、相同的数据类型,从两个表中算出连接列的值相等的所有行,结果不保留相同的属性,没有相同的两个列名,会产生笛卡尔积
select * from emp natural join dept
--using(子句)
--using子句引用的列在sql任何地方不能使用表明或者别名
select * from emp join dept using(deptno)
--on子句
--为了指定连接的列,需要使用on子句
select * from emp e join dept d on e.deptno = d.deptno where deptno = 20;
--left join
--会返回所有左边表中的行,即使在右边的表中没有可对应的列
select * from emp e left join dept d on e.deptno = d.deptno where deptno = 20;
--right join
--与left join相反
select * from emp e right join dept d on e.deptno = d.deptno where deptno = 20;
--inner join
--只返回匹配上的行
 
六、子查询
sql允许多层嵌套,子查询,即嵌套再其他查询中的查询,可将查询当做一张表
select * from emp where deptno in (select deptno from dept);