货物我们希望能够用一个目录来展示它们的位置,这个目录就叫索引...
oracle mysql sqlserver db2 postgre mongdb redis...
关系型数据库:RDBMS (relational data base manager system):
sys:超级管理员,可以管理所有的用户和操作,只能用管理员身份登录
system:普通管理员,可以用管理员也可以用普通用户的身份登录,工作中都是用system管理数据库
database:数据库实例,所有的实例都是以操作系统服务的形式存在的
OracleService 表示它是一个服务 ORCL是服务的名字
sysoper 系统检测员:对系统进行关闭、启动、备份、还原等操作
create user 用户名 identified by 密码;
create user zz identified by 123456;
grant connect,resource,dba to zz;
整数 integer -2147483648~2147483647
小数 number(总长度, 小数精度) 例如1.75 number(4,2)
定长字符串 char(最大长度) 最多可以存放2000个字符
不定长字符串 varchar2(最大长度) 最多可以存放4000个字符
1. 主键:表格中最核心的列 primary key 一个表只能有一个主键
5. 外键: foreign key 外键只能和另一个表的主键关联,外键可以有多个
foreign key (自己表的列名) references 另一个表的名字(它的主键名字)
限制购物车的表格中,userid必须在用户表中已经存在,goods必须在商品表中已经存在,不能填写那些没有存在数据
username varchar2(200) not null,
goods varchar2(200) primary key,
shopping_id number primary key,
foreign key (userid) references user_info3(userid),
foreign key(goods) references goods_info(goods)
username varchar2(12) not null,
sex char(3) check(sex='男' or sex='女'),
high number(4,2) check(high>=1.00 and high<=2.00),
alter table 表名 add 列名 数据类型 约束条件;
alter table user_info add mobile char(11) unique;
alter table 表名 drop column 列名;
alter table user_info drop column high;
alter table 表名 modify 列名 新的数据类型 约束条件;
alter table user_info modify usersex number;
alter table 表名 rename column 旧的列名 to 新的列名;
alter table user_info rename column mobile to phone;
2.2 修改约束条件,在建表的时候添加的约束条件,它的名字是系统自动分配的,但是在alter里面自己手动去操作约束条件,它的名字是要自己给的。
alter table 表名 add constraint 约束条件的名字 约束名(列名);
alter table user_info add constraint pri_userid primary key(userid);
alter table user_info add constraint uni_username unique(username);
alter table user_info add constraint ck_regist check(regist_time is not null);
alter table user_info add constraint ck_sex check(usersex='男' or usersex='女');
alter table user_jifen add constraint fk_user_info_userid foreign key(userid) references user_info(userid);
alter table 表名 drop constraint 约束条件的名字;
alter table user_info drop constraint ck_regist;
alter table 旧表名 rename to 新表名;
alter table shopping rename to shopping_info;
3. DML操作:对表格数据本身的操作:commit(保存提交) rollback(不保存回滚)
insert into 表名 values(值1,值2,值3...);
insert into user_info values(1001,'李雷',1,date'2020-11-19','13400009999');
insert into 表名(列名1,列名2...) values(值1,值2...);
修改已有数据:where 列名=值 根据某个列的值,找到拥有这个值的行,一般都会通过主键查找数据
update 表名 set 列名=新的值 where 列名=原有的值;
update user_info set usersex=0 where username='韩梅梅';
update user_info set username='韩小梅' where userid=1002;
delete from user_info where userid=1001;
1. delete是DML操作,truncate是DDL操作
2. delete是以行为单位删除数据,truncate是基于整个表格删除的
3. delete可以加where筛选需要删除的数据,truncate不能使用where筛选
4. delete是有缓存的,truncate删除是没有缓存的
4. DQL操作:对已有的表格进行数据的查询和筛选 select
select empno,ename,sal from scott.emp;
select 列名1,列名2... from 表名 where 列名=值;
select empno,ename,sal from scott.emp where sal>=3000;
select * from scott.emp where deptno=10;
select * from scott.emp where sal<1000;
select * from scott.emp where ename like 'A%';
select * from scott.emp where ename like 'A__E%';
select * from scott.emp where ename like '__A%';
select * from scott.emp where ename like '%\%%' escape '\';
\ 是转义符的意思,转义符可以将特殊的符号,变成普通的字符;
但是要通过escape关键字告诉sql语句,这个时候\是当成转义符来使用的。
d. 逻辑筛选 and(两个条件要同时满足) or(两个条件满足一个就行) not
select * from scott.emp where deptno=10 or deptno=20;
select * from scott.emp where deptno=10 and sal>2000;
查询10号部门工资超过2000的和20号部门工资低于1000的员工信息
select * from scott.emp where deptno=10 and sal>2000
select * from scott.emp where (deptno=10 or deptno=20)
select * from scott.emp where deptno!=20;
select * from scott.emp where not deptno=20;
select * from scott.emp where deptno=20 and not sal>=1000;
select * from scott.emp where comm is null;
select * from scott.emp where comm is not null;
f. 和范围相关的查询关键字 in between...and...
select * from scott.emp where empno=7369 or empno=7788
select * from scott.emp where empno in(7369,7788,7654);
select * from scott.emp where sal>=1000 and sal<=3000;
select * from scott.emp where sal between 1000 and 3000;
8888,lilei,SALEMAN,7566,1988-10-9,3200,1200,10
4.查询所有的SALESMAN和MANAGER岗位的员工信息
8888,'lilei','SALESMAN',7566,date'1988-10-9',3200,1200,10
update scott.emp set comm=1600 where empno=7654;
select * from scott.emp where mgr is null;
select * from scott.emp where job in ('SALESMAN','MANAGER');
select * from scott.emp where job='CLERK' and sal<1000;
select ename from scott.emp where deptno=10 and job='MANAGER';
select * from scott.emp where comm>sal;
select * from scott.emp where ename like '%O__';
union all:将第一个语句的结果和第二个语句的结果,拼接在一起
select job from scott.emp where deptno=10
select job from scott.emp where deptno=20;,
select job from scott.emp where deptno=10 or deptno=20;
union:将第一个语句的结果和第二个语句的结果,拼接在一起,并且去除掉重复的数据
select job from scott.emp where deptno=10
select job from scott.emp where deptno=20;
select distinct job from scott.emp where deptno=10 or deptno=20;
minus:显示第一个语句有的内容,但是第二个句子没有的内容
select job from scott.emp where deptno=20
select job from scott.emp where deptno=10;
select job from scott.emp where deptno=20
select job from scott.emp where deptno=10;
union all是拼接所有的数据,union也是拼接所有的数据,但是会对数据做去重的处理;
union all的效率更高,通常会使用union all替代or的语句。
dcl(权限) ddl(数据库对象) dml(表的数据) dql(查询表格的数据)
create user 用户名 identifed by 密码;
grant connect,resource,dba to 用户名;
select deptno,count(empno),avg(sal),sum(sal),max(sal),min(sal) from scott.emp group by deptno;
select deptno,count(empno) from scott.emp group by deptno having count(empno)>5;
select deptno,count(empno) from scott.emp where deptno=20 group by deptno;
select deptno,count(empno) from scott.emp group by deptno having deptno=20;
2. where在group by 之前使用的,having是在group by之后使用的
--查询每个工作岗位,他们的最大的工资和最小的工资,分别是多少
select job,max(sal),min(sal) from scott.emp group by job;
select deptno,avg(sal) from scott.emp group by deptno
select deptno,job,avg(sal) from scott.emp group by deptno,job;
select * from scott.emp order by sal;
select deptno,avg(sal) from scott.emp group by deptno
查询所有员工的信息,按照工资降序排序,如果工资相同,再按照编号升序排序
select * from scott.emp order by sal desc,empno asc;
现在工资是第一顺位,编号是第二顺位,当工资相同的时候,编号的排序才会生效。
select * from scott.emp where job=(
select job from scott.emp where ename='SMITH'
select * from scott.emp where sal>(
select sal from scott.emp where ename='MILLER'
select * from scott.emp where job in(
select job from scott.emp where deptno=10
select * from scott.emp where sal>(
select max(sal) from scott.emp where deptno=20
select loc from scott.dept where deptno=(
select deptno from scott.emp where ename='SMITH'
select ename from scott.emp where deptno=(
select deptno from scott.dept where dname='ACCOUNTING'
查询工作地点在NEW YORK并且工作岗位和SMITH一样的员工信息
select * from scott.emp where deptno=(
select deptno from scott.dept where loc='NEW YORK'
select job from scott.emp where ename='SMITH'
拼接多个表格,变成一张大的表格,然后对这个大的表格进行操作。
select 列名 from a [inner | left | right | full ] join b
select 列名 from a,b where a.xx=b.xx; --内连接
select 列名 from a,b where a.xx=b.xx(+); --左连接
select 列名 from a,b where a.xx(+)=b.xx; --右连接
select * from scott.emp join scott.dept
on scott.emp.deptno=scott.dept.deptno;
select * from scott.emp,scott.dept where scott.emp.deptno=scott.dept.deptno;
首先先显示左右两个表格所有的共同数据,然后再显示左边那边表独有的数据,因为右边没有匹配数据,所以显示为空
select * from scott.dept left join scott.emp
on scott.emp.deptno=scott.dept.deptno;
select * from scott.dept,scott.emp where scott.dept.deptno=scott.emp.deptno(+);
右连接 right [outer] join:刚好和左连接相反,首先先显示左右两个表格所有的共同数据,然后再显示右边那边表独有的数据,因为左边没有匹配数据,所以显示为空
select * from scott.emp right join scott.dept
on scott.emp.deptno=scott.dept.deptno;
select * from scott.emp,scott.dept where scott.emp.deptno(+)=scott.dept.deptno;
全连接 full [outer] join:先显示两个表的共同数据,然后再显示左边表的独有数据,右边没有匹配就显示为空,然后再显示右边表的独有数据,左边没有匹配就显示为空。
select * from scott.emp full join scott.dept
on scott.emp.deptno=scott.dept.deptno;
select * from scott.emp,scott.dept where scott.emp.deptno(+)=scott.dept.deptno
select * from scott.emp,scott.dept where scott.emp.deptno=scott.dept.deptno(+);
对a和b的所有数据进行匹配,先找出所有数据的笛卡尔积,然后在所有的集合结果中找出符合的数据
select loc from scott.emp a join scott.dept b
select ename from scott.emp a join scott.dept b
select loc,count(empno) from scott.dept a left join scott.emp b on a.deptno=b.deptno
(select deptno,avg(sal) s from scott.emp group by deptno) a
select loc,avg(sal) from scott.emp a join scott.dept b
group by loc having avg(sal)<2000;
找出SALESMAN分别在哪些不同的部门上班,查询出部门名称
select distinct dname from scott.emp a join scott.dept b
查询出每个部门的员工数量,要求查询出部门编号、部门名称、部门地点、人数
select a.deptno,dname,loc,c from
(select deptno,count(empno) c from scott.emp group by deptno) a
select b.deptno,dname,loc,count(empno) from scott.emp a join scott.dept b
count(1)等同于count(*):以行为单位,只要整行中有一列有值,那么就统计数量
select count(empno) from scott.emp where comm is not null;
select count(comm) from scott.emp;
select deptno,count(empno) from scott.emp where comm is not null group by deptno;
select deptno,count(comm) from scott.emp group by deptno;(select * from sc where c#=001) a
(select * from sc where c#=002) b
select s#,avg(score) from sc group by s# having avg(score)>60;
select a.ename yuangong,b.ename lingdao from scott.emp a join scott.emp b
(select deptno,max(sal) m from scott.emp group by deptno) a
select * from a left join b on a.id=b.id where a.id=2;
select * from a left join b on a.id=b.id and a.id=2;
select * from a join b on a.xx=b.xx join c on a.yy=c.yy join d on d.zz=b.zz;
select * from scott.emp,scott.salgrade where sal between losal and hisal;
select * from scott.emp a join scott.emp b on a.mgr=b.empno
select ename,sal from scott.emp where sal in
(select sal from scott.emp group by sal having count(empno)>=2);
select empno,ename,round(sal/s*100,2)||'%' from
(select deptno,sum(sal) s from scott.emp group by deptno) a
查询每个工作岗位上,最大工资和最小工资的差距小于1000的工作岗位名字,以及最大和最小工资的差额
select job,max(sal)-min(sal) m from scott.emp group by job having max(sal)-min(sal)<1000;
select loc,count(empno) c from scott.emp a right join scott.dept b
group by loc having count(empno)=0;
select loc from scott.dept where deptno not in
(select distinct deptno from scott.emp);
select round(1.2345678,4) from dual;
select round(4.3678) from dual;
select trunc(1.2345678,4) from dual;
select trunc(4.5678) from dual;
substr(x, idx, len) 截取字符串的一部分 substr(字符串, 开始位置, 连续取值的长度)
select substr('abcdefghijklmn',2,4) from dual;
select substr('abcdefghijklmn',-3,2) from dual; 开始位置为负数,表示从后往前数
select substr('abcdefghijklmn',-3) from dual; 连续取值为空,表示一直取到最后
select concat('hello','world') from dual;
select concat(concat('hello','-'),'world') from dual;
select concat('''',concat(deptno,'''')) from scott.emp;
字符串的拼接可以使用管道符来实现,两个管道符可以实现字符的拼接
select ename||':'||deptno from scott.emp;
select ename,replace(ename,'A','.') from scott.emp;
select length(ename) from scott.emp;
select length('abcdefg') from dual;
select last_day(sysdate) from dual;
months_between(x1, x2) 计算两个日期之间的时间间隔
select months_between(date'2020-9-2',date'2019-9-1') from dual;
select add_months(sysdate,11) from dual;
select date'2020-10-1'+10 from dual;
to_number() 只能转换全是数字的字符串,例如 '100'
select to_number('100') from dual;
select to_char(100) n from dual;
select to_char(sysdate,'yyyy') from dual;
select to_char(sysdate,'mm') from dual;
select to_char(sysdate,'dd') from dual;
select to_char(sysdate,'hh') from dual;
select to_char(sysdate,'mi') from dual;
select to_char(sysdate,'ss') from dual;select *from zz.Emp where sal>
(Select max(sal) from emp where deptno =30 )
select to_char(sysdate,'day') from dual; --提取星期几
to_date() 只有时间格式的字符串可以转成日期,例如 '2020-10-1 9:38:12'
select to_date('2020-9-1 10:21:09','yyyy-mm-dd hh24:mi:ss') from dual;
select to_date(to_char(sysdate+1,'yyyy-mm-dd')||' 10:00:00', 'yyyy-mm-dd hh24:mi:ss') from dual;
select * from scott.emp where to_char(hiredate,'day')='星期四';
select to_char(hiredate,'yyyy'),count(empno) from scott.emp group by to_char(hiredate,'yyyy');
计算函数部分() over(partition by 列名 order by 列名 asc|desc)
2. 将这个查询的分组结果和原来表格进行拼接 over(partition by 列名)
max(sal) over(partition by deptno) m
over(partition by 列名):在每个小的分组中,进行数据的计算
max(sal) over(partition by job)
over(order by 列名 asc|desc):对整个表,对排序的列进行依次的累计运算,并列的名次和数据,会当成一个整体进行计算
over(partition by 列名 order by 列名 asc|desc):在每个分组中,对排序的列进行依次的累计运算,并列的名次和数据,会当成一个整体进行计算
avg(sal) over(partition by deptno order by sal)
max() | min() | count() | sum() | avg() over(partition by 组名 order by 列名 asc|desc)
row_number():根据某个列,按照顺序进行排序 1 2 3 4
row_number() over(partition by deptno order by sal desc) r
rank():根据某个列,按照顺序进行排序,如果值相同,会出现并列的名次,会跳过占用的名次 1 2 2 4
rank() over(order by sal desc) r
dense_rank():根据某个列,按照顺序进行排序,如果值相同,会出现并列的名次,不会跳过名次 1 2 2 3
dense_rank() over(order by sal desc) r
rank() over(partition by job order by sal desc) r
insert into t1 values(10,'G');
insert into t1 values(11,'H');
select id,name,id-r group_id from
row_number() over(order by id) r
(select * from t1 where name!='/') a) b;
同比:今年的4月和去年的4月相比,在两个时间范围内,取相同时间节点的数据进行比较
环比:今年的4月和今年的3月相比,在同一个时间范围内,取相邻的时间节点的数据进行比较
insert into sale_info values(2018,1,2342);
insert into sale_info values(2018,2,1234);
insert into sale_info values(2018,3,3545);
insert into sale_info values(2018,4,3456);
insert into sale_info values(2018,5,2342);
insert into sale_info values(2018,6,4534);
insert into sale_info values(2018,7,3453);
insert into sale_info values(2018,8,2342);
insert into sale_info values(2018,9,4352);
insert into sale_info values(2018,10,1312);
insert into sale_info values(2018,11,3453);
insert into sale_info values(2018,12,1235);
insert into sale_info values(2019,1,3453);
insert into sale_info values(2019,2,1233);
insert into sale_info values(2019,3,3445);
insert into sale_info values(2019,4,1233);
insert into sale_info values(2019,5,1231);
insert into sale_info values(2019,6,4234);
insert into sale_info values(2019,7,1231);
insert into sale_info values(2019,8,2131);
insert into sale_info values(2019,9,1231);
insert into sale_info values(2019,10,3421);
insert into sale_info values(2019,11,1231);
insert into sale_info values(2019,12,1231);
select y,m,round((amount-lo)/lo*100,2)||'%' from
lag(amount) over(partition by m order by y) lo
在m这个组,根据y排序,将amount这个列,数据往下平移一行
select b.y,b.m,round((b.amount-a.amount)/a.amount*100,2)||'%' 增长率 from
(select * from sale_info where y=2018) a
(select * from sale_info where y=2019) b
select y,m,round((amount-lo)/lo*100,2)||'%' from
lag(amount) over(order by m ) lo
from sale_info a where y=2019) b;
select a.y,a.m,round((a.amount-b.amount)/b.amount*100,2)||'%' from
(select * from sale_info where y=2019) a
(select * from sale_info where y=2019) b
lead(amount) over(order by m ) lo
from sale_info a where y=2019;
CREATE TABLE NBA (TEAM VARCHAR2(20),Y NUMBER(4));
INSERT INTO NBA VALUES('活塞',1990);
INSERT INTO NBA VALUES('公牛',1991);
INSERT INTO NBA VALUES('公牛',1992);
INSERT INTO NBA VALUES('公牛',1993);
INSERT INTO NBA VALUES('火箭',1994);
INSERT INTO NBA VALUES('火箭',1995);
INSERT INTO NBA VALUES('公牛',1996);
INSERT INTO NBA VALUES('公牛',1997);
INSERT INTO NBA VALUES('公牛',1998);
INSERT INTO NBA VALUES('马刺',1999);
INSERT INTO NBA VALUES('湖人',2000);
INSERT INTO NBA VALUES('湖人',2001);
INSERT INTO NBA VALUES('湖人',2002);
INSERT INTO NBA VALUES('马刺',2003);
INSERT INTO NBA VALUES('活塞',2004);
INSERT INTO NBA VALUES('马刺',2005);
INSERT INTO NBA VALUES('热火',2006);
INSERT INTO NBA VALUES('马刺',2007);
INSERT INTO NBA VALUES('凯尔特人',2008);
INSERT INTO NBA VALUES('湖人',2009);
INSERT INTO NBA VALUES('湖人',2010);
select team,min(y),max(y) from
y-(row_number() over(order by team,y)) r
group by team,r having count(1)>1
select ssex,count(sno) from student group by ssex;
select * from student where sname like '张%';
select count(tno) from teacher where tname like '刘%';
select count(distinct sno) from sc;
(select sno from sc group by sno) a;
select * from sc where score<60 order by cno desc;
6.查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分
select cno,max(score),min(score) from sc group by cno;
select cname,tname,avg(score) s from sc a join course b on a.cno=b.cno
select a.sno,sname,count(cno) from student a left join sc b on a.sno=b.sno
9.查询“c001” 课程成绩在80 分以上的学生的学号和姓名
select sno,sname from student where sno in
(select sno from sc where cno='c001' and score>80);
10.查询“c003”课程分数小于60的同学学号和姓名,按分数降序排列
(select * from sc where cno='c003' and score<60) a
11.查询课程名称为“SSH”,且分数低于60 的学生姓名和分数
select cno from course where cname='SSH'
select a.sno,sname,count(cno),sum(score) from student a
select a.cno,cname,count(sno) from course a left join sc b on a.cno=b.cno
select sno,sname from student where sno in
(select sno from sc group by sno having count(cno)>=2);
select sno,sname from student where sno in
(select sno from sc group by sno having count(cno)=1);
(select sno,avg(score) from sc group by sno having avg(score)>80) a
join student b on a.sno=b.sno;
select sno,sname from student where sno in
(select sno from sc group by sno having max(score)<70);
select sno,sname from student where sno in
(select sno from sc where sno not in
(select distinct sno from sc where score>=70));
18.查询任何一门课程成绩在70 分以上的学生的姓名、课程名称和分数
(select * from sc where score>70) a
(select sno from sc where score>=60 group by sno
(select sno,avg(score) s from sc group by sno) b
avg(score) over(partition by sno) avg_s
group by sno,avg_s having count(1)>=2;
row_number() over(partition by cno order by score desc) r
dense_rank() over(partition by cno order by score desc) r
select * from student where to_char(sysdate,'yyyy')-sage=1998;
insert into student values('s011','王丽',24,'女');
select sname,count(1) from student group by sname having count(1)>=2;
select a.sname,count(1) from student a
join student b on a.sname=b.sname and a.sno!=b.sno
select a.* from sc a join sc b on a.cno!=b.cno and a.score=b.score;
select a.sno,sname,count(cno) from student a left join sc b on a.sno=b.sno
group by a.sno,sname having count(cno)<(
select a.cno,cname,count(sno) from course a left join sc b on a.cno=b.cno
group by a.cno,cname having count(sno)=(
27.查询选修“谌燕”老师所授课程的学生中,每门课程成绩最高的学生姓名及其成绩
select cno from course where tno=
(select tno from teacher where tname='谌燕')
max(score) over(partition by cno) m
(select * from sc where cno in (
select cno from course where tno=
(select tno from teacher where tname='谌燕')
join student a on a.sno=b.sno;
max(score) over(partition by cno) m
(select sname,b.cno cno,score from student a join sc b on a.sno=b.sno
select sname from student where sno not in
(select distinct sno from sc where cno in
(select cno from course where tno=
(select tno from teacher where tname='谌燕')));
select cno from course where tno=
(select tno from teacher where tname='谌燕')
select count(cno) from course where tno=
(select tno from teacher where tname='谌燕')
select sno from sc where cno in (
select cno from course where tno=
(select tno from teacher where tname='谌燕')
) group by sno having count(1)=(
select count(cno) from course where tno=
(select tno from teacher where tname='谌燕')
select sno,sname from student where sno in (
select sno from sc where cno in (
select cno from course where tno=
(select tno from teacher where tname='谌燕')
) group by sno having count(1)=(
select count(cno) from course where tno=
(select tno from teacher where tname='谌燕')
30.查询学过“c001”并且也学过编号“c002”课程的所有同学的学号、姓名
select sno,sname from student where sno in(
(select * from sc where cno='c001') a
(select * from sc where cno='c002') b
distinct和group by都可以去重,那么场景下用哪一种,效率更高?
2. 数据量不大的时候,两者的速度差不多,如果去重的列,有大量的重复的信息的组成的,那么group by更快,如果列里面大部分的信息都不重复,只有少部分需要去重的数据,那么distinct更快
伪列:在创建表格的时候,没有直接写上去的列名,但是每个表都一定会有的信息,效果等同于row_number()
select a.*,rownum r from scott.emp a;
(select a.*,rownum r from scott.emp a) b
(select * from scott.emp order by sal desc) a
row_number() over(order by sal desc) r
rowid:数据去重,表里面每一行数据,在数据库中的唯一编号,不会出现重复的数据
delete from student where rowid not in
(select min(rowid) from student
group by sno,sname,sage,ssex);create table table1(
insert into table1 values(1,'a');
insert into table1 values(2,'b');
insert into table1 values(3,'b');
insert into table1 values(6,'b');
insert into table1 values(8,'c');
insert into table1 values(3,'a');
insert into table1 values(3,'c');
insert into table1 values(5,'c');
delete from table1 where rowid not in
min(id) over(partition by name) mi
delete from table1 where id not in
min(id) over(partition by name) mi
select * from (select 需要查看的列名 from 表名)
pivot(聚合函数(计算的列名) for 维度的列名 in (维度列的值));
select * from (select deptno,sal from scott.emp)
pivot(avg(sal) for deptno in (10,20,30));
--根据部门的维度,计算平均工资的指标,维度是分组的列,指标是计算的列
select * from (select job,sal from scott.emp)
pivot(sum(sal) for job in('SALESMAN','CLERK','MANAGER'));
select * from (select 需要查看的列 from 表名)
pivot(聚合函数(计算的列名) for 小维度的那个列名 in (小维度列的值));
select * from (select deptno,job,sal from scott.emp)
pivot(avg(sal) for job in ('SALESMAN','CLERK','MANAGER','PRESIDENT'));
insert into table_emp values(1,'sale','master',2000);
insert into table_emp values(1,'sale','slave',1000);
insert into table_emp values(2,'dev','master',3000);
insert into table_emp values(2,'dev','slave',2000);
select * from (select id,dept,intype,income from table_emp)
pivot(sum(income) for intype in ('master','slave'))
只使用后面的case when的语法,不使用pivot(),也可以实现行列的转换create table table_emp2(
insert into table_emp2 values(1,'sale','master',2000);
insert into table_emp2 values(2,'sale','slave',1000);
insert into table_emp2 values(3,'sale','master',2000);
insert into table_emp2 values(4,'sale','slave',1000);
insert into table_emp2 values(5,'dev','master',2000);
insert into table_emp2 values(6,'dev','slave',1000);
insert into table_emp2 values(7,'dev','master',2000);
insert into table_emp2 values(8,'dev','slave',1000);
delete from table_emp2 where rowid not in(
select min(rowid) from table_emp2 group by dept,intype,income);
delete from table_emp2 where id not in(
select min(id) from table_emp2 group by dept,intype,income);
select ename,sal,comm,nvl(comm,0)+sal from scott.emp a;
nvl(comm,0) 如果comm这列为空,那么默认值是0,如果不为空,显示原来的值
nvl2(列名, 如果不为空显示的内容, 如果为空显示的内容)
select ename,sal,comm,nvl2(comm,sal+comm,sal) from scott.emp;
如果comm这列为空,那么显示sal本身,如果不为空,显示sal+comm
decode(列名, 判断条件1, 条件1为真的时候, 判断条件2, 条件2为真的时候, 判断条件3, 条件3为真的时候, ... , 所有条件都为假的情况)
decode(comm,null,'没有奖金',0,'没有奖金','有奖金')
如果没有奖金,显示为0,显示提示没有,如果是0,也提示没有,否则,提示有奖金。
在decode里面,只能写精确的值的判断,不能写范围的判断,也不能写取反的值的判断等等,如果要实现范围的判断,需要结合sign()函数。
sign(x-y):如果x比y大,结果就是1,两者相等,结果是0,x比y小,结果就是-1
查询emp表里面的员工工资,小于2000,等级为C,2000-3000等级为B,3000以上等级为A
decode(sign(sal-2000)+sign(sal-3000),-2,'C',2,'A','B')
decode(sign(score-60),-1,'不及格','及格')
when sal>=2000 and sal<=3000 then 'B'
使用case when判断emp的员工是普通员工还是管理层(MANAGER PERSIDENT)
when job in('MANAGER','PRESIDENT') then '管理层'
select sno,case when score>=60 then 'jige' else 'bujige' end c
pivot(count(sno) for c in ('jige','bujige'));
sum(case when score>=60 then 1 else 0 end) jige,
sum(case when score<60 then 1 else 0 end) bujige
使用case when的方法,使用以行进行部门维度的展示,查看每个部门的平均工资
sum(nvl(case when deptno=10 then avg_s end,0)) "10",
sum(nvl(case when deptno=20 then avg_s end,0)) "20",
sum(nvl(case when deptno=30 then avg_s end,0)) "30"
(select deptno,avg(sal) avg_s from scott.emp group by deptno);
sum(case when ssex='男' then 1 else 0 end) 男,
sum(case when ssex='女' then 1 else 0 end) 女
insert into a values(date'2020-6-1','Y');
insert into a values(date'2020-6-2','Y');
insert into a values(date'2020-6-3','Y');
insert into a values(date'2020-6-4','Y');
insert into a values(date'2020-6-5','Y');
insert into a values(date'2020-6-6','N');
insert into a values(date'2020-6-7','N');
insert into a values(date'2020-6-8','Y');
insert into a values(date'2020-6-9','Y');
insert into a values(date'2020-6-10','Y');
insert into a values(date'2020-6-11','Y');
insert into a values(date'2020-6-12','Y');
insert into a values(date'2020-6-13','N');
insert into a values(date'2020-6-14','N');
insert into a values(date'2020-6-15','Y');
insert into a values(date'2020-6-16','Y');
insert into a values(date'2020-6-17','Y');
insert into a values(date'2020-6-18','Y');
insert into a values(date'2020-6-19','Y');
insert into a values(date'2020-6-20','N');
insert into a values(date'2020-6-21','N');
insert into a values(date'2020-6-22','Y');
insert into a values(date'2020-6-23','Y');
insert into a values(date'2020-6-24','Y');
insert into a values(date'2020-6-25','N');
insert into a values(date'2020-6-26','N');
insert into a values(date'2020-6-27','N');
insert into a values(date'2020-6-28','Y');
insert into a values(date'2020-6-29','Y');
insert into a values(date'2020-6-30','Y');
insert into b values('S001',date'2020-6-2',date'2020-6-8');
insert into b values('S002',date'2020-6-3',date'2020-6-26');
insert into b values('S003',date'2020-6-5',date'2020-6-15');
insert into b values('S004',date'2020-6-15',date'2020-6-30');
insert into b values('S005',date'2020-6-18',date'2020-6-27');
select id,count(1) from a,b where status='Y' and sdate<=t and ldate>=t
group by id having count(1)>10;
临时表:临时存储数据的表格,数据暂时放在这个表格中,等会会自动的根据什么事件消失掉,不会永久的占用你的物理磁盘的空间。
create global temporary table 表名(
create global temporary table dept_tmp(
insert into dept_tmp select * from scott.dept;
重新打开plsql的对话框,dept_tmp的表格内容就清空了
create global temporary table 表名(
create global temporary table dept_tmp_2(
insert into dept_tmp_2 select * from scott.dept;
如果进行了commit和rollback的操作,表格的数据都会被清空。
with a as (select deptno from scott.emp where ename='SMITH')
select loc from a join scott.dept b on a.deptno=b.deptno;
with a as (select sno from sc where cno='c001'),
b as (select sno from sc where cno='c002')
select a.* from a,b where a.sno=b.sno;
with a as (select * from scott.emp where deptno=10)
select * from a where sal>2000;
31.查询“c001”课程比“c002”课程成绩高的所有同学的学号、姓名
select sno,sname from student where sno in
(select * from sc where cno='c001') a
(select * from sc where cno='c002') b
on a.sno=b.sno and a.score>b.score);
32.统计各科成绩,各分数段人数 : 课程ID,课程名称,[100-85],[85-70],[70-60],[ <60]
case when score between 85 and 100 then '[100-85]'
when score>=70 and score<85 then '[85-70]'
when score>=60 and score<70 then '[70-60]'
from sc a join course b on a.cno=b.cno)
pivot(count(sno) for s in ('[100-85]','[85-70]','[70-60]','[ <60]'));
sum(case when score>=85 and score<=100 then 1 else 0 end) "[100-85]",
sum(case when score>=70 and score<85 then 1 else 0 end) "[85-70]",
sum(case when score>=60 and score<70 then 1 else 0 end) "[70-60]",
sum(case when score<60 then 1 else 0 end) "[ <60]"
from sc a join course b on a.cno=b.cno
33.查询至少有有一门课与学号为“s001”的同学所学相同的同学的学号和姓名
select sno,sname from student where sno in
(select distinct sno from sc where cno in
(select cno from sc where sno='s001') and sno!='s001');
34.查询学过学号为“s001”同学所有门课的其他同学学号和姓名
select sno,sname from student where sno in
(select cno from sc where sno='s001') a,sc b where sno!='s001' and a.cno=b.cno
group by sno having count(1)=(
select count(1) from sc where sno='s001'
35.查询和“s002”号的同学学习的课程完全相同的其他同学学号和姓名
select sno,sname from student where sno in
(select cno from sc where sno='s002') a,sc b where sno!='s002'
group by sno having count(1)=(
select count(1) from sc where sno='s002'
select sno,sname from student where sno in
(select cno from sc where sno='s002') a
right join sc b on a.cno=b.cno where sno!='s002'
group by sno having count(1)=(
select count(1) from sc where sno='s002'
select a.cno,avg_score,jige/count_cno*100||'%' jigelv from
sum(case when score>=60 then 1 else 0 end) jige
avg(score) over(partition by cno) avg_score,
count(1) over(partition by cno) count_cno
order by avg_score asc,jigelv desc;
select cno,avg(score) avg_score,
sum(case when score>=60 then 1 else 0 end)/count(1)*100||'%' jigelv
order by avg_score asc,jigelv desc;
select count(1) into c from scott.emp where ename=user1;
raise_application_error(-20001,'没有这个账号');
select count(1) into c from scott.emp where ename=user2;
raise_application_error(-20001,'没有这个账号');
select sal into s2 from scott.emp where ename=user2;
select sal into s1 from scott.emp where ename=user1;
raise_application_error(-20002,'余额不足');
update scott.emp set sal=sal-money where ename=user1;
update scott.emp set sal=sal+money where ename=user2;
select sal into s1_2 from scott.emp where ename=user1;
select sal into s2_2 from scott.emp where ename=user2;
if s1_2=s1-money and s2_2=s2+money then
为了避免多个用户对同一个数据同时进行操作,操作数据的时候数据保存出错产生脏数据
A用户在对数据做dml操作的时候,数据会被上锁,B用户不能对这个数据所在的行同时进行操作
A用户在对数据做dml操作的时候,数据所在的表会被上锁,B用户不能对表做ddl(除了新增表格结构之外)的操作
select * from scott.emp where ename='SMITH' for update;
同时操作的进程里面,每个进程都互相占用了对方的资源,谁都无法释放资源和成功跑完
select * from v$locked_object;
--找到锁的对象,是在哪个表上面 根据自己找到的这个表的名字,回去找session_id 131
select * from dba_objects where object_id=69539;
select * from v$session where sid=131;
alter system kill session '131,9555';
表分区:将一个表里面,所有的拥有相同特征的数据,在硬盘上规划出一块区域,整合在一起
)partition by hash(ename) partitions 4;
通过数据库的内部的哈希算法,将所有的行,根据名字的内容,一共放到4个不同的分区中进行分开的保存。哈希算法的分区的数量,最好是写2的次方数。
当某个列的值,是大量的重复的相同数据数据,使用列表分区,对这个列进行特征和内容的归纳和划分,将拥有相同数据的行,放在同一个分区中
partition sal_0_1000 values less than (1001),
partition sal_1001_2000 values less than (2001),
partition sal_2001_3000 values less than (3001),
partition sal_3001 values less than (maxvalue)
partition s20201125 values less than(date'2020-11-26'),
partition s20201126 values less than(date'2020-11-27')
数字类型、日期类型的数据,例如金额、时间、年龄等等,将某个范围内的数据,存放在一起,那么就使用范围分区
insert into emp_range select * from scott.emp;
如果一个表的数据越来越大,查询很慢的话,重新创建一个分区表,复制原有的数据,删除旧表。
subpartition 子分区名字 values 分区规则,
subpartition 子分区名字 values 分区规则,
subpartition sal1000_10 values less than (1001),
subpartition sal2000_10 values less than (2001),
subpartition salmax_10 values less than (maxvalue)
subpartition sal1000_20 values less than (1001),
subpartition sal2000_20 values less than (2001),
subpartition salmax_20 values less than (maxvalue)
subpartition sal1000_30 values less than (1001),
subpartition sal2000_30 values less than (2001),
subpartition salmax_30 values less than (maxvalue)
首先划分父分区,设置父分区的规则,然后在父分区中划分子分区的规则,这样可以在同时对两个列进行查询的时候,有效的减少查询需要消耗的资源和时间。
select * from user_indexes; --查看所有的索引
select * from user_tables; --查看所有的表
select * from user_tab_partitions; --查看所有的分区表
alter table 表名 drop partition 分区名;
alter table 表名 add partition 分区名 values 设置的规则;
什么是索引:就是每一个表格的目录结构,帮你快速的定位表格中的数据在表格里的位置
1. 主键索引:在创建表格的时候,添加了主键约束,那么就会自动生成主键索引
alter table emp_idx add constraint pri_empno primary key(empno);
alter table emp_idx add constraint uni_empno unique(empno);
2.2 在没有约束的前提下,手动创建唯一索引,唯一索引不会反过去创建唯一约束
create unique index idx_emp_empno on emp_idx(empno);
3. 普通索引:这个列经常需要被查询,但是这个列又没有什么特点
create index idx_nor_ename on emp_idx(ename);
4. 组合索引:和普通索引相同,有多个列需要同时被查询,但是这些列也没有什么特点,那么就放在一起,创建一个组合索引
create index idx_sal_job on emp_idx(sal,job);
create index 索引名 on 表名(a,b,c);
5. 函数索引:如果你的列,是需要被使用函数计算之后再用来查询,那么计算过程需要被写在索引里面
create index idx_func_hiredate on emp_idx(to_char(hiredate,'yyyy'));
6. 位图索引:列的内容是由大量的重复的内容组成的 bitmap
create bitmap index idx_emp_deptno on emp_idx(deptno);
create index idx_hash_ename on emp_hash(ename) local;
create index idx_hash_job on emp_hash(job) global;
--本地索引的话,在创建唯一索引的时候,在整个表中,可能会出现重复信息,在一个分区里面,值保证是唯一的,全局索引是整个表中,数据唯一存在
--删除了一个分区或者新增了一个分区,那么全局的索引会失效,需要你删除了索引然后重新建立,本地的索引是不会失效的
主键、唯一、普通、组合、函数(普通的normal类型) 树状结构 b树索引,btree索引
普通索引是通过根节点、分支节点、叶子节点、行数据四个节点块,一层层进行数据范围的筛选。
一个表不要建超过5个索引;索引的数量,不要超过列的数量的15%。
有一个2000W数据的表格,要接着往里面添加2000W的数据,怎么样操作最快?
select * from emp_idx where to_char(hiredate,'yyyy')=1981;
select * from emp_idx where sal+1000=4000 and job='MANAGER'
select * from emp_idx where deptno!=20
select * from emp_idx where not deptno=20
select * from emp_idx where ename is null
insert into t2 values('a','b',1);
insert into t2 values('b','c',2);
insert into t2 values('d','a',2);
insert into t2 values('a','c',2);
insert into t2 values('e','f',5);
(select replace(u,'a','') u from
(select concat(from_user,to_user) u,value from t2)
(select concat(from_user,to_user) u,value from t2) b
where a.u=substr(b.u,1,1) or a.u=substr(b.u,2,1)
(select a.u,from_user u2,value from
(select replace(u,'a','') u from
(select concat(from_user,to_user) u,value from t2)
select a.u,to_user u2,value from
(select replace(u,'a','') u from
(select concat(from_user,to_user) u,value from t2)
insert into u1 values(1,'张三','北京');
insert into u1 values(2,'李四','上海');
insert into u1 values(3,'王五',NULL);
insert into u2 values(1,'张三','上海');
insert into u2 values(3,'王五','广州');
insert into u2 values(4,'赵六','深圳');
select case when b.id is null then a.id else b.id end id,
case when b.name is null then a.name else b.name end name,
case when b.address is null then a.address else b.address end address
from u1 a full join u2 b on a.id=b.id
max(r) over(partition by id,name) m
在plsql工具的菜单栏里面,点击explain plan按钮,或者使用f5的快捷键来查看执行计划执行计划你看什么?
2. A表和B表的数据,相差很大,并且表连接的列都是有索引的,这个时候的等值连接就不会变成hash join,而是会使用nl嵌套连接。
两个表的连接,筛选条件不是对列和列进行筛选,而是对列和值进行筛选
/* +leading(a b) */ a一定要是小表(驱动表),b一定是大表(匹配表)
/*+ parallel(8) */ 强制使用并行的资源,来执行这个sql语句
在oracle中怎么去优化查询的sql语句/怎么优化数据库?
2.查看表格的数量,如果数据量很大,就先给表格进行分区表的设置
6.使用临时表去存储一个或者多个大表筛选的结果,然后使用临时表进行表格的连接
8. 尽量少使用union minus intersect等集合的运算,这些都是效率很差的关键字
oracle的序列:sequence,一组有规律的从大到小或者从小到大的数字,一般序列都是在表格里面,充当主键的自增序号来使用的
insert into s1 values(seq02.nextval,'tom');
oracle的视图:view 一个或者多个表查询的结果,这个结果就是一个虚拟的表,每次运行视图,都会重新运行视图中的那个查询语句
1. 将一个复杂的select语句,放入到一个视图里面,简化日常的操作
2. 可以隐藏一部分原表的列,简化别人在操作表的时候的业务逻辑
对拥有复杂逻辑的视图,再次表连接等操作,会导致语句更加复杂,运行效率很慢。
oracle的物化视图:是一个真实的物理的表格,将一个或多个表格查询的结果,当成一个新的表格来保存,物化视图的表格,会对原表的数据进行同步,物化视图的表格,本身就是不能更改的
create materialized view 物化视图名字
create materialized view stu_nan
select * from student where ssex='男' and sage>20;
create materialized view stu_nv_20
next to_date(to_char(sysdate+1,'yyyy-mm-dd')||' 10:00:00','yyyy-mm-dd hh24:mi:ss')
select * from student where ssex='女' and sage>20;
1. complete 完全刷新,整个表格全部都更新一次数据
3. force 默认的更新方式,默认的更新方法就是fast
dbms_mview.refresh('物化视图的名字','更新的方法');
1. 视图是一张虚拟的表格,不会占用磁盘空间,物化视图是一个真实的表格,会占用磁盘空间
2. 视图为了简化select操作用的,物化视图也叫做快照表,是为了保存某个表格或者是select语句在某个时间点的数据而存在的
3. 视图是实时更新的,物化视图有两个刷新表格内容的方法,一种是提交数据的时候更新,第二种是定时更新
4. 当原表非常大的时候,视图不会减少查询时间,物化视图是会减少查询时间的
拉链表就是一张普通的表格,这个表格会保存你每一次数据前后变更的状态。
有开始时间和结束时间还有变更状态这三列,用来记录每一行数据前后变更的状态和顺序,这三列叫做缓慢变化维。
会创建列的旧数据的备份列,会保存最近一次的变更的数据,和数据变更的时间
sql语句的分类:dcl(权限的操作 grant revoke) ddl(对数据库对象的操作:用户 表 索引 视图 物化视图 create alter drop truncate) dml(对表里面的数据的操作 insert update delete) dql(表数据的查询 select)
数据类型:integer number number(总长度,小数精度) char(长度) varchar2(长度)
约束条件:primary key unique not null check foreign key
单行函数:数字 round trunc abs floor(6.3 变6) ceil(6.1 变7) mod power
字符串 substr concat replace length
日期 last_day months_between add_months sysdate
分析函数:row_number rank dense_rank lag lead + over()
将一个列的字符串,以行的方式拼接起来,中间用逗号隔开怎么去做数据的同比和环比?
lag() over(partition by month order by year)
lag() over(partition by year order by month)
select * from a1 join a2 on a1.year=a2.year+1 and a1.month=a2.month;
select * from a1 join a2 on a1.month=a2.month+1 and a1.year=a2.year;
有a表和b表,a和b都有身份证的列,找出a表有但是b表没有的身份证号码。
select * from a left join b on a.id=b.id where b.id is null;
select * from a left join b on a.id=b.id and a.id=2;
select * from a left join b on a.id=b.id where a.id=2;
alter system kill session(sid, serial#);
匿名块:是一个没有名字的代码块,一般就是临时处理数据用的,用完一次就不要了
dbms_output.put_line(一个变量或者一个内容);
dbms_output.put_line(a||b||c);
select sal into v_sal from emp where empno=7369;
dbms_output.put_line('工资是'||v_sal);
select * into v_user from emp where empno=7369;
dbms_output.put_line(v_user.ename||','||v_user.job);
select * into v_user from emp where ename=v_ename;
dbms_output.put_line(v_user.ename||','||v_user.job);
在代码块中,所有的select都一定要有into来存放你查询出来的数据
select count(1) into c from emp where deptno=60;
dbms_output.put_line('部门里面没有员工');
dbms_output.put_line('部门有多个员工');
select sal into v_sal from emp where deptno=60;
练习:用户输入一个数字,然后去判断这个数字是正数,负数,零?
输入一个用户的编号,首先要先判断有没有这个用户,如果有这个用户,就输出这个用户的工资等级,2000以下是C,2001-3000是B,3001以上是A。
select count(1) into c from emp where empno=v_empno;
dbms_output.put_line('没有这个员工');
select sal into v_sal from emp where empno=v_empno;
elsif v_sal>2001 and v_sal<=3000 then
和if语句相同类型和效果的另一些判断语句的写法:case when
select count(1) into c from emp where empno=v_empno;
when c=0 then dbms_output.put_line('没有这个员工');
else dbms_output.put_line('有这个人');
for:有循环范围的循环方式,一开始就知道运行次数的循环方法
dbms_output.put_line('hello'||i);
dbms_output.put(i||'*'||j||'='||i*j||' ');
假如现在有鸡和兔子,一共有35个头,94只脚,计算出兔子和鸡分别有多少只?
dbms_output.put_line(ji||','||tu);
if ji+tu=35 and 2*ji+4*tu=94 then
dbms_output.put_line(ji||','||tu);
计算出100-999之间所有的水仙花数 个位的3次方+十位的3次方+百位的3次方
if power(bai,3)+power(shi,3)+power(ge,3)=bai*100+shi*10+ge then
dbms_output.put_line(bai*100+shi*10+ge);
create table emp_2 as select * from scott.emp where 1=2; --只会复制结构,不会复制约束
先创建一个和scott.emp结构相同的表格,从上往下查询整个表格的数据,
一行行的读取数据,将名字里面包含了A的,并且工资低于2000的用户信息,单独复制保存到新表中。
select count(1) into c from scott.emp;
select empno,ename,job,mgr,hiredate,sal,comm,deptno into v_user
from (select a.*,rownum r from scott.emp a) where r=i;
if v_user.ename like '%A%' and v_user.sal<2000 then
insert into emp_2 values(v_user.empno,v_user.ename,v_user.job,v_user.mgr,v_user.hiredate,v_user.sal,
dbms_output.put_line('数字'||n);
有张纸,厚度是1mm,珠穆朗玛峰是8848m,请问,这个纸要对折多少次,厚度才会超过山的高度。
loop:判断条件,当条件为真的时候,退出循环,条件为假的时候执行循环
假如从今天开始存1分钱,每天翻倍,明天2分,后天4分,大后天8分,请问要多少天才能存够100万元,使用loop循环计算。
continue:直接开始下一次的循环,忽略掉continue后面的代码
goto:标签语句,使用goto进行代码的任意的跳转,在工作中尽量不要用,容易引起逻辑的混乱
dbms_output.put_line('world');
dbms_output.put_line('hello');
--备份所有自己的T开头的表格,表格的名字 STUDENT_1126 原表名_月日
create table tmp_t(tn varchar2(50));
select count(1) into c from user_tables where table_name like 'T%';
insert into tmp_t select table_name from user_tables where table_name like 'T%';
(select tn,rownum r from tmp_t)
s:='create table '||v_tn||'_1126 as select * from '||v_tn;
--找到自己的所有的表,如果这个表中间的某个字符串varchar2的列,长度没有200,那么统一修改成长度200
使用select * from user_tab_columns; 查询表格和列的信息
select count(1) into c from user_tab_columns
where data_type='VARCHAR2' and data_length<200;
--找出所有符合条件的表名,列名,拼接user_tab_columns和user_tables,确定找到的名称都是表的名字,排除掉视图的名称
select table_name,column_name into v_tn,v_cn from
(select a.table_name,column_name,rownum r from user_tab_columns a join user_tables b on a.table_name=b.table_name
where data_type='VARCHAR2' and data_length<200) where r=i;
select count(1) into c2 from user_tab_partitions where table_name=v_tn;
s:='alter table '||v_tn||' modify '||v_cn||' varchar2(200)';
insert into numbers values(i);
select n into n1 from(select n,rownum r from numbers) where r=i;
select n into n2 from(select n,rownum r from numbers) where r=j;
dbms_output.put_line(n1||','||n2);
for i in (select n from numbers) loop
for j in (select n from numbers) loop
dbms_output.put_line(i.n||','||j.n);
游标:cursor,从上往下游动的箭头,每一次都会读取一行数据,每一行数据都只能读取一次
cursor mc is select * from scott.emp;
dbms_output.put_line(v_user.ename||','||v_user.deptno);
cursor mc is select table_name from user_tables where table_name like 'E%';
cursor mc is select * from scott.emp where sal>=2000;
dbms_output.put_line(i.ename||','||i.sal);
for i in (select * from scott.emp) loop
dbms_output.put_line(i.ename||','||i.sal);
for i in (select table_name from user_tables where table_name like 'U%') loop
execute immediate 'create table '||i.table_name||'_1127 as select * from '||i.table_name;
(select a.table_name,column_name from user_tab_columns a join user_tables b on a.table_name=b.table_name
where data_type='VARCHAR2' and data_length<500) a
(select distinct table_name from user_tab_partitions);
execute immediate 'alter table '||i.table_name||' modify '||i.column_name||' varchar2(500)';
上面的游标,叫做静态游标,就是一旦声明,游标的内容就不会变了。
动态的游标:为了让你只声明一个游标,可以反复的使用这个游标的类型,不需要创建多个游标
--声明一个动态游标的类型 自己定义的dongtai_c和number varchar2 date是一个意思
open mc for select * from scott.emp where deptno=10;
dbms_output.put_line(v_user.ename||','||v_user.deptno);
动态和静态的游标,都叫做显性游标,还有一种叫做隐性游标。通过sql关键字来查看,本次数据修改的范围,一共有多少行。
delete from emp where sal>1500;
dbms_output.put_line(sql%rowcount);
修改emp表格,如果员工是10号部门,就给他加10%的工资,20号部门加20%,30部门加30%。
for i in (select * from scott.emp) loop
update scott.emp set sal=sal*1.1 where empno=i.empno;
update scott.emp set sal=sal*1.2 where empno=i.empno;
update scott.emp set sal=sal*1.3 where empno=i.empno;
create or replace procedure 存储过程名字
create or replace procedure pro_p1
create or replace procedure 存储过程名字(输入参数名字 in 数据类型)
create or replace procedure pro_p2(n1 in number,n2 in number)
dbms_output.put_line(n1+n2+n3);
create or replace procedure 存储过程名字(输入参数名字 out 数据类型)
create or replace procedure pro_p3(s out number)
create or replace procedure pro_p4(n1 in number,n2 in number,s out number)
什么时候会使用到存储过程?一个固定的功能的代码块,并且这个代码需要经常的反复的运行
alter table 表名 add partition 分区名 values 设置的规则;
alter table sales_info add partition s20201127 values less than(date'2020-11-28');
alter table 表名 drop partition 分区名;
alter table sales_info drop partition s20201127;
partition s20201124 values less than(date'2020-11-25'),
partition s20201125 values less than(date'2020-11-26'),
partition s20201126 values less than(date'2020-11-27')
create or replace procedure pro_sales_add_partition
select count(1) into c from user_tab_partitions
where table_name='SALES_INFO' and partition_name=concat('S',to_char(sysdate,'yyyymmdd'));
s:='alter table sales_info add partition s'||to_char(sysdate,'yyyymmdd')||
' values less than(date'''||to_char(sysdate+1,'yyyy-mm-dd')||''')';
call pro_sales_add_partition();
create or replace procedure 过程名
1. 系统预定义的异常 21种 有名字有编号的错误,就是预定义错误
https://www.cnblogs.com/wwxbi/p/4162675.html
2. 系统的非预定义异常:有错误的代码,但是这个错误在系统中没有名字
create or replace procedure pro_p7
--定义一个变量,这个变量数据类型是exception异常类型
pragma exception_init(fk_error,-2291);
update emp set deptno=60 where empno=7369;
dbms_output.put_line('父表中没有这个内容');
3. 自定义异常:并不是语法错误,自己定义的逻辑上的问题,通过raise_application_error(错误编号, 错误提示),错误编号的范围是-20001到-20999
例如:现在有人要加工资,但是规定是,每次加工资,不能超过原有工资的20%
create or replace procedure pro_p8(v_empno in number,v_sal in number)
select sal into s from emp where empno=v_empno;
raise_application_error(-20001,'工资不能超过原来的20%'); --编号的范围 -20000 20999
update emp set sal=v_sal where empno=v_empno;
create or replace procedure insert_error_log(v_proce_name in varchar2,v_table_name in varchar2,
v_mcode in varchar2,v_merror in varchar2)
insert into error_log values(v_proce_name,v_table_name,v_mcode,v_merror,sysdate);
3.在另一个过程里面,如果运行报错了,那么就调用存入错误日志的存储过程
create or replace procedure pro_p8(v_empno in number,v_sal in number)
select sal into s from emp where empno=v_empno;
raise_application_error(-20001,'工资不能超过原来的20%'); --编号的范围 -20000 20999
update emp set sal=v_sal where empno=v_empno;
insert_error_log('pro_p8','emp',sqlcode,sqlerrm);
1. 写一个存储过程,要求往dept中添加新的部门,要求输入部门编号,部门名称,部门地点,输入的过程中,你的部门编号不能和之前的重复
create or replace procedure add_dept(v_deptno in number,v_dname in varchar2,v_loc in varchar2)
select count(1) into c from dept where deptno=v_deptno;
dbms_output.put_line('部门已存在');
insert into dept values(v_deptno,v_dname,v_loc);
call add_dept(50,'BIGDATA','SHENZHEN')
2. 输入一个部门的编号,将这个部门里面所有人的名字和员工编号显示出来。
create or replace procedure select_emp(v_deptno in number)
cursor mc is select * from emp where deptno=v_deptno;
dbms_output.put_line(i.ename||','||i.empno);
数据库的函数:自己去定义数据运行的过程,最终返回这个过程结果的代码块
create or replace function 函数名(输入的参数 数据类型)
create or replace function qiuhe(n1 number,n2 number)
select empno,qiuhe(sal,comm) from emp;
实现一个和数据库power()相同的函数的功能,自己写一个求数字的次方的方法:
create or replace function cifang(n number,c number)
练习:数据库有个initcap()函数,这是首字母大写的函数,自己写一个最后一个字母大写的函数。
create or replace function endcap(str varchar2)
s:=concat(lower(substr(str,1,length(str)-1)),upper(substr(str,-1)));
select endcap('allen') from dual;
1.存储过程可以没有参数,也可以有输入和输出的参数;函数一定要有输入的参数和返回的值
4.函数是用来进行数据计算的,存储过程是用来实现一个固定的功能
数据库的触发器:在做A这个事情的时候,自动的发生B这个事情 trigger
create or replace trigger 触发器名字
before|after insert or update or delete on 表名
create or replace trigger jinzhi_del_boss
raise_application_error(-20001,'不能删除老板');
如果要去更新用户的工资,新增的用户,工资不能超过2000元,老用户涨工资不能超过原来工资的10%。
create or replace trigger ck_emp_sal
before insert or update on emp
raise_application_error(-20001,'新员工工资不能超过2000元');
raise_application_error(-20002,'老用户涨工资不能超过原来工资的10%');
create or replace trigger backup_dept
after insert or update or delete on dept
insert into dept_old values(:new.deptno,:new.dname,:new.loc);
update dept_old set deptno=:new.deptno,dname=:new.dname,loc=:new.loc
delete from dept_old where deptno=:old.deptno;
create or replace trigger insert_dept_log
after insert or update or delete on dept
insert into dept_log values(:new.deptno,:new.dname,:new.loc,user,sysdate,'新增数据');
insert into dept_log values(:old.deptno,:old.dname,:old.loc,user,sysdate,'更新前的数据');
insert into dept_log values(:new.deptno,:new.dname,:new.loc,user,sysdate,'更新后的数据');
insert into dept_log values(:old.deptno,:old.dname,:old.loc,user,sysdate,'删除数据');
create or replace trigger insert_dept_log_trunc
if ora_dict_obj_name='DEPT_OLD' then
insert into dept_log values(null,null,null,user,sysdate,ora_sysevent);
包:统一的管理同一个模块下所有的代码的块的一个概念 package
create or replace package 包的名字
function 函数名字(输入的参数 数据类型) return 返回的数据;
procedure 过程的名字(输入的参数 in 数据类型, 输出的参数 out 数据类型);
create or replace package pkg_emp
procedure add_emp_info(v_empno in number,v_ename in varchar2,v_job in varchar2,v_mgr in number,
v_hiredate in date,v_sal in number,v_comm in number,v_deptno in number,v_mobile in char);
function select_dept_count(v_deptno number) return number;
create or replace package body 包的名字
function 函数名字(输入的参数 数据类型) return 返回的数据
procedure 过程的名字(输入的参数 in 数据类型, 输出的参数 out 数据类型)
create or replace package body pkg_emp
procedure add_emp_info(v_empno in number,v_ename in varchar2,v_job in varchar2,v_mgr in number,
v_hiredate in date,v_sal in number,v_comm in number,v_deptno in number,v_mobile in char)
insert into emp values(v_empno,v_ename,v_job,v_mgr,
v_hiredate,v_sal,v_comm,v_deptno,v_mobile);
function select_dept_count(v_deptno number) return number
select count(1) into c from emp where deptno=v_deptno;
call pkg_emp.add_emp_info(7777,'LUCY','CLERK',8889,null,1000,100,20,null);
create public database link 链接的名字
connect to 用户名 identified by "密码"
create public database link teacher_db
connect to zz identified by "123456"
(ADDRESS = (PROTOCOL = TCP)(HOST = PC-202004101937)(PORT = 1521))
create table zq_customer_info as select * from zq_customer_info@teacher_db;
create table xt_customer_info as select * from xt_customer_info@teacher_db;
结论:两者差别几乎可忽略。所以查询所有字段(或者大多数字段)的时候,大可 select * 来操作。如果某些不需要的字段数据量特别大,还是写清楚字段比较好,因为这样可以减少网络传输。
SELECT *,需要数据库先 Query Table Metadata For Columns,一定程度上为数据库增加了负担(影响网络传输的性能),但是实际上,两者效率差别不大。
因为程序里面你需要使用到的列毕竟是确定的, SELECT * 只是减少了一句 SQL String 的长度,并不能减少其他地方的代码。
select abc from table; 和 select * from table;
在 abc 字段有索引的情况下,mysql 是可以不用读 data,直接使用 index 里面的值就返回结果的。但是一旦用了 select *,就会有其他列需要读取,这时在读完 index 以后还需要去读 data 才会返回结果,这样就造成了额外的性能开销。
综上:除平时练习使用,其他情况都不推荐使用 SELECT * FROM XXX 。
遇到一个需要补位的问题,蛋疼的自己写了一个半天调试不通,后来才发现原来就有。。瞎忙
LPAD是在字符串左边用设定的字符补满指定位数,RPAD则是右边