*********************************
** oracle 学习笔记 **
** author Cindy **
***********************************
初始化表的位置:
cd $ORACLE_HOME/rdbms cd demo summit2.sql
这个角本可以初始化练习用的表
set LANG = AMERICAN_AMERICA.US7ASCII
*********************************
我们目前使用的是oralce 9i 9201 版本
恢复练习表命令:
sqlplus openlab/open123 @summit2.sql
登陆oracle的命令:
sqlplus 用户名/密码
show user 显示当前登陆的身份.
set pause on
set pause off 分页显示.
oracle中默认日期和字符是左对齐,数字是右对齐
table or view does not exist ; 表或示图不存在
edit 命令用于自动打开vi修改刚修执行过的sql的命令。
修改方法二:
l 3 先定位到行 c /旧串/新串
执行出错时,利用错误号来查错误:
!oerr ora 942 (装完系统后会装一个oerr工具,用于通过错误号来查看错
误的具体信息)
想在sql中执行unix命令时,把所有的命令前加一个!就可以, 或者host( 用
于从sql从切换至unix环境中去)
/*** 初次使用时注意 ****
运行角本时的命令:
先切换到unix环境下,cd $oracle_home cd sqlplus cd demo 下面有两
个角本建表语句。
@demobld.sql
sqlplus nanjing/nanjing @demobid.sql 直接运行角本,后面跟当前目录或
者是绝对路径
保存刚才的sql语句: save 命令 第二次保存时要替换之前的角本
save 文件名 replace
把刚才保的sql重新放入 buffer中
spool 文件名
此命令会把所有的操作存在某个文件中去
spool off
练习1:查看s_emp表中员工的年工资
select first_name , salary*12 salary from s_emp;
给列起别名的命令:
利用关键字 as 或者用空格 "别名" 双引号内大小写敏感保持引号内容
原样输出,如果不加双引号时,默认为大写
拼接字段:
select first_name||last_name "employees" from s_emp ;
oracle中表达字符串用单引号来表达:
select first_name||' '||last_name from s_emp;(在两个字段之间拼接
一个空格)
查看当前用户所有的表:
练习2:(常用于批量更改数据)
set echo off
spool selecttab.sql;
select 'select * from ' || table_name ||' ; ' "table name " from
user_tables;
spool off;
set head off(去除第一行)
set feed off(去除最后一行)
练习3:(查出s_emp表中所有员工的一年的总收入)
select first_name , salary*12*( 1+nvl(commission_pct/100 , 0 ) ) "
year salary " from s_emp;
nvl函数 专用于处理空值的影响.
*******************************************************************
***************************************************************
column 定义格式化输出
column last_name Heading format a15;
column last_name;
column salary justify left format $99,999.00 ( 定义工资的显示形式
)
$ echo $LANG
zh_CN.hp15CN
$ echo $NLS_LANG
simplified chinese_china.zhs16cgbk
ORDER BY 排序 升序和降序 ASC 升序(默认) DESC 降序
select * from s_emp order by dept_id , salary desc 部门号升序,工
资降序
关键字distinct也会触发排序操作。
过滤操作: where 子句
select * from s_emp where dept_id=42; 查看部门号为42的所有员工
select * from s_emp where salary>1000 查看工资高于1000的所有员工
select salary from s_emp where first_name='Geroge' 找出名字为
Geroge的员工的工资数
select table_name from user_tables where table_name='S_EMP'; 查
某个具体表名时,表名的字符串必须要为大写
日期的默认的格式 DD-MON-RR(天-月-年)
BETWEEN AND 在什么之间 NOT BETWEEN AND
注意区间:[ ]是一个闭区间
IN( LIST) 在某个集合中 NOT IN (list)
空值会有影响 (等于list其中任何一个就行,为提高效率常把比例
高的放在前面)
LIKE 模糊配置 NOT LIKE
通配比较
IS NULL 是空
AND
OR
NOT
练习4:(找出表名以S_开头的所有表)对于一些特殊字符,要用到escape转义,
并不是一定要用\,escape后面定义是什么字符为转义字符,那就用哪个字符
select table_name from user_tables where table_name like 'S\_%'
escape '\';
当有多个条件时,要用逻辑运算符:AND OR
写对where语句:正确的数据类型判断、逻辑运算符
sql函数的作用:
sql函数的分类:单行函数、多行函数
单行函数: (dual 哑表 )
字符函数:
lower 转小写 select lower('SQLPLUS') from dual;-->
对纯字符串处理的时候
upper 转大写 select upper('sqlplus') from dual;
initcap 首字符大写 select initcap('tarena') from dual;
concat 连接字符串 select concat(first_name , last_name)
from s_emp;等效于
substr 求子串 select substr('tarenasd0603' ,1,6) from
dual; (取前六个字符) select substr('tarenasd0603',-2) from dual;
(取后两个字符)
length 求字符长度 select length('tarena') from dual;
nvl 空值函数 两个参数的类型要匹配,统一的,表示:如果有,
则返回前面的参数,如果没有就返回后面的参数
eg:select first_name,salary from s_emp where lower(first_name)
='george';
select first_name , substr(first_name , -2 ) from s_emp; (查出
s_emp表中所有用户名字的最后两个字符)
默认的是从左向右,如果是-2则表示从右向左数
练习5: select first_name , salary from s_emp where lower
(first_name)='george';
数值函数:
round 函数(四舍五入) select round(45.935, 2) from dual; 不带参
数时默认为0位小数
trunc 函数(截取,不管后面的数字) select trunc(45.995, 1) from dual;
日期函数:DD-MON-RR ,默认不显示世纪、时、分、秒 日期格式敏感
世纪、年、月、日
sysdate 返回当前系统时间 select sysdate from dual;
更改当前会话的设置格式:
alter session set nls_date_format='yyyy mm dd hh24:mi:ss';
select sysdate-1, sysdate+1, sysdate , sysdate+1 from dual; 注意
单位是以天为单位,也可以得到多少小时、多少分钟之后的时间
MONTHS_BETWEEN (DATE1 , DATE2 ) 求两个日期之前相差的月数
add_months(date , 4 ) 在 date上再添加4个月
select round(last_day(sysdate),'month') from dual;
select next_day(sysdate,'FRIDAY') from dual ; 求这个日期的下一个
FRIDAY
last_day 求月的最后一天
round 函数: select round(sysdate, 'MONTH') from dual; 参
数可以为: MONTH YEAR(看上半年还是下半年)
select trunc(last_day(sysdate)+1) from dual;
select add_months(trunc(sysdate, 'MONTH'), 1 ) from dual ;
关于 日期的两种形式:
转换函数:
to_char显示日期:
从数字转化为char to_char(date,'格式')
从日期转化为char to_char(date, 'fmt' )
select to_char(sysdate, 'yyyy mm dd hh24:mi:ss') from dual;
select to_char(sysdate, 'fmyyyy mm
dd hh24:mi:ss') from dual;去掉前导名
select to_char(sysdate ,'YEAR MONTH
dy
eg:查出三月分入职的员工:select first_name,start_date from s_emp
where to_char(start_date,'mm')='03';
to_date表达日期:
字符转日期 select to_date('2000 11 20', 'yyyy mm dd ')
from dual;
select round(to_date('10-OCT-06'
,'dd-mon-RR') ) from dual;
to_number
字符转数字
select to_number('10') from dual ;
where 条件一定是根据某个字段来进行过滤操作.
多表连接操作:
两表没有任何关联时会产生迪卡尔机:
select first_name , name from s_emp , s_dept;
等值连接:
练习一:查看员工的姓名和员工部门号:(要考虑到表中实际数据中空值的影响)
select first_name , name from s_emp e, s_dept d where e.dept_id=d.id;同时起了别名
select first_name , name from s_emp e, s_dept d where e.dept_id=d.id and e.first_name='George';具体到哪个人所在的部门
练习二:每个员工所在的部门和部门所在的地区
select first_name , name from s_emp, s_dept, s_region where s_emp.dept_id=s_dept.id and s_dept.region_id=s_region.id;
eg:select first_name,d.name,r.name
from s_emp e,s_dept d,s_region r
where e.dept_id=d.id and d.region_id=r.id;
等值连接:
练习三:找出每个员工和每个员工的工资级别
select a.ename , a.sal, b.grade from emp a , salgrade b where a.sal between b.losal and b.hisal;
select a.ename , a.sal, b.grade from emp a , salgrade b where a.sal>=b.losal and a.sal<=b.hisal;
自连接:当一个表的插入行之间有了关系时就发生了(又名:内连接)
select first_name , manager_id from s_emp;
查出所有员工的部门领导的名称:( 这种sql会少一条记录,总经理没有被配置上)
select e.first_name , m.first_name from s_emp e , s_emp m where e.manager_id=m.id;
外连接:(防止空值时,用(+)的一方会模拟一条记录配置另一方)这就称为外连接,一个记录都不能少;
select e.first_name , m.first_name from s_emp e , s_emp m where e.manager_id=m.id(+);
+号放在哪边就表示在哪边补空,来跟对方来匹配,使得数据一个都不会漏掉,这个例子中的领导有可能会没有(最高领导就再没有领导了,所以就
方法领导的那边)
标准写法:select e.deptno,d.name from emp e,dept d where e.deptno(+)=d.depton and e.depton is null;
查看员工分部的部门:
select distinct(deptno) from emp ;
找出没有员工的部门:(很经典的一个例子,用外连接来解决的标准做法,这是一种方式)
第一步:
select e.deptno , d.deptno from emp e , dept d where e.deptno(+)=d.deptno;
第二步:
select e.deptno , d.deptno from emp e , dept d where e.deptno(+)=d.deptno and e.deptno is null;
组函数(group function):
group by 分组子句 对分组后的子句进行过滤还可以用having 条件 对分组后的条件进行过滤 where 是对记录进行过滤
avg(distinct | all )求平均值
count(distinct | all )统计
max(distinct | all ) 求最大值
min(distinct | all )求最小值
sum(distinct | all ) 求和
(所有组函数会忽略空值 , avg sum只能作用于数字类型)
求有提成员工的提成的平均值;
select avg(nvl(commission_pct ,0 ) ) from s_emp;
有多少人有提成:
select count( commission_pct ) from s_emp ;
count(*) 用于统计记录数:
select sum(commission_pct)/ count(*) from s_emp;
员工分部在多少个不同的部门:count 默认为作all的动作
select count(dept_id) from s_emp;
select count(distinct dept_id) from s_emp;
求各个部门的平均工资:group by 子句也会触发排序
select dept_id , avg(salary) aa from s_emp group by dept_id order by aa ;
select dept_id , avg(salary) aa from s_emp group by dept_id ;
注意:group by 子句后面跟有条件只能是查询的结果中的字段,所以我们会人为在结果要加入一些group by 要用的字段
select region_id , count(*) from s_dept 此句会有错
select max(region_id) , count(*) from s_dept; (强制语法上可以正确,但是不能保证结果也会正确)
求各个部门不同工种的平均工资:
select dept_id , title, avg(salary) from s_emp group by dept_id , title ;
哪些部门的平均工资比2000高:
select dept_id, avg(salary) aa from s_emp group by (dept_id) having avg(salary)>2000;
除了42部门以外的部门的平均工资:
select dept_id , avg(salary) from s_emp group by (dept_id ) having dept_id!=42;
select dept_id , avg(salary) from s_emp where dept_id!=42 group by (dept_id ) ;(此种sql效率要高,先过滤再计算)
where 单行函数。
having 组函数。
求各个部门的平均工资:
// 这样统计不详细
select max(d.name) , avg (s.salary) from s_emp s, s_dept d where s.dept_id=d.id group by d.name;
//****这问题很经典,为了过 oracle sql 语法关而写max(d.name) ***
select max(d.name) , avg(e.salary) , max(r.name) from s_emp e, s_dept d , s_region r where e.dept_id = d.id and d.region_id=r.id group by d.id ;
关于子查询: Subqueries
找出所有员工中,工资最低的那个员工:( 利用子查询 )
select first_name, salary from s_emp where salary = ( select min(salary) from s_emp) ;
//这样写会出错姓名和工资不一致
select max(first_name), min(salary) from s_emp;(利用子查询可以解决)
子查询运行的顺序:先运行子查询再运行主查询 子查询一般出现在运算符的右边
单值运算符:运算后面只能跟一个值
多值运算符:可以对两个以上的值进行操作
查询谁跟Smith干一样的活:
select last_name from s_emp where last_name='Smith';
//下种写法可能还存在bug,没有考虑到数据的全面性,有潜在性问题
select last_name , title from s_emp where title =( select title from s_emp where last_name='Smith' ) and last_name <> 'Smith' ;
//这种写法才考虑的比较全面
select last_name , title from s_emp where title in ( select title from s_emp where last_name='Smith' ) and last_name <> 'Smith' ;
使用子查询时应注意: 单行子查询返回多个结果时会有错误 single-row subquery returns more than one value
查出哪些员工的工资比平均工资低:
select * from s_emp where salary < ( select avg(salary) from s_emp) ;
哪些部门的平均工资比32部门的平均工资要低:
第一步先查出各个部门的平均工资:
select min(avg(salary ) ) from s_emp group by dept_id;
第二步再查出哪个部门的工资是最低的:
select dept_id, avg(salary) from s_emp group by dept_id having avg(salary) = (select min(avg(salary) ) from s_emp group by dept_id ) ;
哪个部门里没有员工:
select deptno from dept where deptno not in ( select deptno from emp );
哪些人是普通员工:(用子查询形式来做)
select * from s_emp where id not in ( select manager_id from s_emp);
E--R图 实体关系图entity relation
开发流程先进行需求分析,进行系统设计,建表,再进行开发编码,测试最终产品上线试运行。
把软件设计模型转化为数据中的表,设计时要考虑性能的设计
第一范式:最简单的一种建方式,一张表只有一个主键。
第二范式:表的自连接存在原因,一张表,学生表中也有班级的信息。
第三范式:表连接存在的原因,两张表,其中一张表引用其它一张表。