Oracle下SQL学习笔记

时间:2023-03-09 15:41:49
Oracle下SQL学习笔记

主机字符串:as sysdba

alter user scott account unlock;//解锁scott,不会就谷歌检索

DML语句,增、删、查、改

select语句:
熟悉表结构 desc emp;

number(4) 4位数字类型
number(7,2) 7位数字,2位小数
varchar2(10) 10位可变长度字符串
date 日期类型

select * from salgrade s;select s.* from salgrade s;

select ename, sal * 12 as "Annual Salary" from emp;//有空格时使用双引号;双引

号内容显示 保持原样;这里给列去别名,也只能有双引号,不能使用单引

号‘AnnualSalary'

select 3*4 from dual;//一行的表dual

0不是空值null,任何含有空值的表达式的值都是空值

coalesce(comm,0)

字符串连接,连接列值: || 字符串用单引号;不能用双引号 || “abC”
select ename||sal from emp;

select ename || 'asdf' from emp;//结果中,单引号包含的字符串还是小写:

JANESasdf

去除重复值:
select distinct deptno from dept;//修饰多个字段,去除重复的组合
select distinct job,comm from emp;//结果中clerk ,null 只保留了一个

where 过滤条件,and or not 连接多个条件
select * from emp where empno=7782;//等值判断
select * from emp where deptno <> 10;//不等于
select ename from emp where eanme > "CBA"//字符串比较
select ename, sal from emp where sal between 800 and 1000;//包含等于
select ename, comm from emp where comm is not null;//是否是空值
ename in('SMITH', 'TOM')
sal not in (800,1500)
日期处理:1.按照相关特定格式写 2.日期函数
select ename, hiredate from emp where hiredate > '28-4月-1999';

模糊查询,通配符 %零个或者多个,_ 一个字母,一个汉字占2个
select ename from emp where ename like ‘%ALL%’;

转义字符,默认的\ 指定转义字符 not like'%$%A%' escape '$';

排序,可以按多个字段排序
降序select deptno from dept order by deptno desc ;默认升序asc ascent 上升

descent 下机
select ename, sal from emp where sal > 1000 order by sal, ename desc;

SQL函数;接收实参,字段名。
对字符串操作: lower() upper() select lower(upper(ename)) from emp;
substr(ename,2,3) 截子串 从第2个字符开始截,一共截3个

chr(65) 结果是65对于的ascii码
select ascii('A') from dual;

round(23.65,-1) 四舍五入到十位,round 圆,大约
select round(12.3347,2) from dual; 四舍五入小数点后2位

对数字格式转换,用得较少
select to_char(sal,'$99,999.9999') from emp;//指定格式转换数字,9代表一位数字
to_char(sal,'L00000.0000)//L本地货币

对日期(包含日期、时间)转换,把日期转换成字符串,用得很多
select to_char(hiredate,'yyyy-mm-dd hh:mi:ss') from emp;
select to_char(sysdate,'yyyy-mm-dd hh:mi:ss') from dual;//sysdate 当前时间
select to_char(sysdate,'yyyy-mm-dd hh24-mi-ss') from dual;//yyyy mm dd等*组

合,24进制

to_date() 把字符串转换成日期
select ename, hiredate from emp
where hiredate > to_date('1982-2-28 17:23:59', 'yyyy-mm-dd hh24:mi:ss');

to_number()把字符串转换成相关数字
to_number('$1,223.00', '$9,999.99);
select sal from emp where sal > to_number('$1,888.22','$9,999.99')

nvl(comm,0) 把空值转换成数值 coalesce(comm,0)
单行函数,有多少条记录就有多少条输出

重点:组函数,多行函数:多条记录座位输入,只产生一个输出
max(sal)只有一个最大值,但是可能对于多条记录
min(sal) avg(sal) sum(sal) count(*)求表中记录数

select count(*) from emp where deptno=10;

count某一个字段,如果不是空值,就算一个
select count(comm) from emp;
select count(distinct deptno) from emp;

每个部门的平均薪水 group by 分组函数;
出现在select列表中的字段,没有出现在组函数里,就必须出现在group by 里,才能产

生唯一值,匹配起来。

select deptno, avg(sal) from emp group by deptno;
按照两个字段分组,就是安装两个字段的组合来分组
select deptno,job,max(sal) from emp group by deptno,job;

薪水最高的人的名字(子查询)
select ename, sal from emp
where sal = (select max(sal) from emp);

where对单条记录进行过滤,不能对分组group by的现在,先执行where再分组
select avg(sal),deptno from emp
where sal >1500
group by deptno;

having,对分组进行限制
select avg(sal),deptno from emp group by deptno
having avg(sal) >2000

先取数据select 再 where限制 再分组group by 再having限制分组 再order by 排序

薪水大于1200的雇员,按部门分组,分组平均薪水大于1500,查询分组的平均工资,按工

资倒序排列
select avg(sal),deptno from emp
where sal >1200
group by deptno
having avg(sal) >1500
order by avg(sal) desc

子查询
求工资比平均工资高的人
select ename,sal from emp
where sal > (select avg(sal) from emp);

每个部门挣钱最多的名字,部门名称?(作连接的表有相同的属性名,需要.指明表)
select ename,emp.deptno,sal from
emp join(select max(sal) max_sal,deptno from emp group by deptno) t
on(emp.deptno=t.deptno and emp.sal=t.max_sal);

每个部门平均薪水等级?? select ... from (.. join .. on..)
(取别名是给某个子查询形成的表取名,两张表要连接,要包含连接条件中出现的属性列

,故意select * from salgrade,为了突出这样才包含on条件中的losal和hisal属性)
select t1.avg_sal,t1.deptno,t2.grade from
((select avg(sal) avg_sal, deptno from emp group by deptno) t1
join(select * from salgrade) t2
on(t1.avg_sal between t2.losal and t2.hisal));

select avg_sal, grade from
(select avg(sal) avg_sal,deptno from emp group by deptno)
t join salgrade
on(t.avg_sal between losal and hisal);

自连接,取别名,当成两张表(连接后存在重复列)
select t1.empno, t1.ename, t1.mgr, t2.ename mgr_name from emp t1, emp t2
where t1.mgr=t2.empno;

交叉连接 cross join
select ename,dname from emp cross join dept;//
这样连接不行:select ename,dname from emp join dept;要么指明连接条件,要cross

join
select ename, dname from emp, dept//笛卡尔乘积(行的所有可能组合)
where emp.deptno=dept.deptno;

where中不出现连接条件,只写过滤条件。读起来更清楚,SQL1999标准
select ename,dname from emp join dept on
(emp.deptno=dept.deptno);
select ename,dname from emp join dept using(deptno);//不推荐使用;假设两张表

都有字段deptno,且类型一样。

select ename,grade from emp join salgrade on(emp.sal between salgrade.losal

and salgrade.hisal);

三张表连接
select ename,dname,grade
from emp e join dept d on(e.deptno=d.deptno)
join salgrade s on(e.sal between s.losal and s.hisal)
where ename >'CLERK';

外连接:
左外连接会把左边那张表的多余数据(不能产生连接数据)拿出来 left (outer) join
右外连接 right (outer) join
全外连接 full join//1992不支持

部门平均薪水等级? //between 小的值 and 大的值
select deptno,avg(grade) avg_grade from
(select ename,deptno,sal,grade from
emp e join salgrade s
on(e.sal between s.losal and s.hisal)
) group by deptno;//

雇员中有哪些人是经理人?
select distinct t2.ename mgr_name from
((select mgr from emp)t1 join
(select ename,mgr,empno from emp)t2
on (t1.mgr=t2.empno));

select distinct ename mgr_name from emp
where empno in(select mgr from emp);//编号出现在mgr中就是经理人

不用组函数,求薪水最高值?(全部两两比较,笛卡尔乘积…,自连接)
select sal from emp
where sal not in(select t1.sal from (emp t1 join emp t2 on(t1.sal<t2.sal)));

平均薪水最高的部门的编号?(平均薪水部门编号->平均薪水最大值->部门编号)
select t.deptno ,t.avg_sal max_avg_sal from
(select avg(sal) avg_sal,deptno from emp group by deptno) t
where avg_sal=
(select max(avg_sal) from
(select avg(sal) avg_sal,deptno from emp group by deptno));

平均薪水最高的部门的名称?
select dname from dept
where deptno =( );

求平均薪水的等级最低的部门的部门名称
select deptno from
(
select t.avg_sal,s.grade,t.deptno from
((select avg(sal) avg_sal,deptno from emp group by deptno) t
join
salgrade s
on(avg_sal between s.losal and s.hisal))
)where avg_sal =
(select min(grade)
from
(select t.avg_sal,s.grade,t.deptno from
((select avg(sal) avg_sal,deptno from emp group by deptno) t
join
salgrade s
on(avg_sal between s.losal and s.hisal))));

第一步: 平均薪水,等级,部门编号
select avg_sal,grade,deptno from
((select avg(sal) avg_sal,deptno from emp group by deptno)
join
salgrade s
on(avg_sal between s.losal and s.hisal))
在这个表的基础上求最低薪水等级,最低等级对应的部门编号,部门编号对应的部门名称
(select套select)
select dname,deptno from dept
where deptno=(select deptno from
(select avg_sal,grade,deptno from
((select avg(sal) avg_sal,deptno from emp group by deptno)
join
salgrade s
on(avg_sal between s.losal and s.hisal)))
where grade=
( select min(grade) from
(select avg_sal,grade,deptno from
((select avg(sal) avg_sal,deptno from emp group by deptno)
join
salgrade s
on(avg_sal between s.losal and s.hisal)))));

组函数可以嵌套,最多可以嵌套两层,因为嵌套两层后输出必然为单行
select max(avg(sal)) from emp group by deptno;

创建视图(视图是虚表,实际数据还在原表中)create view as
create view v_dept_avg_sal_info as
select deptno,grade,avg_sal from
(select avg(sal) avg_sal, deptno from emp group by deptno) t
join salgrade s on(t.avg_sal between s.losal and s.hisal);

授权grant
登陆 conn sys/zwj as sysdba;
grant create table,create view to scott;
conn scott/zwj;

部门经理中平均薪水最低的部门的名称?
select dname from dept
where deptno =
(
select deptno from
(
select deptno, avg(sal) avg_sal from emp
where job='MANAGER'
group by deptno
)
where avg_sal =
(
select min(avg(sal)) min_avg_sal from emp
where job='MANAGER'
group by deptno
)
);

比普通员工最高薪水还要高的经理人名称?
select ename as "Sal_big_than_Staff" from emp where
empno in(select mgr from emp where mgr is not null)
and sal >
(
select max(sal) max_staff_sal from emp
where empno not in(select mgr from emp where mgr is not null));//mgr中有空值,

如果不除去,结果不对

求薪水最高的前5名雇员?(rownum <=5 限制返回行数,但是不能直接select where

order by ,这样就直接只取了表的前五行,然后按sal排序)
select * from
(
select ename,sal from emp
order by sal desc
)
where rownum <=5;

求薪水最高的第6到第10名雇员?(求差集函数minus,子查询not in)
select * from
(
select * from
(
select ename,sal from emp
order by sal desc
)
where rownum <=10
minus
select * from
(
select ename,sal from emp
order by sal desc
)
where rownum <=5
)order by sal desc;

执行效率。理论上……;实际执行,数据库可能做优化

表空间
创建一个新用户,建立新的表空间,再导入表
create user test identified by test default tablespace users quota 10M on

users;
授权
grant create session, create table, create view to test;
1.备份scott
exp, 登陆, 导出文件(按默认,各种回车……)
imp
test/test //登陆该新创建用户
输入用户名scott,导入的是scott下面的东西,导出文件中有可能包含多个用户导出的东

西,只需要导入scott导出的东西

rollback//回滚
create table emp2 as select * from emp;

insert
1.按属性列默认顺序,插入全部属性的值
insert into dept2 values(50,'game','Chang Sha');
2.指明字段,没指明的属性默认空值
insert into dept2(loc,deptno) values('Bei Jing',60);
3.插入子查询,要求:子查询的结果和被插入表的结构一样
insert into dept2
(select * from dept2);

Oracle伪字段rownum(首先把rownum加到表字段上),只能< 或 <=,不能和大于一起


select rownum,ename from emp;

select ename from(select rownum ,ename from emp) where rownum >10;

select rownum, ename, sal from emp
order by sal desc;//观察rownum,rownum先加到字段上,再排序

在排好序的表基础上,rownum
select rownum, ename,sal from
(select ename,sal order by sal desc)
where rownum <=10

第26集
创建表,定义表级约束,...foreign key references (sno)
create table sc(sno number(2) ,cno number(1), scgrade number(2),
foreign key (sno) references s(sno),foreign key (cno) references c(cno),

primary key(sno,cno));

没选过“黎明”老师的所有学生姓名?
select sname from s
where sno not in( select sno from sc where cno in
(select cno from c where c.cteacher = '黎明'));

下面这样逻辑不对,虽然3个表连接起来,但是有学生某门课程选的老师不是黎明,而

他又选了黎明教的那门课:Lily Math 黎明 59;Lily Compu Smith 56 这样第二条记录

中老师不是黎明,把Lily给选了出来
select s.sname,c.cname,c.cteacher, sc.scgrade from s
join sc on(s.sno = sc.sno) join c
on (sc.cno=c.cno) where
c.cteacher <> '黎明';

两门以上不及格学生姓名
select sname from
s join
(
select sc.sno,count(*) fail_class_num from sc
where scgrade <60
group by sc.sno
having count(*) >1 //此处可以having这个
)t on s.sno = t.sno;

既选修了1号又选修了2号课程的所有学生姓名(交集,、、、in、、、,差集minus,

not in并集 union/union all包括重复的项目)
select sname from s
where s.sno in
(select sc.sno from sc where cno = 1 and sno in(select sno from sc where cno =

1));

update emp2 set sal=sal*2, ename=ename||'-' where deptno = 10;

delect from dept2 //全部删了
where deptno = 20;

DDL数据定义语句,建表(create table),建视图(create view),删除表(drop

table)。DCL:grant

事务-transaction,要么全完成,要么不完成(账户转账)。
一个transaction起始于一条dml语句,正常终止于commit(提交)、遇到DDL语句

(create)、DCL语句(grant...to)、正常断开(敲exit)自动提交,一敲rollback所

有修改回退了,如果commit提交完成,上面的transaction已经完成,再rollback无效。

不能回退了。
非正常断开(断电、直接关闭窗口……),自动回滚。

数据库常用对象(表、视图)

create table(字段名 数据类型,……)
char(8):定长字符串,固定占8位(效率更高,定位快,类似数组;浪费空间,拿空间

换时间)
number(8,3):整个数字一共8位,3位小数
date:日期,年月日时分秒
long变长字符串,2G ,存图片,数据库存文件名(数据在硬盘上),一篇文章
varchar2:变长字符串,最多4K,4096字节 1Byte 8bit;
varchar2(20)可存十个字符

五个约束条件:非空,唯一,主键,外键,check;约束可以取名字;字段级约束,表级

约束。check约束用得少,一般在java这边效验过了。

取值唯一可以插入空值,空值不认为是重复的。

约束:constraint 约束名 约束类型 加约束的字段
create table stu(
id number(6),
name varchar2(20) constraint stu_name_nn not null,
sex number(1),
age number(3),
sdate date,
grade number(3) default 1,
class number(4) references class(class_id),
email varchar2(50),
constraint stu_name_email_uni unique(email,name)
);

insert into stu values(123456,'Tom',1,22,to_date

('19900101','yyyymmdd'),2,4212,'abc@126.com');

主键primary key:not null,唯一标识一个记录 。建在数字上,速度快

外键:涉及到两个字段,被参考字段必须是主属性,参考字段

create talbe class
(
class_id number(4) primary key,
name varchare2(20)
);

被参考,不能删除。

select distinct t1.name from(
(select name,sum(pcount) red_sum_count from product
where color='红色' and pcount is not null group by name) t1
join
(select name,sum(pcount) blue_sum_count from product
where color='蓝色' and pcount is not null
group by name) t2
on(t1.name=t2.name and t1.red_sum_count > t2.blue_sum_count ));

取了别名之后,不能用t1.name,只能t1.产品
select t1.产品, t1.红色, t2.蓝色 from(
(select name 产品,sum(pcount) 红色 from product
where color='红色'
group by name)t1
join
(select name 产品,sum(pcount) 蓝色 from product
where color='蓝色'
group by name) t2 on(t1.产品=t2.产品))

换一种写法:
select t1.name 产品, t1.红色, t2.蓝色 from(
(select name ,sum(pcount) 红色 from product
where color='红色'
group by name)t1
join
(select name 产品,sum(pcount) 蓝色 from product
where color='蓝色'
group by name) t2 on(t1.name=t2.产品));

alter 修改表结构(或者删了重新建一遍,插入数据一般会保存这些sql语句,删除测

试时插入的几条数据没关系)
add方式添加新列和完整性约束
drop方式,删除指定完整性约束添加或删除指定的列
change方式,修改某些列 alter table stu change id to s_id varchar2(12);
modify方式,修改某些列的数据类型

alter table t_name drop (name);//删除属性
desc stu;

alter table stu add(add varchar2(20));//添加属性

alter table stu modify(addr varchar2(15));//修改后要能容纳原来数据才能修改成功

alter table stu drop constraint stu_class_fk;//删除约束

alter table stu add constraint stu_class_fk foreign key(class) references

class(id);添加约束

alter table stu add unique(id);

删除表drop table stu;

忘了约束的名字怎么办?

user_tables 数据字典表
select view_name from user_tables;
talbe_name
constraint_name from user_constraints;
index_name from user_indexs;
数据字典表的表,dictionary(字典)
desc dictionary;

索引 create index ……on …… drop index …… 不要轻易创建索引
create index idx_stu_email on stu(email)//多个字段,为多个字段的组合创建索引

,查找时的效率更高,读的效率高,插入删除效率低了(要把索引插入索引表,索引要占

用大量空间)
drop index idx_name;

视图(视图就是一个子查询),表结构改了,视图也要维护代价;视图可以简化查询,

(视图,外模式,用户角度)提供安全;数据还在原表中;视图是可以更新数据的,实际

上是跟新原表的数据,不过很少这么用,比如视图来自多个表,容易出错。
create view v$_student
as
select……

Oracle独特的东西:序列sequence(SqlServer里面:identity),不间断的,一般是

用来作主键。一般一个sequence对应一个表,这么用,虽然一个sequence也可以用在其他

表。

并发,多个线程插入第101个帖子时
create sequence seq_article1;//第一次执行为1,第二次执行为2……;取名要见名知意

select seq.nextval from dual;//(内部做了线程同步)

insert into article values(seq.nextval,……);

表,依附在表上的约束,视图(用途很多,但是有维护代价,不轻易建),索引(牢牢

记住,面试题,建立索引),序列sequence(Oracle特有,mysql:autoincrement,自动

递增)……

数据库设计三范式(很有用,但是该打破的时候要打破;范式主要目标消除冗余数据)
第一范式:要有主键;列不可分(不含有表中表)。
部分依赖:非主属性,依赖部分主键(拆分表,查询时需要作连接)
传递依赖:

弄清需求:
板块、帖子、回复、用户