【sql】编写基本的SQL SELECT语句四

多表查询及创建对象训练手册

  第1章  多表查询

1.1.  等连接

    通过两个表具有相同意义的列,建立连接条件。查询结果只显示两个列中的值是等值条件的行数据。表中同名列被选择时必须添加表名前缀进行修饰 否则无法确定这一列是属于哪个表

HR@ENMOEDU> conn hr/hr

Connected.

HR@ENMOEDU>SELECT count(*)

  FROM departments d, employees t

  WHERE d.department_id = t.department_id;

 

  COUNT(*)

----------

 106

 

HR@ENMOEDU> --注:下面sql语句中 INNER 是可以省略不写的。

HR@ENMOEDU>SELECT COUNT(*)

  FROM departments d

 INNER JOIN employees t

 ON d.department_id = t.department_id;

 

  COUNT(*)

----------

 106

 

HR@ENMOEDU>SELECT COUNT(*)

  FROM departments d

  JOIN employees t

    USING (department_id);

 

COUNT(*)

----------

106

 

HR@ENMOEDU>

 

表名前缀(因为两张表都存在字段department_id,故报此错误)

HR@ENMOEDU>select department_id, employee_id, first_name, department_name

  from employees d, departments t

    where d.department_id = t.department_id;

select department_id, employee_id, first_name, department_name

       *

ERROR at line 1:

ORA-00918: column ambiguously defined

 

HR@ENMOEDU>select d.department_id, employee_id, first_name, department_name

  from employees d, departments t

 where d.department_id = t.department_id;

 

DEPARTMENT_ID EMPLOYEE_ID FIRST_NAME           DEPARTMENT_NAME

----------------------- -------------------- ------------------------------

           10         200 Jennifer             Administration

           20         201 Michael              Marketing

           20         202 Pat                  Marketing

           30         114 Den                  Purchasing

           30         115 Alexander            Purchasing

           30         116 Shelli               Purchasing

           30         117 Sigal                Purchasing

           30         118 Guy                  Purchasing

           30         119 Karen                Purchasing

           40         203 Susan                Human Resources

           50         120 Matthew              Shipping

 

HR@ENMOEDU>

问:下面两个sql的结果是否相同?为什么?相同,and是并行满足,而where是过滤只要满足这一个条件。

SQL1:

SELECT *

FROM departments d

JOIN employees t

ON d.department_id= t.department_id

AND d.department_name = 'SALES';

 

SQL2:

SELECT *

FROM departments d

JOIN employees t

ON d.department_id = t.department_id

WHERE d.department_name = 'SALES';

1.2.  自然连接

    自然连接只发生在两个表中有相同名字和数据类型的列上,如果单纯的列名相同而类型不同,那么会报语法错误。

HR@ENMOEDU>desc departments

Name                                      Null?    Type

 ------------------------------ -------- ----------------------------

 DEPARTMENT_ID                             NOT NULL NUMBER(4)

 DEPARTMENT_NAME                           NOT NULL VARCHAR2(30)

 MANAGER_ID                                         NUMBER(6)

 LOCATION_ID                                        NUMBER(4)

 

HR@ENMOEDU>desc employees

Name                                      Null?    Type

 --------------------------------- -------- ----------------------------

 EMPLOYEE_ID                                       NOT NULL NUMBER(6)

 FIRST_NAME                                         VARCHAR2(20)

 LAST_NAME                                 NOT NULL VARCHAR2(25)

 EMAIL                                     NOT NULL VARCHAR2(25)

 PHONE_NUMBER                                       VARCHAR2(20)

 HIRE_DATE                                 NOT NULL DATE

 JOB_ID                                    NOT NULL VARCHAR2(10)

 SALARY                                             NUMBER(8,2)

 COMMISSION_PCT                                     NUMBER(2,2)

 MANAGER_ID                                         NUMBER(6)

 DEPARTMENT_ID                                      NUMBER(4)

 

HR@ENMOEDU> SELECT d.department_name, d.location_id, t.first_name

   FROM departments d NATURAL JOIN employees t;

 

DEPARTMENT_NAME                LOCATION_ID FIRST_NAME

------------------------------ ----------- --------------------

Executive                             1700 Neena

Executive                             1700 Lex

IT                                    1400 Bruce

IT                                    1400 David

IT                                    1400 Valli

IT                                    1400 Diana

Finance                               1700 Daniel

Finance                               1700 John

Finance                               1700 Ismael

Finance                               1700 Jose Manuel

Finance                               1700 Luis

Purchasing                            1700 Alexander

Purchasing                            1700 Shelli

Purchasing                            1700 Sigal

Purchasing                            1700 Guy

Purchasing                            1700 Karen

Shipping                              1500 Laura

Shipping                              1500 Mozhe

 

HR@ENMOEDU>

1.3.  using子句

1)   using子句的用法:

HR@ENMOEDU>select d.department_name,d.location_id,t.first_name

   from departments d join employees t using (department_id);

 

DEPARTMENT_NAME                LOCATION_ID FIRST_NAME

------------------------------ ----------- --------------------

Administration                        1700 Jennifer

Marketing                             1800 Pat

Marketing                             1800 Michael

Purchasing                            1700 Sigal

Purchasing                            1700 Karen

Purchasing                            1700 Shelli

Purchasing                            1700 Den

Purchasing                            1700 Alexander

Purchasing                            1700 Guy

Human Resources                       2400 Susan

Shipping                              1500 Kevin

Shipping                              1500 Jean

Shipping                              1500 Adam

Shipping                              1500 Timothy

Shipping                              1500 Ki

Shipping                              1500 Girard

 

HR@ENMOEDU>

2)   using子句的注意事项

HR@ENMOEDU> select d.department_name,d.location_id,t.first_name

    from departments d join employees t

  using (department_id)

   where department_id=10;

 

DEPARTMENT_NAME                LOCATION_ID FIRST_NAME

------------------------------ ----------- --------------------

Administration                        1700 Jennifer

 

HR@ENMOEDU>select d.department_name,d.location_id,t.first_name

from departments d join employees t

  using (department_id) where d.department_id=10;

 

using (department_id) where d.department_id=10

                            *

ERROR at line 3:

ORA-25154: column part of USING clause cannot have qualifier

 

HR@ENMOEDU>

    通过面的例子可以得出,using子句中,相同名字的字段不允许有任何限定符,否则将报ORA-25154:错误,此限制同样适用于natural join(自然连接)

1.4.  不等连接

    A表中的某列数据和B表中一列或多列的关系是非等值关系,大于,小于,不等于,等条件都属于不等连接的范畴

    就是排除完全相等条件以外的 >,<,!=, <=, >=, between and主要在于不同表之间显示特定范围的信息(也可以理解成包含关系)

HR@ENMOEDU>create table job_grades (s_grade varchar2(2),low_salary number,high_salary number);

insert into job_grades (s_grade, low_salary, high_salary) values ('A', 0, 10000);

insert into job_grades (s_grade, low_salary, high_salary) values ('B', 10001, 20000);

insert into job_grades (s_grade, low_salary, high_salary) values ('C', 20001, 30000);

HR@ENMOEDU> commit;

Commit complete.

 

HR@ENMOEDU>select first_name,salary,s_grade

 from employees a,job_grades b

 where salary between low_salary and high_salary and b.s_grade='B';

 

FIRST_NAME               SALARY S_

-------------------- ---------- --

Neena                     17000 B

Lex                       17000 B

Nancy                     12008 B

Den                       11000 B

John                      14000 B

 

HR@ENMOEDU>

between A and B (大于等于A并且小于等于B)

HR@ENMOEDU> with t as (

select rownum id from dual connect by rownum<=10)

select id from t where id between 2 and 8;

 

        ID

---------

         2

         3

         4

         5

         6

         7

         8

 

7 rows selected.

 

HR@ENMOEDU>

1.5.  自连接

    数据都来自一张表,所以在from句中需要对表添加别名,添加表别名后才能合法化的引用表中的列名本质就是将一张表虚拟成了两张表

HR@ENMOEDU>SELECT d.last_name || ' works for ' || t.last_name

FROM   employees d, employees t

WHERE  d.manager_id = t.employee_id;

 

D.LAST_NAME||'WORKSFOR'||T.LAST_NAME

-------------------------------------------------------------

Smith works for Cambrault

Ozer works for Cambrault

Kumar works for Cambrault

……

中间省略n

……

Hutton works for Zlotkey

Grant works for Zlotkey

Abel works for Zlotkey

 

106 rows selected.

 

HR@ENMOEDU>

1.6.  外连接

    选择出满足等连接条件的及其以外的记录。(+)修饰符号用法:置在选出结果只包含等连接的列后,另一列的结果就是等值行+非等值行

1.6.1.  左外连接

在等连接的基础上,还包含左表中所有不符合条件的数据行,并在其中的右表列填写NULL

1)   Oracle自己的写法(不推荐):

HR@ENMOEDU>col id for 99

HR@ENMOEDU>col name for a4

HR@ENMOEDU> with

t1 as (

select 1 as id,'a' as name from dual union all

select 2,'b' from dual union all

select 3,'c' from dual),

t2 as (

select 2 as id,'bb' as name from dual union all

select 3,'cc' from dual union all

select 4,'dd' from dual)

select t1.id,t1.name,t2.id,t2.name from t1,t2 where t1.id=t2.id(+);

 

ID NAME        ID NAME

----- -------- ----- --------

2 b            2 bb

 3 c            3 cc

1 a

HR@ENMOEDU>

2)   SQL99写法

 

HR@ENMOEDU> with

t1 as (

select 1 as id,'a' as name from dual union all

select 2,'b' from dual union all

select 3,'c' from dual),

t2 as (

select 2 as id,'bb' as name from dual union all

select 3,'cc' from dual union all

select 4,'dd' from dual)

select t1.id,t1.name,t2.id,t2.name from t1 left outer join t2 on t1.id=t2.id;

 

ID NAME        ID NAME

----- -------- ----- --------

2 b            2 bb

 3 c            3 cc

1 a

 

HR@ENMOEDU>

注:outer 可以省略

问:下面的sql结果是否相同,思考为什么?不一样,and是同时满足,而where是只满足。

SQL1

with

t1 as (

select 1 as id,'a' as name from dual union all

select 2,'b' from dual union all

select 3,'c' from dual),

t2 as (

select 2 as id,'bb' as name from dual union all

select 3,'cc' from dual union all

select 4,'dd' from dual)

select t1.id,t1.name,t2.id,t2.name from t1 left join t2 on t1.id=t2.id and t2.id=2;

SQL2

with

t1 as (

select 1 as id,'a' as name from dual union all

select 2,'b' from dual union all

select 3,'c' from dual),

t2 as (

select 2 as id,'bb' as name from dual union all

select 3,'cc' from dual union all

select 4,'dd' from dual)

select t1.id,t1.name,t2.id,t2.name from t1 left join t2 on t1.id=t2.id where t2.id=2;

1.6.2.  右外连接

在等连接的基础上,还包含右表中所有不符合条件的数据行,并在其中的左表列填写NULL

1)   Oracle自己的写法(不推荐):

HR@ENMOEDU> with

t1 as (

select 1 as id,'a' as name from dual union all

select 2,'b' from dual union all

select 3,'c' from dual),

t2 as (

select 2 as id,'bb' as name from dual union all

select 3,'cc' from dual union all

select 4,'dd' from dual)

select t1.id,t1.name,t2.id,t2.name from t1,t2 where t1.id(+)=t2.id;

 

ID NAME        ID NAME

----- -------- ----- --------

2 b           2 bb

 3 c            3 cc

 4 dd

 

HR@ENMOEDU>

2)   SQL99写法

HR@ENMOEDU> with

t1 as (

select 1 as id,'a' as name from dual union all

select 2,'b' from dual union all

select 3,'c' from dual),

t2 as (

select 2 as id,'bb' as name from dual union all

select 3,'cc' from dual union all

select 4,'dd' from dual)

select t1.id,t1.name,t2.id,t2.name from t1 right outer join t2 on t1.id=t2.id;

 

ID NAME        ID NAME

----- -------- ----- --------

2 b           2 bb

 3 c            3 cc

 4 dd

 

HR@ENMOEDU>

1.6.3.  全外连接

在等连接的基础上,还包含两个表中所有不符合条件的数据行,并在其中的左表、和右表列填写NULL 

HR@ENMOEDU>col n1 for a5

HR@ENMOEDU>col n2 for a5

HR@ENMOEDU>with

t1 as (

select 1 as id,'a' as name from dual union all

select 2,'b' from dual union all

select 3,'c' from dual),

t2 as (

select 2 as id,'bb' as name from dual union all

select 3,'cc' from dual union all

select 4,'dd' from dual)

select nvl(t1.id,t2.id) as id ,t1.name as n1, t2.name as n2

from t1 full join t2 on t1.id=t2.id order by 1 asc;

 

ID N1    N2

----- ----- -----

1 a

2 b     bb

3 c     cc

4       dd

 

HR@ENMOEDU>

1.7.  交叉连接(笛卡尔

将两个表的所有行进行组合,连接后的行数为两个表的乘积数。

往往有人会说要避免笛卡尔积,上学的时候,老师也把它说的很恐怖,其实则不然,我倒是认为如若弄明白它的原理,则可合理利用它。

1)   写法一:

HR@ENMOEDU> WITH t1 AS (SELECT 'range' AS r FROM dual

            UNION ALL SELECT 'list' FROM dual),

     t2 AS (SELECT 'range' AS l FROM dual

            UNION ALL SELECT 'list' FROM dual),

     t3 AS (SELECT 'hash' AS h from dual)

SELECT r,l FROM t1 CROSS JOIN t2

UNION ALL

SELECT l,h FROM t2 CROSS JOIN t3;

 

R     L

----- -----

range range

range list

list  range

list  list

range hash

list  hash

 

6 rows selected.

 

HR@ENMOEDU>

2)   写法二:

HR@ENMOEDU> WITH t1 AS (SELECT 'range' AS r FROM dual

            UNION ALL SELECT 'list' FROM dual),

     t2 AS (SELECT 'range' AS l FROM dual

            UNION ALL SELECT 'list' FROM dual),

     t3 AS (SELECT 'hash' AS h from dual)

SELECT r,l FROM t1,t2

UNION ALL

SELECT l,h FROM t2,t3;

 

R     L

----- -----

range range

range list

list  range

list  list

range hash

list  hash

 

6 rows selected.

 

HR@ENMOEDU>


  第2章  创建和管理表

语法:

CREATE TABLE [schema.]table

        (columndatatype [DEFAULT expr][, ...]);

2.1.  创建表

HR@ENMOEDU>CREATE TABLE dept2

(department_id   NUMBER(2),

 dname   VARCHAR2(14),

 loc   VARCHAR2(13));

 

Table created.

 

HR@ENMOEDU>

2.2.  日期数据类型

TIMESTAMP       带小数秒的日期型

INTERVAL YEAR TO MONTH  作为年和月的时间间隔存储

INTERVAL DAY TO SECOND 作为天、小时、分和秒的时间间隔存储(DAY, HOUR, MINUTE, SECOND

HR@ENMOEDU>create table ha (id number,x INTERVAL YEAR TO MONTH,y INTERVAL DAY TO SECOND );

 

Table created.

 

HR@ENMOEDU>

--x字段插入:5

--y字段插入:2

HR@ENMOEDU>insert into ha values(1,INTERVAL '5' year,INTERVAL '2' day);

 

1 row created.

 

HR@ENMOEDU>

 

--x字段插入:10个月

--y字段插入:2小时

HR@ENMOEDU>insert into ha values(2,INTERVAL '10' month,INTERVAL '2' hour);

 

1 row created.

 

HR@ENMOEDU>

--x字段插入:2年零6个月

--y字段插入:1天零12小时30分钟1

HR@ENMOEDU>insert into ha values(3,INTERVAL '2-6' YEAR TO MONTH,INTERVAL '1 12:30:01' DAY TO SECOND);

                                           

1 row created.

 

HR@ENMOEDU>commit;

 

Commit complete.

 

HR@ENMOEDU>

--利用系统时间加上xy字段来验证这两个数据类型

HR@ENMOEDU>select id,sysdate,sysdate+x,sysdate+y from ha;

 

 ID SYSDATE             SYSDATE+X           SYSDATE+Y

--- ------------------- ------------------- -------------------

  1 2012-09-09 13:19:32 2017-09-09 13:19:32 2012-09-11 13:19:32

  2 2012-09-09 13:19:32 2013-07-09 13:19:32 2012-09-09 15:19:32

  3 2012-09-09 13:19:32 2015-03-09 13:19:32 2012-09-11 01:49:33

 

HR@ENMOEDU>

2.3.  用子查询语法创建表

HR@ENMOEDU>create table dept3 as select * from departments;

 

Table created.

 

HR@ENMOEDU>

HR@ENMOEDU>select count(*) from dept3;

 

  COUNT(*)

----------

27

 

HR@ENMOEDU>desc dept3;

Name                                      Null?    Type

 --------------------------------- -------- ----------------------------

 DEPARTMENT_ID                                      NUMBER(4)

 DEPARTMENT_NAME                           NOT NULL VARCHAR2(30)

 MANAGER_ID                                         NUMBER(6)

 LOCATION_ID                                        NUMBER(4)

HR@ENMOEDU>

2.4.  修改表

1)   增加字段

HR@ENMOEDU>alter table dept3 add (job_id number(5));

 

Table altered.

 

HR@ENMOEDU>desc dept3;

Name                                      Null?    Type

 ------------------------------ -------- ----------------------------

 DEPARTMENT_ID                                      NUMBER(4)

 DEPARTMENT_NAME                           NOT NULL VARCHAR2(30)

 MANAGER_ID                                         NUMBER(6)

 LOCATION_ID                                        NUMBER(4)

 JOB_ID                                             NUMBER(5)

HR@ENMOEDU>

2)   修改字段大小

HR@ENMOEDU>alter table dept3 modify (job_id number(10));

 

Table altered.

 

HR@ENMOEDU>desc dept3;

Name                                      Null?    Type

 --------------------------------- -------- ----------------------------

 DEPARTMENT_ID                                      NUMBER(4)

 DEPARTMENT_NAME                           NOT NULL VARCHAR2(30)

 MANAGER_ID                                         NUMBER(6)

 LOCATION_ID                                        NUMBER(4)

 JOB_ID                                             NUMBER(10)

HR@ENMOEDU>

3)   删除字段

HR@ENMOEDU>alter table dept3 drop column job_id;

 

Table altered.

 

HR@ENMOEDU>desc dept3;

Name                                      Null?    Type

 --------------------------------- -------- ----------------------------

 DEPARTMENT_ID                                      NUMBER(4)

 DEPARTMENT_NAME                           NOT NULL VARCHAR2(30)

 MANAGER_ID                                         NUMBER(6)

 LOCATION_ID                                        NUMBER(4)

HR@ENMOEDU>

2.5.  字段UNUSED

UNUSED 选项标记一个或多个未使用的列

特别注意:unused是不可逆的。

    那么为什么还要这么做呢,主要还是因为,这个动作是对数据字典进行了删除,性能非常的好,对数据库没什么压力。如果数据库压力很大,同时又不想要某个字段了,那么就可以用这种方式,等压力小了,再做清除的处理

1)   创建测试表test(两个字段xy并插入一条记录

HR@ENMOEDU>create table test(x number(1),y number(2));

 

Table created.

 

HR@ENMOEDU>insert into test values(1,2);

 

1 row created.

 

HR@ENMOEDU>commit;

 

 

Commit complete.

 

HR@ENMOEDU>

2)   将字段y设置为unused

HR@ENMOEDU> alter table test set unused (y);

 

Table altered.

 

HR@ENMOEDU>

3)   查看表,y字段已经消失

HR@ENMOEDU>select * from test;

 

X

----------

1

 

HR@ENMOEDU>

4)   查看字典表中,表设置为unused字段个数,由于unused是不可逆的,所以,此处只显示字段个数,不显示具体的字段

 desc user_unused_col_tabs

 Name                                      Null?    Type

 ----------------------------------------- -------- ----------------------------

 TABLE_NAME                                NOT NULL VARCHAR2(30)

 COUNT                                              NUMBER

HR@ENMOEDU> select * from user_unused_col_tabs;

 

TABLE_NAME                          COUNT

------------------------------ ----------

TEST                                    1

 

HR@ENMOEDU>

5)   我们可以加入一个字段yvarchar2类型),查看testy字段创建成功

HR@ENMOEDU>alter table test add(y varchar2(10));

 

Table altered.

 

HR@ENMOEDU>select * from test;

 

 X Y

---------- ----------

1

 

HR@ENMOEDU>

6)   删除设置为unused的字段

HR@ENMOEDU>alter table test drop unused COLUMNS;

 

Table altered.

 

HR@ORA11GR2>select * from user_unused_col_tabs;

 

no rows selected

2.6.  删除表

HR@ENMOEDU>drop table test;

 

Table dropped.

 

HR@ENMOEDU>

注:此种方式删除后,是进入回收站的,如果不进入回收站直接删除的话,那么在删除的时候加上purge子句,详见《闪回》章节。

2.7.  改变对象的名字

1)   查看当前用户下所有表对象

HR@ENMOEDU>select tname from tab where tabtype='TABLE';

 

TNAME

------------------------------

EMPLOYEES

DEPARTMENTS

DEPT2

......

 

HR@ENMOEDU>

2)   重命名DEPT2DEPT5

HR@ENMOEDU>rename DEPT2 to DEPT5;

 

Table renamed.

 

3)   再次查看DEPT2已经不见了,已经重命名为DEPT5

HR@ENMOEDU>select tname from tab where tabtype='TABLE';

 

TNAME

------------------------------

EMPLOYEES

DEPARTMENTS

DEPT5

......

 

HR@ENMOEDU>

2.8.  截断表

?   TRUNCATE  TABLE 语句

-     删除表中所有的行

-     释放该表所使用的存储空间,降低高水位

?   DDL操作,不能回退用 TRUNCATE 删除的行

?   如果想删除某几行,那么可以用 DELETE 语句删除行

 

1)   创建测试表,并查看分配的区

HR@ENMOEDU>create table tt_tab as select * from all_objects;

 

Table created.

 

HR@ENMOEDU>col SEGMENT_NAME for a12

HR@ENMOEDU>col SEGMENT_TYPE for a12

HR@ENMOEDU>col TABLESPACE_NAME for a15

HR@ENMOEDU>col EXTENT_ID for 999999999

HR@ENMOEDU>col BLOCKS for 999999

HR@ENMOEDU>set pagesize 300

HR@ENMOEDU>

select segment_name,segment_type,tablespace_name,extent_id,bytes/1024 as "size(k)",blocks from user_extents where segment_name=upper('tt_tab');

 

SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME  EXTENT_ID    size(k)  BLOCKS

------------ ------------ --------------- ---------- ---------- -------

TT_TAB        TABLE          USERS                        0           64        8

TT_TAB        TABLE          USERS                        1           64        8

TT_TAB        TABLE          USERS                        2           64        8

TT_TAB        TABLE          USERS                        3           64        8

TT_TAB        TABLE          USERS                        4           64        8

TT_TAB        TABLE          USERS                        5           64        8

TT_TAB        TABLE          USERS                        6           64        8

TT_TAB        TABLE          USERS                        7           64        8

TT_TAB        TABLE          USERS                        8           64        8

TT_TAB        TABLE          USERS                        9           64        8

TT_TAB        TABLE          USERS                       10           64        8

TT_TAB        TABLE          USERS                       11           64        8

TT_TAB        TABLE          USERS                       12           64        8

TT_TAB        TABLE          USERS                       13           64        8

TT_TAB        TABLE          USERS                       14           64        8

TT_TAB        TABLE          USERS                       15           64        8

TT_TAB        TABLE          USERS                       16         1024      128

TT_TAB        TABLE          USERS                       17         1024      128

TT_TAB        TABLE          USERS                       18         1024      128

TT_TAB        TABLE          USERS                       19         1024      128

TT_TAB        TABLE          USERS                       20         1024      128

TT_TAB        TABLE          USERS                       21         1024      128

 

22 rows selected.

 

HR@ENMOEDU>

2)   DDLtruncate)操作后,不能回退用 TRUNCATE 删除的行,因为是DDL操作,无需要显示提交,当然,回滚也无济于事。

HR@ENMOEDU>truncate table tt_tab;

 

Table truncated.

 

HR@ENMOEDU>select count(*) from tt_tab;

 

  COUNT(*)

----------

 

         0

 

HR@ENMOEDU>

--验证DDL语句无法rollback

HR@ENMOEDU>rollback;

 

Rollback complete.

 

HR@ENMOEDU>select count(*) from tt_tab;

 

  COUNT(*)

----------

         0

 

HR@ENMOEDU>

3)   降低高水位,我们发现分配的区已经全部收回

HR@ENMOEDU>select segment_name,segment_type,tablespace_name,extent_id,bytes/1024 as "size(k)",blocks from user_extents where segment_name=upper('tt_tab');

 

SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME  EXTENT_ID    size(k)  BLOCKS

------------ ------------ --------------- ---------- ---------- -------

TT_TAB       TABLE        USERS                    0         64       8

 

HR@ENMOEDU>

自测题:

请大家按照以上的方法自行验证用delete方式清空表后delete from tablename,区的分配情况。


 

 

  第3章  内置约束

3.1.  NOT NULL

注:not null约束只能在列级定义。

HR@ENMOEDU>create table t_notnull

(x number not null,

y number constraint nn_tnotnull_y not null

);

 

Table created.

 

HR@ENMOEDU>select constraint_name,constraint_type,search_condition

from user_constraints

where table_name=upper('t_notnull');

 

CONSTRAINT_NAME CONSTRAINT_TYPE SEARCH_CONDITION

--------------- --------------- -------------------------

SYS_C0011054    C               "X" IS NOT NULL

NN_TNOTNULL_Y   C               "Y" IS NOT NULL

 

3.2.  UNIQUE

唯一键约束

HR@ENMOEDU>create table student1

(sno number(5) not null,

sname varchar2(20) not null constraint uk_student_sname1 unique,

idcard varchar2(18),

createtime date default sysdate not null,

constraint uk_student_idcard1 unique(idcard)

);

Table created.

 

HR@ENMOEDU>

HR@ENMOEDU>create table student2

(sno number(5) not null,

sname varchar2(20) not null unique,

idcard varchar2(18),

createtime date default sysdate not null,

constraint uk_student_idcard2 unique(idcard)

);

 

Table created.

 

HR@ENMOEDU>create table student3

(sno number(5) not null,

sname varchar2(20) not null unique,

idcard varchar2(18),

createtime date default sysdate not null,

unique(idcard)

);

 

Table created.

 

HR@ENMOEDU>col table_name for a12

HR@ENMOEDU>col column_name for a15

HR@ENMOEDU>col constraint_name for a20

HR@ENMOEDU>select table_name,column_name,constraint_name from user_cons_columns where table_name like upper('student_');

 

TABLE_NAME   COLUMN_NAME     CONSTRAINT_NAME

------------ --------------- --------------------

STUDENT3      IDCARD            SYS_C0011070

STUDENT3      SNAME             SYS_C0011069

STUDENT3      CREATETIME        SYS_C0011068

STUDENT3      SNAME             SYS_C0011067

STUDENT3      SNO               SYS_C0011066

STUDENT2      IDCARD            UK_STUDENT_IDCARD2

STUDENT2      SNAME             SYS_C0011064

STUDENT2      CREATETIME        SYS_C0011063

STUDENT2      SNAME             SYS_C0011062

STUDENT2      SNO               SYS_C0011061

STUDENT1      IDCARD            UK_STUDENT_IDCARD1

STUDENT1      SNAME             UK_STUDENT_SNAME1

STUDENT1      CREATETIME        SYS_C0011058

STUDENT1      SNAME             SYS_C0011057

STUDENT1      SNO               SYS_C0011056

 

15 rows selected.

 

HR@ENMOEDU>

3.3.  PRIMARY KEY

主键约束

1)   行级定义主键,系统分配主键名称

HR@ENMOEDU>CREATE TABLE t_pk1

(

sno NUMBER(5) primary key,

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE

);

 

Table created.

 

HR@ENMOEDU>

2)   表级定义主键,自定义主键名称

HR@ENMOEDU>CREATE TABLE t_pk2

(

sno NUMBER(5),

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE,

constraint pk_t_pk2_sno primary key(sno)

);

 

Table created.

 

HR@ENMOEDU>

3)   表级定义主键,系统分配主键名称

HR@ENMOEDU>CREATE TABLE t_pk3

(

sno NUMBER(5),

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE,

primary key(sno)

);

 

Table created.

 

HR@ENMOEDU>

4)   行级定义主键,自定义主键名称,并且指定索引使用的表空间

HR@ENMOEDU>CREATE TABLE t_pk4

(

sno NUMBER(5) constraint pk_t_pk4_sno primary KEY using index tablespace example,

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE

);

 

Table created.

 

HR@ENMOEDU>

5)   表级定义主键,自定义主键名称,并且指定索引使用的表空间

HR@ENMOEDU>CREATE TABLE t_pk5

(

sno NUMBER(5),

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE,

constraint pk_t_pk5_sno primary key(sno) using index tablespace example

);

 

Table created.

 

HR@ENMOEDU>

6)   查看刚刚建表的主键情况

HR@ENMOEDU>select table_name,column_name,constraint_name from user_cons_columns where table_name like upper('t_pk_');

 

TABLE_NAME  COLUMN_NAME    CONSTRAINT_NAME

---------- -------------- --------------------

T_PK1        SNO             SYS_C0011132

T_PK2        SNO             PK_T_PK2_SNO

T_PK3        SNO             SYS_C0011134

T_PK4        SNO             PK_T_PK4_SNO

T_PK5        SNO             PK_T_PK5_SNO

 

HR@ENMOEDU>

7)   查看主键自动创建索引情况

HR@ENMOEDU>select index_name,uniqueness,tablespace_name from user_indexes where table_name like upper('t_pk_');

 

INDEX_NAME                     UNIQUENES TABLESPACE_NAME

-------------------------- --------- ------------------------------

SYS_C0011132                   UNIQUE    USERS

PK_T_PK2_SNO                   UNIQUE    USERS

SYS_C0011134                   UNIQUE    USERS

PK_T_PK4_SNO                   UNIQUE    EXAMPLE

PK_T_PK5_SNO                   UNIQUE    EXAMPLE

 

HR@ENMOEDU>

8)   清理环境

HR@ENMOEDU>

drop table t_pk1 purge;

drop table t_pk2 purge;

drop table t_pk3 purge;

drop table t_pk4 purge;

drop table t_pk5 purge;

Table dropped.

Table dropped.

Table dropped.

Table dropped.

Table dropped.

 

HR@ENMOEDU>

9)   创建测试表t_pk6命令行增加主键,自定义主键名称

HR@ENMOEDU>CREATE TABLE t_pk6

(

sno NUMBER(5),

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE

);

 

Table created.

 

HR@ENMOEDU>alter table t_pk6 add constraint pk_t_pk6_sno primary key (sno);

 

Table altered.

 

HR@ENMOEDU>

10)  创建测试表t_pk7命令行增加主键,自定义主键名称,并且指定自动创建索引的表空间

HR@ENMOEDU>CREATE TABLE t_pk7

(

sno NUMBER(5),

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE

);

 

Table created.

 

 

HR@ENMOEDU>

HR@ENMOEDU>

HR@ENMOEDU>alter table t_pk7 add constraint pk_t_pk7_sno primary key (sno)using index tablespace example;

 

Table altered.

 

HR@ENMOEDU>

11)  创建测试表t_pk8命令行增加主键,自定义主键名称,并且指定创建索引的名称、类型及表空间

HR@ENMOEDU>CREATE TABLE t_pk8

(

sno NUMBER(5),

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE

);

 

Table created.

 

HR@ENMOEDU>

HR@ENMOEDU>alter table t_pk8 add constraint pk_t_pk8_sno primary key (sno) using index (create unique index un_t_pk8_sno on t_pk8(sno) tablespace example);

 

Table altered.

 

HR@ENMOEDU>

12)  创建测试表t_pk6t_pk7t_pk8,主键情况

HR@ENMOEDU>select table_name,column_name,constraint_name from user_cons_columns where table_name like upper('t_pk_');

 

TABLE_NAME  COLUMN_NAME   CONSTRAINT_NAME

----------- ------------ --------------------

T_PK6        SNO             PK_T_PK6_SNO

T_PK7        SNO             PK_T_PK7_SNO

T_PK8        SNO             PK_T_PK8_SNO

 

HR@ENMOEDU>

13)  创建测试表t_pk6t_pk7t_pk8索引情况

HR@ENMOEDU>select index_name,uniqueness,tablespace_name from user_indexes where table_name like upper('t_pk_');

 

INDEX_NAME      UNIQUENES TABLESPACE_NAME

-------------- --------- ---------------

PK_T_PK6_SNO    UNIQUE    USERS

PK_T_PK7_SNO    UNIQUE    EXAMPLE

UN_T_PK8_SNO    UNIQUE    EXAMPLE

 

HR@ENMOEDU>

14)  主键的索引并一定都是唯一索引,也可以是普通的B*tree索引

HR@ENMOEDU>CREATE TABLE t_pk9

(

sno NUMBER(5),

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE

);

 

Table created.

 

HR@ENMOEDU>alter table t_pk9 add constraint pk_t_pk9_sno primary key (sno) using index (create index un_t_pk9_sno on t_pk9(sno) tablespace example);

 

Table altered.

 

HR@ENMOEDU>select index_name,uniqueness,tablespace_name from user_indexes where table_name like upper('t_pk_');

 

INDEX_NAME      UNIQUENES TABLESPACE_NAME

-------------- --------- ---------------

PK_T_PK6_SNO    UNIQUE    USERS

PK_T_PK7_SNO    UNIQUE    EXAMPLE

UN_T_PK6_SNO    UNIQUE    EXAMPLE

UN_T_PK9_SNO    NONUNIQUE EXAMPLE

 

HR@ENMOEDU>

3.4.  FOREIGN KEY

外键约束

语法:

CONSTRAINT emp_dept_fk FOREIGN KEY (department_id)

      REFERENCES departments(department_id)

                 [ON DELETE {CASCADE|SET NULL}]

   FOREIGN KEY: 在表约束级别,定义子表中的列。

   REFERENCES: 确定父表中的表和列。

   ON DELETE CASCADE: 当父表中的行被删除时,删除子表中相依赖的行(级联删除)

   ON DELETE SET NULL: 当父表的值被删除时,转换外键值为空。

 

1)   清理测试环境

HR@ENMOEDU>drop table student purge;

 

Table dropped.

 

HR@ENMOEDU>

2)   创建籍贯表,插入测试数据

HR@ENMOEDU>create table nativeplace

(

nid number(2) primary key,      --主键id

np_name varchar2(20) not null   --籍贯名称

);

 

Table created.

 

HR@ENMOEDU>insert into nativeplace values(1,'heilongjiang');

 

1 row created.

 

HR@ENMOEDU>insert into nativeplace values(2,'jilin');

 

1 row created.

 

HR@ENMOEDU>insert into nativeplace values(3,'liaoning');

 

1 row created.

 

 

HR@ENMOEDU>insert into nativeplace values(4,'beijing');

 

1 row created.

 

HR@ENMOEDU>commit;

HR@ENMOEDU>select * from nativeplace;

 

       NID NP_NAME

---------- --------------------

         1 heilongjiang

         2 jilin

         3 liaoning

         4 beijing

 

HR@ENMOEDU>

3)   创建学生表,插入测试数据

HR@ENMOEDU>CREATE TABLE student

(

sno NUMBER(5) constraint pk_student primary KEY using index, --学生编号(主键)

sname VARCHAR2(20) not null,                                 --学生名称

idcard VARCHAR2(18) not null,                                --身份证号

createtime DATE default SYSDATE not null,                  --创建时间

native_place number(2),                                      --籍贯id

constraint fk_student foreign key (native_place) REFERENCES nativeplace (nid) ON DELETE SET NULL

);

 

Table created.

 

HR@ENMOEDU>

insert into student values(1,'zhangsan','123456789123456780',default,1);

 

1 row created.

 

HR@ENMOEDU>

insert into student values(2,'lisi','123456789123456781',default,2);

 

1 row created.

 

HR@ENMOEDU>

insert into student values(3,'wangwu','123456789123456782',default,3);

 

1 row created.

 

HR@ENMOEDU>

insert into student values(4,'zhaoliu','123456789123456783',default,4);

 

1 row created.

 

HR@ENMOEDU>col sno for 999

HR@ENMOEDU>col sname for a10

HR@ENMOEDU>select * from student;

 

 SNO SNAME      IDCARD             CREATETIME          NATIVE_PLACE

---- ---------- ------------------ ------------------- ------------

   1 zhangsan   123456789123456780 2012-09-14 16:06:06            1

   2 lisi       123456789123456781 2012-09-14 16:06:10            2

   3 wangwu     123456789123456782 2012-09-14 16:06:13            3

   4 zhaoliu    123456789123456783 2012-09-14 16:06:16            4

 

HR@ENMOEDU>

4)   创建课程表,插入测试数据

HR@ENMOEDU>create TABLE course

(

cno NUMBER(5) CONSTRAINT pk_course PRIMARY KEY NOT NULL,  --课程编号(主键)

cname VARCHAR2(20) NOT NULL                               --课程名称

);

 

Table created.

 

HR@ENMOEDU>insert into course VALUES(1,'Oracle');

 

1 row created.

 

HR@ENMOEDU>insert into course VALUES(2,'Java');

 

 

1 row created.

 

HR@ENMOEDU>insert into course VALUES(3,'C++');

 

1 row created.

 

HR@ENMOEDU>select * from course;

 

       CNO CNAME

--------- --------------

         1 Oracle

         2 Java

         3 C++

 

HR@ENMOEDU>

5)   创建成绩表,插入测试数据

HR@ENMOEDU>create TABLE sc

(

sno NUMBER(5),       --学生编号

cno NUMBER(5),       --课程编号

grade NUMBER(4,1),  --成绩

constraint pk_sc primary key (sno,cno),

constraint fk_sc_sno foreign key (sno) REFERENCES student (sno) ON DELETE CASCADE,

constraint fk_sc_cno foreign key (cno) REFERENCES course (cno)

);

 

Table created.

 

HR@ENMOEDU>

insert into sc values(1,1,91);

insert into sc values(1,2,92);

insert into sc values(1,3,93);

insert into sc values(2,1,88);

insert into sc values(2,2,77);

insert into sc values(2,3,99);

insert into sc values(3,1,65);

insert into sc values(3,2,75);

insert into sc values(3,3,85);

insert into sc values(4,1,80);

insert into sc values(4,2,88);

insert into sc values(4,3,89);

HR@ENMOEDU>commit;

Commit complete.

 

HR@ENMOEDU>select * from sc;

 

 SNO       CNO      GRADE

---- -------- ---------

   1          1         91

   1          2         92

   1          3         93

   2          1         88

   2          2         77

   2          3         99

   3          1         65

   3          2         75

   3          3         85

   4          1         80

   4          2         88

   4          3         89

 

12 rows selected.

 

HR@ENMOEDU>

6)   测试,子表插入父表不存在的数据的时候,报错的效果往成绩表中插入数据,学生编号不存在

HR@ENMOEDU>insert into sc values(5,1,100);

insert into sc values(5,1,100)

*

ERROR at line 1:

ORA-02291: integrity constraint (SCOTT.FK_SC_SNO) violated - parent key not

found

 

HR@ENMOEDU>

7)   往成绩表中插入数据,课程编号不存在

HR@ENMOEDU>insert into sc values(1,4,100);

insert into sc values(1,4,100)

*

ERROR at line 1:

ORA-02291: integrity constraint (SCOTT.FK_SC_CNO) violated - parent key not

found

 

HR@ENMOEDU>

8)   开始测试,验证set null,查看表nativeplace

HR@ENMOEDU>select * from nativeplace;

 

       NID NP_NAME

--------- --------------------

         1 heilongjiang

         2 jilin

         3 liaoning

         4 beijing

 

HR@ENMOEDU>

9)   查看表student

HR@ENMOEDU>select * from student;

 

 SNO SNAME      IDCARD             CREATETIME          NATIVE_PLACE

---- ---------- ------------------ ------------------- ------------

   1 zhangsan   123456789123456780 2012-09-14 16:06:06            1

   2 lisi       123456789123456781 2012-09-14 16:06:10            2

   3 wangwu     123456789123456782 2012-09-14 16:06:13            3

   4 zhaoliu    123456789123456783 2012-09-14 16:06:16            4

 

HR@ENMOEDU>

10)  删除籍贯表中nid3的记录

HR@ENMOEDU>delete nativeplace where nid=3;

 

1 row deleted.

 

HR@ENMOEDU>commit;

 

Commit complete.

 

HR@ENMOEDU>

11)  查看籍贯表,nid3的记录已经删除

HR@ENMOEDU>select * from nativeplace;

 

       NID NP_NAME

--------- --------------------

         1 heilongjiang

         2 jilin

         4 beijing

 

HR@ENMOEDU>

12)  查看学生表,此时之前籍贯为3的籍贯id已经变为null,此时,外键约束set null起了作用

HR@ENMOEDU>select * from student;    

 

 SNO SNAME      IDCARD             CREATETIME          NATIVE_PLACE

---- ---------- ------------------ ------------------- ------------

   1 zhangsan   123456789123456780 2012-09-14 16:06:06            1

   2 lisi       123456789123456781 2012-09-14 16:06:10             2

   3 wangwu     123456789123456782 2012-09-14 16:06:13

   4 zhaoliu    123456789123456783 2012-09-14 16:06:16            4

 

 

13)  验证级联删除

HR@ENMOEDU>select * from student;

 

SNO SNAME      IDCARD             CREATETIME          NATIVE_PLACE

--- ---------- ------------------ ------------------- ------------

   1 zhangsan   123456789123456780 2012-09-14 16:06:06            1

   2 lisi       123456789123456781 2012-09-14 16:06:10            2

   3 wangwu     123456789123456782 2012-09-14 16:06:13

   4 zhaoliu    123456789123456783 2012-09-14 16:06:16            4

 

HR@ENMOEDU>select * from sc;

 

 SNO        CNO  GRADE

---- -------- ---------

   1          1         91

   1          2         92

   1          3         93

   2          1         88

   2          2         77

   2          3         99

   3          1         65

   3          2         75

   3          3         85

   4          1         80

   4          2         88

   4          3         89

 

12 rows selected.

 

HR@ENMOEDU>

14)  删除学生表中,学号为1的记录,查询验证,学号为1的记录已经删除

HR@ENMOEDU>delete student where sno=1;

 

1 row deleted.

 

HR@ENMOEDU>commit;

 

Commit complete.

 

HR@ENMOEDU>select * from student;

 

 SNO SNAME     IDCARD             CREATETIME          NATIVE_PLACE

---- -------- ------------------ ------------------- ------------

   2 lisi       123456789123456781 2012-09-14 16:06:10            2

   3 wangwu     123456789123456782 2012-09-14 16:06:13

   4 zhaoliu    123456789123456783 2012-09-14 16:06:16            4

 

HR@ENMOEDU>

15)  查看成绩表,此时发现,学号为1的学生的成绩已经全部删除,此时外键的级联删除起了作用

HR@ENMOEDU>select * from sc;

 

 SNO        CNO     GRADE

---- -------- ---------

   2          1         88

   2          2         77

   2          3         99

   3          1         65

   3          2         75

   3          3         85

   4          1         80

   4          2         88

   4          3         89

 

9 rows selected.

 

HR@ENMOEDU>

16)  验证默认约束规则,提示无法删除

HR@ENMOEDU>delete course where cno=1;

delete course where cno=1

*

ERROR at line 1:

ORA-02292: integrity constraint (HR.FK_SC_CNO) violated - child record found

 

 

HR@ENMOEDU>

3.5.  CHECK

1)   删除环境中原来的学生表

HR@ENMOEDU>drop table student1 purge;

 

Table dropped.

 

HR@ENMOEDU>

创建学生表,要求,建表的同时,创建两个check,一个保证身份证内容都为小写,一个是保证所有学生的名字都为大写

HR@ENMOEDU>CREATE TABLE student1

(

sno NUMBER(5),

sname VARCHAR2(20),

idcard VARCHAR2(18) check (idcard=lower(idcard)),

createtime DATE,

CONSTRAINT ck_student_sname CHECK (sname=upper(sname))

) ;

 

Table created.

 

HR@ENMOEDU>

2)   插入测试数据,验证check约束

HR@ENMOEDU>insert into student1 values(1,'AA','123a',sysdate);

 

1 row created.

 

HR@ENMOEDU>insert into student1 values(2,'aa','123a',sysdate);

insert into student1 values(2,'aa','123a',sysdate)

*

ERROR at line 1:

ORA-02290: check constraint (HR.CK_STUDENT_SNAME) violated

 

HR@ENMOEDU>commit;

 

Commit complete.

 

HR@ENMOEDU>

 

问:

下面语句是否能够执行成功?

insert into student1 values(1,null,null,sysdate);可以,null空值是不受check约束的

 

注:下面两个建表脚本是不被允许的。

Drop table student1 purge;

CREATE TABLE student1

(

sno NUMBER(5),

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE check(createtime <sysdate)

);

 

CREATE TABLE student1

(

sno NUMBER(5),

sname VARCHAR2(18) check(sname=idcard),

idcard VARCHAR2(18),

createtime DATE

);

如下表达式在check是不被允许的

  - 涉及到 CURRVAL, NEXTVAL, LEVEL ROWNUM 伪列

  - 调用 SYSDATE, UID, USER USERENV 函数

  - 涉及其它行中其它值的查询


 

 

  第4章  创建视图

语法:

CREATE [OR REPLACE] [FORCE|NOFORCE] VIEW view

  [(alias[, alias]...)]

 AS subquery

[WITH CHECK OPTION [CONSTRAINT constraint]]

[WITH READ ONLY [CONSTRAINT constraint]];

 

OR   REPLACE

如果视图已经存在重新创建它

FORCE

创建视图,而不管基表是否存在

NOFORCE

只在基表存在的情况下创建视图(这是默认值)

View

视图的名字

Alias

为由视图查询选择的表达式指定名字(别名的个数必须与由视图选择的表达式的个数匹配)

Subquery

是一个完整的 SELECT 语句(对于在 SELECT 列表中的字段你可以用别名)

WITH   CHECK   OPTION

指定只有可访问的行在视图中才能被插入或修改

Constraint

CHECK OPTION 约束指定的名字

WITH   READ   ONLY

确保在该视图中没有 DML 操作被执行

 

如果基表不存在,那么

Force 可以创建成功,但会提示编译错误

Noforce 直接提示表或视图不存在

4.1.  简单视图、复杂视图区别及测试

特性

简单视图

复杂视图

表的数目

一个

一个或多个

包含函数

包含数据分组

通过视图进行DML操作

不允许

1)   创建学生表

HR@ENMOEDU>CREATE TABLE student

(

sno NUMBER(5),

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE default SYSDATE not null,

native_place number(2)

);

2)   学生表插入数据

insert into student values(1,'zhangsan','123456789123456780',default,1);

insert into student values(2,'lisi','123456789123456781',default,2);

insert into student values(3,'wangwu','123456789123456782',default,3);

insert into student values(4,'zhaoliu','123456789123456783',default,4);

3)   创建简单视图和复杂视图   grant create view to scott;

简单视图:

HR@ENMOEDU>create view vw_student1 as select sno,sname,createtime from student;

 

View created.

 

HR@ENMOEDU>create view vw_student2 as select sno,sname,createtime,sysdate as dd from student;

 

View created.

 

复杂视图:

HR@ENMOEDU>create view vw_student3 as select sno,sname,to_char(createtime,'yyyy-mm-dd') as ctime from student;

 

View created.

 

HR@ENMOEDU>create view vw_student4 as select native_place,count(*) as num from student group by native_place;

 

View created.

 

HR@ENMOEDU>

4)   插入数据测试

HR@ENMOEDU>insert into vw_student1 values(5,'test',sysdate);

 

1 row created.

 

HR@ENMOEDU>insert into vw_student2(sno,sname,createtime) values(6,'test1',sysdate);

 

1 row created.

HR@ENMOEDU>insert into vw_student3(sno,sname,ctime) values(7,'test2',to_char(sysdate,'yyyy-mm-dd'));

insert into vw_student3(sno,sname,ctime) values(7,'test2',to_char(sysdate,'yyyy-mm-dd'))

                                  *

ERROR at line 1:

ORA-01733: virtual column not allowed here

 

 

HR@ENMOEDU>insert into vw_student4 values(1,1);

insert into vw_student4 values(1,1)

*

ERROR at line 1:

ORA-01733: virtual column not allowed here

 

 

HR@ENMOEDU>

4.2.  WITH CHECK OPTION

视图中的check约束

1)   建表、插入测试数据

HR@ENMOEDU>drop table student purge;

 

Table dropped.

 

HR@ENMOEDU>CREATE TABLE student

(

sno NUMBER(5) constraint pk_student primary KEY using index,

sname VARCHAR2(20),

idcard VARCHAR2(18),

createtime DATE default SYSDATE,

native_place number(2)

);

 

Table created.

 

HR@ENMOEDU>

insert into student values(1,'zhangsan','123456789123456780',default,1);

insert into student values(2,'lisi','123456789123456781',default,2);

insert into student values(3,'wangwu','123456789123456782',default,3);

insert into student values(4,'zhaoliu','123456789123456783',default,2);

insert into student values(5,'zhaosi','123456789123456783',default,2);

insert into student values(6,'maba','123456789123456783',default,2);

commit;

2)   创建没有约束的简单视图

HR@ENMOEDU>create or replace view vw_student7

as

select sno,sname,idcard,native_place

from student where native_place=2;

 

View created.

 

HR@ENMOEDU>

3)   创建有约束的简单视图with check option,即指定只有可访问的行在视图中才能被插入或修改

HR@ENMOEDU>create or replace view vw_student8

as

select sno,sname,idcard,native_place

from student where native_place=2

with check option;

 

View created.

 

HR@ENMOEDU>

4)   插入数据测试

HR@ENMOEDU>

insert into vw_student8 values(7,'zhu88','123456789123456783',3);

insert into vw_student8 values(7,'zhu88','123456789123456783',3)

*

ERROR at line 1:

ORA-01402: view WITH CHECK OPTION where-clause violation

 

 

HR@ENMOEDU>

insert into vw_student7 values(7,'zhu88','123456789123456783',3);

 

1 row created.

 

HR@ENMOEDU>

insert into vw_student8 values(8,'niu99','123456789123456783',2);

 

1 row created.

 

HR@ENMOEDU>commit;

 

Commit complete.

 

HR@ENMOEDU>

小结:

1)   当往有约束的简单视图中插入不符合约束的数据时,数据库则会抛出错误,当插入符合约束条件的数据,则插入正常。

2)   当往没有约束的视图中插入符合标准的数据时,则可以正常插入

4.3.  WITH READ ONLY

只读视图

HR@ENMOEDU>create or replace view vw_student9

as

select sno,sname,idcard,native_place

from student

where native_place=2

with read only;

 

View created.

 

HR@ENMOEDU>

HR@ENMOEDU>insert into vw_student9 values(9,'r_only','123456789123456783',2);

insert into vw_student9 values(9,'r_only','123456789123456783',2)

*

ERROR at line 1:

ORA-42399: cannot perform a DML operation on a read-only view


  第5章  其他数据库对象

5.1.  序列

(一)语法:

1)   创建序列

CREATE SEQUENCE sequence

       [INCREMENT BY n]

       [START WITH n]

       [{MAXVALUE n | NOMAXVALUE}]

       [{MINVALUE n | NOMINVALUE}]

       [{CYCLE | NOCYCLE}]

       [{CACHE n | NOCACHE}];

sequence

是序列发生器的名字

INCREMENT   BY   n

指定序列号之间的间隔,在这儿 n 是一个整数  (如果该子句被省略,序列增量为 1)

START   WITH   n

指定要产生的第一个序列数  (如果该子句被省略,序列从 1开始)

MAXVALUE   n

指定序列能产生的最大值

NOMAXVALUE

对于升序序列指定 10^27 为最大值,对于降序序列指定-1为最大值  (这是默认选项) 

MINVALUE   n

指定最小序列值

NOMINVALUE

对于升序序列指定 1 为最小值,对于降序序列指定-(10^26)为最小值  (这是默认选项)

CYCLE|NOCYCLE

指定序列在达到它的最大或最小值之后,是否继续产生 (NOCYCLE 是默认选项)

CACHE   n|NOCACHE

指定 Oracle 服务器预先分配多少值,并且保持在内存中(默认情况下,Oracle 服务器缓冲 20 个值)

2)   修改序列:

ALTER     SEQUENCE sequence

[INCREMENT   BY   n]

[{MAXVALUE   n   |   NOMAXVALUE}]

[{MINVALUE   n   |   NOMINVALUE}]

[{CYCLE   |   NOCYCLE}]

[{CACHE   n   |   NOCACHE}];

3)   删除序列:

DROP SEQUENCE sequence;

(二)使用NEXTVALCURRVAL的规则

1)   可以使用nextvalcurrval

?   一个不是子查询的一部分的 SELECT 语句的 SELECT 列表

?   在一个 INSERT 语句中子查询的 SELECT 列表

?   一个 INSERT 语句中的 VALUES 子句

?   一个 UPDATE 语句的 SET 子句

2)   不允许使用nextvalcurrval

?   一个视图的 SELECT 列表

create or replace view vw_a as select seq_test.nextval,1 as id from dual;

?   一个带 DISTINCT 关键字的 SELECT 语句

?   一个带 GROUP BYHAVING ORDER BY 子句的 SELECT 语句

?   一个在 SELECTDELETE UPDATE 语句中的子句

?   CREATE TABLE ALTER TABLE 语句中的 DEFAULT 表达式

(三)序列测试

HR@ENMOEDU>create sequence SEQ

  minvalue 1

  maxvalue 100

  start with 2

  increment by 1;

 

Sequence created.

--在没有执行nextval的时候,无法执行currval

HR@ENMOEDU>select seq.currval from dual;

select seq.currval from dual

       *

ERROR at line 1:

ORA-08002: sequence SEQ.CURRVAL is not yet defined in this session

 

 

HR@ENMOEDU>select seq.nextval from dual;

 

   NEXTVAL

----------

2

 

HR@ENMOEDU>select seq.nextval from dual;

 

   NEXTVAL

----------

 

         3

 

HR@ENMOEDU>

新打开一个会话:

HR@ENMOEDU> select seq.currval from dual;

select seq1.currval from dual

       *

ERROR at line 1:

ORA-08002: sequence SEQ.CURRVAL is not yet defined in this session

 

小结:

1)   在一个新的会话中,不能直接使用currval,必须先nextval后再currval

2)   新建的一个序列,第一次nextval的值为start with的值

(四)序列和触发器配合应用

HR@ENMOEDU>create table t_seq(nid number(10),name varchar2(10));

 

Table created.

 

HR@ENMOEDU>create sequence seq_t_seq;

 

Sequence created.

 

HR@ENMOEDU>create trigger trg_t_seq

  before insert on t_seq

  for each row

begin

  if :new.nid is null then

    select seq_t_seq.nextval

      into :new.nid

      from dual;

  end if;

end;

/

 

Trigger created.

 

HR@ENMOEDU>insert into t_seq (name) values('a');

 

1 row created.

 

HR@ENMOEDU>insert into t_seq (name) values('b');

 

1 row created.

 

HR@ENMOEDU>

上面的insert语句,有这样的误解,nid不是主键,也非not null,插入两条记录很正常,那么我们将nid修改为主键,如下:

HR@ENMOEDU>alter table t_seq add primary key(nid);

 

Table altered.

 

HR@ENMOEDU>insert into t_seq (name) values('c');

 

1 row created.

 

HR@ENMOEDU>commit;

 

Commit complete.

 

HR@ENMOEDU>

HR@ENMOEDU>select * from t_seq;

 

       NID NAME

---------- ----------

         1 a

         2 b

         3 c

 

HR@ENMOEDU>

此时我们发现,主键字段也是有数据的,主键的数据就是来源于触发器,这个是一个比较典型的触发器利用序列协助写入主键的例子

(五)查询序列

1)   查看序列SEQ_T_SEQ

HR@ENMOEDU>select sequence_name,min_value,max_value,increment_by,cycle_flag,last_number from user_sequences where sequence_name='SEQ_T_SEQ';

 

SEQUENCE_NAME  MIN_VALUE  MAX_VALUE INCREMENT_BY LAST_NUMBER

------------- ---------- ---------- ------------ -----------

SEQ_T_SEQ              1 1.0000E+28            1 21

 

HR@ENMOEDU>

注:如果指定NOCACHE 选项,那么LAST_NUMBER显示序列中下一个有效的值,'SEQ_T_SEQ'这个序列的LAST_NUMBER显示的就不是下一个有效值

2)   查看创建SEQ_T_SEQ的脚本,确认cache

HR@ENMOEDU>set long 999999

HR@ENMOEDU>select dbms_metadata.get_ddl(object_type => 'SEQUENCE',name => 'SEQ_T_SEQ') from dual;

 

DBMS_METADATA.GET_DDL(OBJECT_TYPE=>'SEQUENCE',NAME=>'SEQ_T_SEQ')

------------------------------------------------------------------------

 

   CREATE SEQUENCE  "HR"."SEQ_T_SEQ"  MINVALUE 1 MAXVALUE 9999999999999999999999

999999 INCREMENT BY 1 START WITH 21 CACHE 20 NOORDER  NOCYCLE

 

HR@ENMOEDU>

3)   下面举我们创建一个NOCACHE的例子

HR@ENMOEDU>select sequence_name,min_value,max_value,increment_by,cycle_flag,last_number from user_sequences where sequence_name='SEQ_T_SEQ';

 

SEQUENCE_NAME  MIN_VALUE  MAX_VALUE INCREMENT_BY LAST_NUMBER

------------- ---------- ---------- ------------ -----------

SEQ_T_SEQ              1 1.0000E+28            1             21

 

HR@ENMOEDU>create sequence seq_nocache nocache;

 

Sequence created.

 

4)   执行一次sequence,得到的结果为1,下一个值应该是2

HR@ENMOEDU>select seq_nocache.nextval from dual;

 

   NEXTVAL

----------

         1

 

HR@ENMOEDU>

5)   查看序列SEQ_NOCACHELAST_NUMBER,此时我们发现LAST_NUMBER值为2,也就是下一个有效值

HR@ENMOEDU>select sequence_name,min_value,max_value,increment_by,last_number from user_sequences where sequence_name='SEQ_NOCACHE';

 

SEQUENCE_NAME  MIN_VALUE  MAX_VALUE INCREMENT_BY LAST_NUMBER

------------- ---------- ---------- ------------ -----------

SEQ_NOCACHE            1 1.0000E+28            1        2

 

HR@ENMOEDU>

(六)删除序列

HR@ENMOEDU>drop sequence seq_nocache;

 

Sequence dropped.

 

HR@ENMOEDU>

5.2.  索引

(一)自动创建

创建主键或唯一键约束会在相应字段上创建唯一索引

1)   创建测试表

HR@ENMOEDU>create table t_a_index(x number,y number);

 

Table created.

 

HR@ENMOEDU>

2)   修改表,增加主键主键的名字为pk_t_a_index

HR@ENMOEDU>alter table t_a_index add constraint pk_t_a_index primary key(x);

Table altered.

 

HR@ENMOEDU>

3)   修改表,增加唯一键,唯一键的名字为uk_t_a_index

HR@ENMOEDU>alter table t_a_index add constraint uk_t_a_index unique(y);

 

Table altered.

 

HR@ENMOEDU>

4)   查看表T_A_INDEX的相关索引,发现有两个与约束名称相同的索引

HR@ENMOEDU>select index_name,index_type,table_owner,table_name,uniqueness from user_indexes where table_name='T_A_INDEX';

 

INDEX_NAME   INDEX_TYPE TABLE_OWNER TABLE_NAME UNIQUENES

------------ ---------- ----------- ---------- ---------

UK_T_A_INDEX NORMAL     HR          T_A_INDEX  UNIQUE

PK_T_A_INDEX NORMAL     HR          T_A_INDEX  UNIQUE

 

HR@ENMOEDU>

通过这个测试,我们了解到,主键和唯一键会自动创建唯一索引,索引的名称与约束的名称相同

(二)手工创建

在一个或多个列上创建索引,语法:

CREATE INDEX index ON table (column[, column]...);

1)   创建测试表

HR@ENMOEDU>create table t_m_index(x number,y number,z number);

 

Table created.

 

HR@ENMOEDU>

2)   x字段上创建普通索引

HR@ENMOEDU>create index idx_t_m_index_x on t_m_index(x);

 

Index created.

 

HR@ENMOEDU>

3)   y,z字段上创建普通复合索引

HR@ENMOEDU>create index idx_t_m_index_yz on t_m_index(y,z) tablespace users;

 

Index created.

 

HR@ENMOEDU>

4)   查看表T_M_INDEX相关索引

HR@ENMOEDU>select index_name,index_type,table_owner,table_name,uniqueness from user_indexes where table_name='T_M_INDEX';

 

INDEX_NAME       INDEX_TYPE TABLE_OWNER TABLE_NAME UNIQUENES

---------------- ---------- ----------- ---------- ---------

IDX_T_M_INDEX_YZ NORMAL     HR          T_M_INDEX  NONUNIQUE

IDX_T_M_INDEX_X  NORMAL     HR          T_M_INDEX  NONUNIQUE

 

HR@ENMOEDU>

注:字典表user_indexesUNIQUENES字段

comment on column SYS.USER_INDEXES.UNIQUENESS is 'Uniqueness status of the index:  "UNIQUE",  "NONUNIQUE", or "BITMAP"';

5)   查看T_M_INDEX相关索引及索引字段

HR@ENMOEDU>SELECT t.index_name, t.column_name, t.column_position col_pos, d.uniqueness FROM user_indexes d, user_ind_columns t

WHERE t.index_name = d.index_name

 AND t.table_name = 'T_M_INDEX';

 

INDEX_NAME       COLUMN_NAME    COL_POS UNIQUENES

---------------- ------------ ---------- ---------

IDX_T_M_INDEX_X  X                     1 NONUNIQUE

IDX_T_M_INDEX_YZ Y                     1 NONUNIQUE

IDX_T_M_INDEX_YZ Z                     2 NONUNIQUE

 

HR@ENMOEDU>

5.3.  同义词

同义词,简单点儿理解就是一个别名,一个映射的关系。

(一)同义词的分类

Oracle同义词有两种类型,分别是公用Oracle同义词与私有Oracle同义词。

1)   公用Oracle同义

由一个特殊的用户组Public所拥有。顾名思义,数据库中所有的用户都可以使用公用同义词。公用同义词往往用来标示一些比较普通的数据库对象,这些对象往往大家都需要引用。

2)   私有Oracle同义词(默认创建)

它是跟公用同义词所对应,他是由创建他的用户所有。当然,这个同义词的创建者,可以通过授权控制其他用户是否有权使用属于自己的私有同义词。

(二)语法

1)   创建同义词

create [or replace] [public] synonym [schema.]synonym

for [schema.]object[@dblink];

2)   删除同义词

drop [public] synonym [schema.]synonym [force];

(三)先决条件

1)   要自己的schema下创建私有的同义词,你必须拥有CREATE SYNONYM系统权限

2)   要在其他schema下创建一个私有同义词,你必须有CREATE ANY SYNONYM系统权限

3)   创建一个公共的同义词,你必须有CREATE PUBLIC SYNONYM系统权限

(四)私有同义词测试

1)   scott下想查看hr下的employees,没有权限查看,如果不想直接把employees的查询权限给scott,那么可以考虑创建一个同义词

SYS@ENMOEDU> create user scott identified by scott ;

User created.

SYS@ENMOEDU> grant connect,resource,create synonym to scott;

Grant succeeded.

SYS@ENMOEDU> conn scott/scott

Connected.

 

SCOTT@ENMOEDU> select count(*) from hr.employees;

select count(*) from hr.employees

                        *

ERROR at line 1:

ORA-00942: table or view does not exist

 

SCOTT@ENMOEDU>

2)   连接到scott用户下创建hr用户下的employees的同义词syn_employees

SCOTT@ENMOEDU> conn hr/hr

Connected.

HR@ENMOEDU> grant select on employees to scott;

 

Grant succeeded.

HR@ENMOEDU> conn scott/tiger

Connected.

SCOTT@ENMOEDU>create synonym syn_employees for hr.employees;

 

create synonym syn_employees for hr.employees

*

ERROR at line 1:

ORA-01031: insufficient privileges

 

 

SCOTT@ENMOEDU >conn / as sysdba

Connected.

SYS@ENMOEDU >grant create any synonym to scott;

 

Grant succeeded.

 

SYS@ENMOEDU >conn scott/tiger;

Connected.

SCOTT@ENMOEDU >create synonym syn_employees for hr.employees;

 

Synonym created.

 

3)   scott用户下查询hr下的同义词

HR@ENMOEDU> conn scott/tiger

Connected.

SCOTT@ENMOEDU> select count(*) from syn_employees;

 

  COUNT(*)

----------

       107

SCOTT@ENMOEDU>

(五)公共同义词测试

1)   sys用户下创建公共同义词dept

SYS@ENMOEDU>create or replace public synonym dept for hr.departments;

 

Synonym created.

 

SYS@ENMOEDU>

2)   连接到scott用户测试公共同义词是否可以查询

查询结果为表或视图不存在,之所以报这个错误,是因为scott没有查询hr.departments的权限

SYS@ENMOEDU> conn scott/scott

Connected.

SCOTT@ENMOEDU> select * from dept;

select * from dept

              *

ERROR at line 1:

ORA-00942: table or view does not exist

 

SCOTT@ENMOEDU>

3)   我们到拥有DBA权限的system用户可以查看到dept同义词

SCOTT@ENMOEDU> conn system/oracle

Connected.

 

SYSTEM@ENMOEDU>select count(*) from dept;

 

  COUNT(*)

----------

27

 

SYSTEM@ENMOEDU>

4)   我们可以将同义词departmentsselect权限赋予public

SYSTEM@ENMOEDU> conn hr/hr

Connected.

HR@ENMOEDU>grant select on departments to public;

 

Grant succeeded.

 

HR@ENMOEDU>

5)   我们再回到scott用户,此时就可以查询了

HR@ENMOEDU> conn scott/scott

Connected.

SCOTT@ENMOEDU> select count(*) from dept;

 

  COUNT(*)

----------

        27

SCOTT@ENMOEDU>

其实规则是这样的

-     首先查看发出命令的用户对表或者视图是否存在并且有访问权限

-     如果表或视图不存在,则检查私有同义词

-     如果私有同义词不存在,则访问公共同义词

-     如果公共同义词仍不存在,Oracle返回消息“ORA-00942 table or view does not exist”.


 

 

   第6章  使用集合运算

6.1.  UNION

A集合和B集合的合并,去掉两集合重复的部分并且排序

HR@ENMOEDU>select department_id,first_name from employees where department_id in (10,20);

 

DEPARTMENT_ID FIRST_NAME

------------- --------------------

           10 Jennifer

           20 Michael

           20 Pat

 

HR@ENMOEDU>select department_id,first_name from employees where department_id in (10,30);

 

DEPARTMENT_ID FIRST_NAME

------------- --------------------

           10 Jennifer

           30 Den

           30 Alexander

           30 Shelli

           30 Sigal

           30 Guy

           30 Karen

 

7 rows selected.

 

HR@ENMOEDU>

select department_id,first_name from employees where department_id in (10,20)

union

 select department_id,first_name from employees where department_id in (10,30);

 

DEPARTMENT_ID FIRST_NAME

------------- --------------------

           10 Jennifer

           20 Michael

           20 Pat

           30 Alexander

           30 Den

           30 Guy

           30 Karen

           30 Shelli

           30 Sigal

 

9 rows selected.

 

HR@ENMOEDU>

6.2.  UNION ALL

A集合和B集合的合并不去重,不排序

HR@ENMOEDU>

select department_id,first_name from employees where department_id in (10,20)

union all

 select department_id,first_name from employees where department_id in (10,30);

 

 

DEPARTMENT_ID FIRST_NAME

------------- --------------------

           10 Jennifer

           20 Michael

           20 Pat

10 Jennifer

           30 Den

           30 Alexander

           30 Shelli

           30 Sigal

           30 Guy

           30 Karen

 

10 rows selected.

 

HR@ENMOEDU>

6.3.  INTERSECT

两个集合交集部分排序并去重

HR@ENMOEDU>

select department_id,first_name from employees where department_id in (10,20)

intersect

 select department_id,first_name from employees where department_id in (10,30);

 

DEPARTMENT_ID FIRST_NAME

------------- --------------------

           10 Jennifer

 

HR@ENMOEDU>

6.4.  MINUS

取两个集合差集返回A集合中存在,B集合中不存在的数据

HR@ENMOEDU>

select department_id,first_name from employees where department_id in (10,20)

minus

 select department_id,first_name from employees where department_id in (10,30);

 

DEPARTMENT_ID FIRST_NAME

------------- --------------------

           20 Michael

           20 Pat

 

HR@ENMOEDU>

6.5.  UNION/UNION ALL注意事项

HR@ENMOEDU>create table t_union1(col number);

 

Table created.

 

HR@ENMOEDU>

HR@ENMOEDU>create table t_union2(col  number);

 

Table created.

 

HR@ENMOEDU>

思考题:

在先不考虑t_union1t_union2两张表中的数据的情况下,请问如下两个sql的结果是否相同相同

 

SQL1

Select 1 as type,col from t_union1

Union

Select 2,col from t_union2;

SQL2

Select 1 as type,col from t_union1

Union all

Select 2,col from t_union2;

1)   测试:

HR@ENMOEDU>insert into t_union1 values(1);

 

1 row created.

 

HR@ENMOEDU>insert into t_union1 values(1);

 

1 row created.

 

HR@ENMOEDU>insert into t_union2  values(1);

 

1 row created.

 

HR@ENMOEDU>insert into t_union2  values(2);

 

1 row created.

 

HR@ENMOEDU>commit;

 

Commit complete.

 

HR@ENMOEDU>select * from t_union1;

 

       COL

----------

         1

         1

 

HR@ENMOEDU>select * from t_union2;

 

       COL

----------

         1

         2

 

HR@ENMOEDU>select 1 as type,col from t_union1;

 

      TYPE        COL

---------- ----------

         1          1

         1          1

 

HR@ORA11GR2>select 2 as type,col from t_union2;

 

      TYPE        COL

---------- ----------

         2          1

         2          2

 

HR@ENMOEDU>Select 1 as type,col from t_union1

Union

Select 2,col from t_union2;

 

      TYPE        COL

--------- ---------

         1          1

         2          1

         2          2

 

HR@ENMOEDU>Select 1 as type,col from t_union1

Union all

Select 2,col from t_union2;

 

      TYPE        COL

--------- ---------

         1          1

         1          1

         2          1

         2          2

 

HR@ENMOEDU>

2)   小结

    通过上面的测试我们发现,虽然有常量字段type,但是这两个结果集还是不一样的,因为union的去重操作不单单是两个结果集之间的去重而是整个结果集的一个去除重复的动作(即先是两个结果集的分别去重,然后再两个结果集的合并,最后再去重排序),所以,我们在使用unionunion all的时候要格外注意,特别是在性能优化的时候,不要不假思索的把union替换成union all

请使用浏览器的分享功能分享到微信等