Oracle SQL笔记二

一、sqlplus命令在bin目录下
   有一个环境变量Oralce_sid,决定跟哪个数据库连
  
   严格做数据类型转换
   where子句中尽量不写表达式
  
  
select to_char(sysdate,'fmmm') from dual;   
   'fm'是去掉前导0
                             
二、多表查询

表连接(关联查寻)

    如果多表查询时不加where子句,也就是过滤条件或者是使用了无效的条件,就会产生两表之间记录的相互逐条匹配(组合),产生很多无效的结果(笛卡尔积)。

注意:在使用表连接时,要注意查询的表间的关系信息,表之间的字段所表示的信息的关系

1、等值连接

select [表别名1.字段名1],[表别名2.字段名2],...
from 表1 表别名1 ,表2 表别名2
where 表别名1.字段名3=表别名2.字段名4;
    表连接时,当表与表之间有同名字段时,可以加上表名或表的别名,加以区分,使用时要用
表名.字段名或表别名.字段名(列名)。当表的字段名是唯一时,可以不用加上表名或表的别名。

注意:当为表起了别名,就不能再使用表名.字段名。

例:select a.first_name,a.last_name,b.name
     from s_emp a,s_dept b
     where a.dept_id=b.id;

2、非等值连接

select [表别名1.字段名1],[表别名2.字段名2],...
from 表1 表别名1 ,表2 表别名2
where 表别名1.字段名3 ..... 表别名2.字段名4

....可以使比较运算符,也可以使其他的除了'='的运算符

例:select e.ename, d.grade,e.sal
     from emp e,salgrade d
     where e.sal between d.losal and d.hisal;

3、自连接

    用别名把一张表中的数据分成两部分,然后在使用条件过滤。
select [表别名1.字段名1],[表别名2.字段名2],...
from 表1 表别名1 ,表1 表别名2
where 表别名1.字段名3=表别名2.字段名4;

例:select a.first_name ename,b.first_name cname
     from s_emp a,s_emp b
     where a.manager_id=b.id;

    以上所提到的表连接,都叫做内连接,严格匹配两表的记录。

4、外连接

会使用一方表中的所有记录去和另一格表中的记录按条件匹配,空值也会匹配,这个表中的所有记录都会显示,数据库会模拟出记录去和那些不匹配的记录匹配。

例:select a.first_name enamei,a.id,b.first_name cname,b.id
     from s_emp a,s_emp b
     where a.manager_id=b.id(+);

     即用a表中的数据去匹配b表的,若b表中有null,系统模拟纪录与其匹配

注意:要把那一方的记录全部都显示出来,还有注意条件(+)跟在要全部选出的对端。              

外连接的应用:
列出哪个部门没有员工
select e.deptno,d.deptno
from emp e,dept d
where e.deptno(+)=d.deptno
and e.deptno is null;

三、组函数

group 组
group by 分组子句,按指定的分组规则分组 ,这个group by 子句可以跟在 select 语句后或是 having后面。
group by子句也会出发排序操作,会按分组字段排序。

select [组函数或分组的字段名] ,... from 表名 group by [字段名1],[字段名2],.....;

例:select avg(salary) from s_emp group by dept_id;

注意:组函数可以处理一组数据,返回一个值。
     组函数会忽略空值。

avg(..),求平均值,sum(..),求和 这两个函数的参数只能是number型的。

    以下所提到的函数可以使用任意类型做参数。
count(..),用来统计记录数,可以使用排重命令。count(...)默认使用的是all。
max(..),min(..)求最大值和最小值,
count(*),统计表中记录数。

例:select max(b.name),avg(a.salary), max(c.name)
   from s_emp a,s_dept b,s_region c
   where a.dept_id=b.id and b.region_id=c.id
   group by b.dept_id;

注意:只要写了group by子句,
     ***   select后就只能用group by后的字段或者是组函数。  ***
     where子句只能够过滤记录,放单行函数。

having子句可以过滤组函数结果或是分组的信息,且写在group by子句后。

例:
select max(b.name),avg(a.salary), max(c.name)
from s_emp a,s_dept b,s_region c
where a.dept_id=b.id and b.region_id=c.id
group by b.id
having sum(a.salary)>4000;

column 也可以定义有别名的列的格式。
column "别名" 格式定义

注意:要先过滤掉不需要的记录,然后再进行分组操作,提高效率。

四、子查询

    子查询,就是可以嵌在任何的sql语句中的select语句。

    在select语句中嵌套子查询时,会先执行子查询。一般的会将子查询放在运算符的右边。

    注意:在使用子查询时,要注意这个运算符是单行的(也就是只能是单值),还是多行运算符(范围,多值,in)。
    配合使用子查询返回的结果必须符合运算符的用法。

例:
select first_name,title
from s_emp
where title=any(select title from s_emp
               where last_name='Smith')
and upper(last_name)!='SMITH';

select first_name,title
from s_emp
where title in (select title from s_emp
               where last_name='Smith')
and upper(last_name)!='SMITH';

 

五、将业务需求转换成可操作的表

一: 需求分析
二: 画E-R图
三: 转换成表关系
四: 割接(新老系统交接)
五:

E-R图属性:
* 为强制且非空属性
o 可选属性(可以有值也可以没有)
#* 表示此属性唯一且非空 

实体关系:
mastbean maybean

数量关系:   多对一关系
   一对多关系
   一对一关系
   多对多关系

第一范式,所有的属性都必须是单值,也就是属性只表示单一的意义。(记录可以重复,没有任何限制)
第二范式,属性要求唯一且非空,(记录不可重复,但是数据可能会出现冗余)。
第三范式,非主属性只能依赖于主属性,不能依赖于其他非主属性。(解决数据冗余问题)

六、约束

    约束是针对表中的字段进行定义的。

primary key (主键约束 PK)保证实体的完整性,保证记录的唯一
    主键约束,唯一且非空,并且每一个表中只能有一个主键,有两个字段联合作为主键,只有两个字段放在一起唯一标识记录,叫做联合主键。

foreign key (外建约束 FK)保证引用的完整性,
    外键约束,外键的取值是受另外一张表中的主键或唯一值得约束,不能够取其他值,只能够引用主键会唯一键的值,被引用的表,叫做parent table(父表),引用方的表叫做child table(子表),要想创建子表,就要先创建父表,后创建子表,记录的插入也是如此,先父表后子表,删除记录,要先删除子表记录,后删除父表记录,要修改记录,如果要修改父表的记录要保证没有被子表引用。要删表时,要先删子表,后删除父表。

unuque key(唯一键),值为唯一

index(索引)是数据库特有的一类对象
view(视图)
典型的一对多 class 对应多个学生。
student table                      class table
______________________________     _________________________
| id | name | address| class_id|   | id |class_desc|class_num|
|(PK)|______|________|___(FK)__|   |(pk)|__________|_________|
|    |      |        |         |   |    |          |         |

一对一

student tabel             shenfenzheng table
____________________     _________________________________
| id | name | address|   |  s_id  |shenfen_desc|shenfen_num|
|(PK)|______|________|   |(PK,FK)|____________|___________|
|    |      |        |   |        |            |           |

多对多

student tabel             zhongjian table                      kecheng table
____________________     _________________________________    __________________
| id | name | address|   |  s_id  |shenfen_desc|shenfen_num|  | kid | kechengname|
|(PK)|______|________|   |(FK,FK)|____________|___________|  | (PK)|____________|
|    |      |        |   |联合主键|            |           |  |     |            |

引用对方表的主键,当作本身的主键,所以这个表的主键,既是主键又是外建

建表和其他相关操作

DDL语句

创建表:
  create    table  表名   (    字段名1    类型(数据长度)(default ...)   约束条件,   字段名2    类型(数据长度)    约束条件 );

Oracle数据库中的数据类型

varchar(长度),可变长字符串,char(长度) 定长
number(..,..),number 表示浮点数,或者是整数
long 大对象,clog 字符的大对象,相当于文本文件在表中只存放一个相当于只针对值
            blog 二进制的大对象,也是以相当于指针的形式存放的。
primary key约束:
主键约束的定义:
第一种定义形式:
create table  test(c  number  primary key  );     列级约束
第二种定义形式:
create table  test(c  number , primary key(c) )  ; 表级约束
create table  test( c1  number  constraints   pkc1  primary key );   此约束有名字:  pkc1
create table  test(c number , c2  number ,  primary key (c ,c1) )  ; 用表级约束可以实现联合主键

foregin  key   (fk)   外键约束:
(先定义父表,再定义子表)
carete   table    parent(c1 number  primary key );
create   table    child  (c  number primary key ,   c2 number  references parent(c1));

或表级约束定义:
create   table  child( c number primary key ,  c2  number  , foreign key(c2)  references  parent(c1));

如果两个字段都为唯一且非空,这时可以定义成UK+NOT NULL

(PK或UK)一对多(FK)
(PK+UK)一对一(FK)      或   (PK)一对一(PK)
多对对多关系,一般都通过一张中间表来分解成两个一对多的表

建立表
create table[schema]table
schema: 一个用户对应一个schema       不同用户下的表不能互相查看

select count(*) from s_dept;     <===>     select count(*) from sd0611.s_dept;

一个表中只能存储一个LONG类型
CLOB 存储大的文本对象
BLOB 存储大的二进制对象

create table test(c1 number primary key);   设置主键
create table test(c1 number constraints test_c1 primary key);   定义约束名,默认约束名为SYS_      在列后面定义约束称为列级约束
create table test(c1 number primary key(c1));   所有列定义完后再定义约束称为表级约束(能定义联合主键)
cretae table test(c1 number,c2 number,priary key(c1,c2));    定义联合主键
create table child(c1 number primary key);    先要定义父表
create table child(c1 number primary key, c2 number references parent(c1));   然后定义子表  references parent定义外键
create table child(c1 number primary key, c2 number references parent(c1) on delete cascate);  on delete cascate为级联删除
create table child(c1 number primary key, c2 number references parent(c1) on delete set null);   on delete set null删除后将外键置空
create table child (c1 number primary key, c2 number,foreignkey(c2) references parent(c1));

 

课堂练习

两表没有任何关联时会产生迪卡尔机:
select   first_name , name  from    s_emp , s_dept;

等值连接:
练习一:查看员工的姓名和员工部门号要考虑到表中实际数据中空值的影响)
select   first_name ,   name from  s_emp, s_dept   where s_emp.dept_id=s_dept.id;

练习二:每个员工所在的部门和部门所在的地区
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;

非等值连接:
练习三:查出每个员工和每个员工的工资级别
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  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;
练习六:查询员工有多少人有提成:
select  count( commission_pct ) from    s_emp ;
select   sum(commission_pct) count(*)   from     s_emp;

练习七:员工分部在多少个不同的部门:
select   count(dept_id)  from s_emp;
select   count(distinct dept_id) from   s_emp;

练习八:求各个部门的平均工资:
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    ;

//体会下句sql
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效率要高,先过滤再计算)
练习十二:求各个部门的平均工资:
//****这问题很经典,为了过 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 );


如果给你带来帮助,欢迎微信或支付宝扫一扫,赞一下。