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,自动
递增)……
数据库设计三范式(很有用,但是该打破的时候要打破;范式主要目标消除冗余数据)
第一范式:要有主键;列不可分(不含有表中表)。
部分依赖:非主属性,依赖部分主键(拆分表,查询时需要作连接)
传递依赖:
弄清需求:
板块、帖子、回复、用户