oracle主鍵和外鍵

CREATE TABLE "SCOTT"."MID_A_TAB"

  (    "A" VARCHAR2(20 BYTE),

  "B" VARCHAR2(10 BYTE),

  "DETPNO" VARCHAR2(10 BYTE)

  )TABLESPACE "USERS" ;

  CREATE TABLE "SCOTT"."MID_B_TAB"

  (    "A" VARCHAR2(20 BYTE),

  "B" VARCHAR2(10 BYTE),

  "DEPTNO" VARCHAR2(10 BYTE)

  )TABLESPACE "USERS" ;

  --給MID_A_TAB表添加主鍵

  alter table mid_a_tab add constraint a_pk primary key (detpno);

  --給MID_B_TAB表添加主鍵

  alter table mid_b_tab add constraint b_pk primary key(a);

  --給子表MID_B_TAB添加外鍵,並且引用主表MID_A_TAB的DETPNO列,並通過on delete cascade指定引用行爲是級聯刪除

  alter table mid_b_tab add constraint b_fk foreign key (deptno) references mid_a_tab (detpno) on delete cascade;

  --向這樣就創建了好子表和主表

  向主表添加數據記錄

  SQL> insert into mid_a_tab(a,b,detpno)  values('1','1','10');

  已創建 1 行。

  已用時間:  00: 00: 00.00

  向子表添加數據

  SQL> insert into mid_b_tab(a,b,deptno) values('1','2','6');

  insert into mid_b_tab values('1','2','6')

  *

  第 1 行出現錯誤:

  ORA-00001: 違反唯一約束條件 (SCOTT.B_PK)

  已用時間:  00: 00: 00.00

  可見上面的異常信息,那時因爲子表插入的deptno的值是6,然而此時我們主表中

  detpno列只有一條記錄那就是10,所以當子表插入數據時,在父表中不能夠找到該引用

  列的記錄,所以出現異常。

  但我們可以這樣對子表的數據的進行插入(即:在子表的deptno列插入null,因爲我們在建表的時候

  並沒有對該列進行not null的約束限制):

  SQL> insert into mid_b_tab(a,b,deptno) values('3','2',null);

  已創建 1 行。

  已用時間:  00: 00: 00.00

  現在如果我們把子表mid_b_tab中deptno列加上not null約束。

  SQL> alter table mid_b_tab modify deptno not null;

  alter table mid_b_tab modify deptno not null

  *

  第 1 行出現錯誤:

  ORA-02296: 無法啓用 (SCOTT.) - 找到空值

  已用時間:  00: 00: 00.01

  上面又出現異常,這是因爲現在mid_b_tab表中有了一條記錄,就是我們先前添加的

  那條記錄。

  3,2,null

  現在我們要把該表的deptno列進行not null約束限制,所以oracle不讓我們這樣幹。

  那我們就只有把該表給delete或truncate掉,然後在修改deptno列爲非空。

  SQL> delete from mid_b_tab;

  已刪除2行。

  已用時間:  00: 00: 00.01

  再次修改子表mid_b_tab表的deptno列爲非空。

  SQL> alter table mid_b_tab modify deptno not null;

  表已更改。

  已用時間:  00: 00: 00.01

  修改成功!

  我們再次插入數據

  insert into mid_b_tab(a,b,deptno) values('13','2',null);試試。

  SQL> insert into mid_b_tab(a,b,deptno) values('13','2',null);

  insert into mid_b_tab(a,b,deptno) values('13','2',null)

  *

  第 1 行出現錯誤:

  ORA-01400: 無法將 NULL 插入 ("SCOTT"."MID_B_TAB"."DEPTNO")

  已用時間:  00: 00: 00.00

  看見現在oracle不讓我們插入空值了。

  所以我們在創建子表的外鍵約束時,該表的引用列必須要進行not null限制,也可以在

  該列創建unique,或primary key約束,並且引用列與被引用列的數據類型必須相同。

  SQL> insert into mid_b_tab(a,b,deptno) values('13','2','10');

  已創建 1 行。

  已用時間:  00: 00: 00.01

  此時數據插入成功,因爲此時插入的10,在主表中的被引用列中已經存在了。

  現在我們一系列的操作:

  SQL> select * from mid_b_tab ;

  A                    B          DE

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

  13                   2          10

  已用時間:  00: 00: 00.00

  SQL> select * from mid_a_tab;

  A                    B          DE

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

  1                    1          10

  已用時間:  00: 00: 00.00

  SQL> delete from mid_a_tab;

  已刪除 1 行。

  已用時間:  00: 00: 00.01

SQL> select * from mid_b_tab;

  未選定行

  從上邊的操作中可以看出當我們刪除了主表中的記錄後,子表中相應的記錄

  也被級聯刪除掉了。

  通過引用行爲可以確定如何處理子表中的外鍵字段。引用類型包括3中類型:

  1.on delete cascade;--級聯刪除

  2.on set null;--刪除主表中的記錄後,子表中的相應記錄的列被設置爲null(但子表的該字段必須支持null值)。

  3.on no action;--不允許刪除主表中被引用的數據,該操作會被禁止。

  如果有on delete cascade,而且沒有在子表上加索引:那麼每刪除主表中的一行

  都會對子表做一個全表掃描。而且如果從父表刪除多行,那麼每從父表中刪除一行

  就要掃描一次子表。

  SQL> select * from mid_a_tab a,mid_b_tab b where

  2  a.detpno=b.deptno;

  A                    B          DETPNO     A                    B          DEPTNO

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

  1                    2          12         2                    2          12

  1                    2          12         1                    1          12

  2                    22         13         22                   212        13

  3                    33         14         55                   6666       14

  已用時間:  00: 00: 00.00

  執行計劃

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

  0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=7 Card=4 Bytes=208

  )

  1    0   HASH JOIN (Cost=7 Card=4 Bytes=208)

  2    1     TABLE ACCESS (FULL) OF 'MID_A_TAB' (TABLE) (Cost=3 Card=

  3 Bytes=78)

  3    1     TABLE ACCESS (FULL) OF 'MID_B_TAB' (TABLE) (Cost=3 Card=

  4 Bytes=104)

  統計信息

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

  210  recursive calls

  0  db block gets

  74  consistent gets

  0  physical reads

  0  redo size

  748  bytes sent via SQL*Net to client

  512  bytes received via SQL*Net from client

  2  SQL*Net roundtrips to/from client

  8  sorts (memory)

  0  sorts (disk)

  4  rows processed

  SQL> create index mid_b_index on mid_b_tab(deptno);

  索引已創建。

  已用時間:  00: 00: 00.00

  SQL> select * from mid_a_tab a,mid_b_tab b where

  2   a.detpno=b.deptno;

  A                    B          DETPNO     A                    B          DE

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

  1                    2          12         2                    2          12

  1                    2          12         1                    1          12

  2                    22         13         22                   212        13

  3                    33         14         55                   6666       14

  已用時間:  00: 00: 00.01

  執行計劃

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

  0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=6 Card=4 Bytes=208

  )

  1    0   TABLE ACCESS (BY INDEX ROWID) OF 'MID_B_TAB' (TABLE) (Cost

  =1 Card=1 Bytes=26)

  2    1     NESTED LOOPS (Cost=6 Card=4 Bytes=208)

  3    2       TABLE ACCESS (FULL) OF 'MID_A_TAB' (TABLE) (Cost=3 Car

  d=3 Bytes=78)

  4    2       INDEX (RANGE SCAN) OF 'MID_B_INDEX' (INDEX) (Cost=0 Ca

  rd=4)

  統計信息

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

  10  recursive calls --訪問數據字典得到元數據。第二次執行相同語句,遞歸調用基本爲零

  0  db block gets  -- 指DML語句所得到的數據塊個數   

  31  consistent gets  --重要!!指select語句所得到的數據塊個數 

  0  physical reads --硬盤上讀出的數據 

  0  redo size --產生的日誌

  748  bytes sent via SQL*Net to client  --網絡流量指標   

  512  bytes received via SQL*Net from client --網絡流量指標 

  2  SQL*Net roundtrips to/from client

  2  sorts (memory)

  0  sorts (disk)

  4  rows processed

  大家可以從上面的執行計劃中看出,向子表添加索引前後查詢的差別。如果兩表中的數據量再大點的話那麼效果可能會更明顯。


 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章