數(shù)據(jù)庫筆記(九)——對違反約束的處理 2017.10.15

寫在前面:本篇博客大部分內(nèi)容參考數(shù)據(jù)庫系統(tǒng)概念(本科教學(xué)版)第四章的一些尾巴,然后開始講第六章的關(guān)系代數(shù)
筆者接下來的代碼示例會主要在SQL Server數(shù)據(jù)庫中測試


在開始今天的摸魚大業(yè)之前,讓我們構(gòu)造一些簡單表

-- 執(zhí)行下面的語句構(gòu)造表
CREATE TABLE country(
  country_id INTEGER PRIMARY KEY ,
  country_name VARCHAR(20)
);

CREATE TABLE person(
  person_id INTEGER PRIMARY KEY ,
  name VARCHAR(20),
  country_id INTEGER FOREIGN KEY REFERENCES country(country_id)
    ON DELETE CASCADE
    ON UPDATE CASCADE
);

INSERT INTO country (country_id, country_name) VALUES (
    1, 'China'
);
INSERT INTO country (country_id, country_name) VALUES (
    2, 'English'
);
INSERT INTO country (country_id, country_name) VALUES (
    3, 'America'
);

INSERT INTO person (person_id, name, country_id) VALUES (
    1, 'Sunny', 1
);

INSERT INTO person (person_id, name, country_id) VALUES (
    2, 'Robbin', 2
);

INSERT INTO person (person_id, name, country_id) VALUES (
    3, 'Jane', 3
);

級聯(lián)操作

在指定外鍵以后埋涧,由于存在完整性約束河狐,所以在執(zhí)行刪除或更新的時候由于語句可能會破壞完整性約束而執(zhí)行失敗布持。因此可以在定義外鍵的時候聲明為級聯(lián)刪除和級聯(lián)更新(是一種對違反參照完整性約束時的處理方式)

  • 使用方式

    CREATE table 表名(
      ...
      FOREGIN KEY (字段序列) REFERENCES 表名(字段序列)
          ON DELETE CASCADE
          ON UPDATE CASCADE,
      ...
    )
    
  • 級聯(lián)刪除(ON DELETE CASCADE)

    • 級聯(lián)刪除是在定義外鍵時指定的筐眷,但是卻會在執(zhí)行刪除語句時產(chǎn)生影響
    • 舉個栗子
      • 我們先不指定級聯(lián)
        DROP TABLE person;
        DROP TABLE country;
        CREATE TABLE country(
          country_id INTEGER PRIMARY KEY ,
          country_name VARCHAR(20)
        );
        
        CREATE TABLE person(
          person_id INTEGER PRIMARY KEY ,
          name VARCHAR(20),
          country_id INTEGER FOREIGN KEY REFERENCES country(country_id)
        );
        
        INSERT INTO country (country_id, country_name) VALUES (
            1, 'China'
        );
        INSERT INTO country (country_id, country_name) VALUES (
            2, 'English'
        );
        INSERT INTO country (country_id, country_name) VALUES (
            3, 'America'
        );
        
        INSERT INTO person (person_id, name, country_id) VALUES (
            1, 'Sunny', 1
        );
        
        INSERT INTO person (person_id, name, country_id) VALUES (
            2, 'Robbin', 2
        );
        
        INSERT INTO person (person_id, name, country_id) VALUES (
            3, 'Jane', 3
        );
        
        
      • 然后執(zhí)行下面的刪除操作
        -- 下面我們試圖刪除中國的信息肿孵,但是在person表里有一條數(shù)據(jù)引用了中國澳眷,所以因為參照完整性約束的存在胡嘿,所以這條語句會執(zhí)行失敗
        DELETE country
        WHERE country_id = 1
        
      • 接下來我們重新構(gòu)造一遍(當(dāng)然直接用DDL語句更新也是可以的)--并在構(gòu)造person表時指定了級聯(lián)刪除
        DROP TABLE person;
        DROP TABLE country;
        CREATE TABLE country(
          country_id INTEGER PRIMARY KEY ,
          country_name VARCHAR(20)
        );
        
        CREATE TABLE person(
          person_id INTEGER PRIMARY KEY ,
          name VARCHAR(20),
          country_id INTEGER FOREIGN KEY REFERENCES country(country_id)
              ON DELETE CASCADE
        );
        
        INSERT INTO country (country_id, country_name) VALUES (
            1, 'China'
        );
        INSERT INTO country (country_id, country_name) VALUES (
            2, 'English'
        );
        INSERT INTO country (country_id, country_name) VALUES (
            3, 'America'
        );
        
        INSERT INTO person (person_id, name, country_id) VALUES (
            1, 'Sunny', 1
        );
        
        INSERT INTO person (person_id, name, country_id) VALUES (
            2, 'Robbin', 2
        );
        
        INSERT INTO person (person_id, name, country_id) VALUES (
            3, 'Jane', 3
        );
        
        
      • 然后再次執(zhí)行下面的刪除操作
        -- 此時執(zhí)行會發(fā)現(xiàn)語句成功執(zhí)行了,不但刪除了中國的信息钳踊,連帶person表中引用了中國信息的所有數(shù)據(jù)都被刪除了
        DELETE country
        WHERE country_id = 1
        
    • 上面的例子便很好的說明了級聯(lián)刪除的作用衷敌。如果我們視圖刪除外鍵參照鍵所在表(此處為country表)的某條數(shù)據(jù)A(此處是中國的信息),而這條數(shù)據(jù)又被外鍵所在表的一條或多條數(shù)據(jù)B所關(guān)聯(lián)(此處person表中Sunny的country_id關(guān)聯(lián)了country表中中國的id)拓瞪。在指定了級聯(lián)刪除的情況下缴罗,刪除A會連帶著刪除所有滿足條件的B
    • 當(dāng)然在實際使用的時候用的還是比較少的,因為參照完整性約束在一定程度上可以防止數(shù)據(jù)的誤刪除祭埂,對數(shù)據(jù)庫的完整性起了一定的保護作用面氓,如果指定了級聯(lián)刪除,這層保護就失效了蛆橡。所以還是視情況而用
  • 級聯(lián)更新(ON UPDATE CASCADE)

    • 類似的舌界,級聯(lián)更新和級聯(lián)刪除一樣,如果我們更新時違反了完整性約束泰演,同樣更新操作不被拒絕呻拌,而是級聯(lián)更新
    • 舉個栗子(我們在上面操作的基礎(chǔ)上執(zhí)行,上面構(gòu)造時指定了級聯(lián)刪除睦焕,但是沒指定級聯(lián)更新)
      -- 我們試圖執(zhí)行下面的更新操作柏锄,我們把修改English的country_id, 但是由于person表中還有數(shù)據(jù)的country_id=2,如果下面的更新成功執(zhí)行复亏,則會導(dǎo)致person表中存在country_id=2的數(shù)據(jù)趾娃,而country中卻沒有對應(yīng)數(shù)了,違反參照完整性約束缔御,故下面的語句執(zhí)行失敗
      UPDATE country
      SET country_id = 4
      WHERE country_id = 2
      
    • 同樣的抬闷,我們重新構(gòu)造一下,此時指定級聯(lián)更新
      DROP TABLE person;
      DROP TABLE country;
      CREATE TABLE country(
        country_id INTEGER PRIMARY KEY ,
        country_name VARCHAR(20)
      );
      
      CREATE TABLE person(
        person_id INTEGER PRIMARY KEY ,
        name VARCHAR(20),
        country_id INTEGER FOREIGN KEY REFERENCES country(country_id)
          ON DELETE CASCADE
          ON UPDATE CASCADE
      );
      
      INSERT INTO country (country_id, country_name) VALUES (
          1, 'China'
      );
      INSERT INTO country (country_id, country_name) VALUES (
          2, 'English'
      );
      INSERT INTO country (country_id, country_name) VALUES (
          3, 'America'
      );
      
      INSERT INTO person (person_id, name, country_id) VALUES (
          1, 'Sunny', 1
      );
      
      INSERT INTO person (person_id, name, country_id) VALUES (
          2, 'Robbin', 2
      );
      
      INSERT INTO person (person_id, name, country_id) VALUES (
          3, 'Jane', 3
      );
      
    • 此時再執(zhí)行一下上面的更新語句
      -- 由于指定了級聯(lián)更新,所以會發(fā)現(xiàn)下面的語句執(zhí)行成功了笤成,不但更改了country表中的數(shù)據(jù)评架,連帶著person表中的數(shù)據(jù)也一并更新了
      UPDATE country
      SET country_id = 4
      WHERE country_id = 2
      
    • 上面就是級聯(lián)更新的效果
  • 另一類對違反完整性約束的處理

    • SET DEFAULT
      • 一旦違反完整性約束,就將參照域(此處為country_id)設(shè)置為默認(rèn)值
    • SET NULL
      • 一旦違反完整性約束炕泳,就將參照域(此處為country_id)設(shè)置為NULL
    • 舉個栗子
      • 執(zhí)行下面的構(gòu)造
        DROP TABLE person;
        DROP TABLE country;
        CREATE TABLE country(
          country_id INTEGER PRIMARY KEY ,
          country_name VARCHAR(20)
        );
        
        CREATE TABLE person(
          person_id INTEGER PRIMARY KEY ,
          name VARCHAR(20),
          country_id INTEGER FOREIGN KEY REFERENCES country(country_id)
            ON DELETE SET NULL
        );
        
        INSERT INTO country (country_id, country_name) VALUES (
            1, 'China'
        );
        INSERT INTO country (country_id, country_name) VALUES (
            2, 'English'
        );
        INSERT INTO country (country_id, country_name) VALUES (
            3, 'America'
        );
        
        INSERT INTO person (person_id, name, country_id) VALUES (
            1, 'Sunny', 1
        );
        
        INSERT INTO person (person_id, name, country_id) VALUES (
            2, 'Robbin', 2
        );
        
        INSERT INTO person (person_id, name, country_id) VALUES (
            3, 'Jane', 3
        );
        
      • 然后執(zhí)行下面的刪除操作
        -- 下面的刪除操作成功執(zhí)行纵诞,但不是級聯(lián)刪除,而是把person表中原來country_id=1的數(shù)據(jù)的country_id都設(shè)成了NULL
        DELETE country
        WHERE country_id = 1
        

延遲檢查

這是由于數(shù)據(jù)庫默認(rèn)是在執(zhí)行每一條SQL語句的時候都進行完整性約束的檢查培遵,導(dǎo)致有些操作無法進行浙芙。延遲操作就將完整性約束的檢查延遲到了事務(wù)結(jié)束的時候檢查(大多數(shù)數(shù)據(jù)庫不支持,比如SQL Server籽腕, 但Oracle數(shù)據(jù)支持)

  • 由于不常用嗡呼,SQL Server也不支持,這里就講一下概念皇耗,不舉實際的栗子了南窗。

  • 假設(shè)上面的例子表中沒有指定延遲檢查

    • 執(zhí)行下面的語句
    -- 執(zhí)行下面兩條語句是會出錯的,因為插入第一條數(shù)據(jù)的時候郎楼,由于完整性約束的存在万伤,要求country表中要有country_id=4的數(shù)據(jù),但是這個數(shù)據(jù)目前還不存在(所以只要先執(zhí)行第二條語句呜袁,這兩個語句才能成功執(zhí)行)
    INSERT INTO person (person_id, name, country_id) VALUES (
        4, 'Jerry', 4
    );
    INSERT INTO country (country_id, country_name) VALUES (
        4, 'France'
    );
    
  • 而如果指定了延遲檢查呢

    • 執(zhí)行下面語句(下面兩個語句處于同一個事務(wù)中)
    -- 由于是延遲檢查壕翩,所以兩條數(shù)據(jù)都插入完,執(zhí)行commit傅寡,事務(wù)結(jié)束時才進行完整性約束的檢查放妈,此時就不會出錯,可以正常插入
    INSERT INTO person (person_id, name, country_id) VALUES (
        4, 'Jerry', 4
    );
    INSERT INTO country (country_id, country_name) VALUES (
        4, 'France'
    );
    COMMIT
    
  • 雖然SQL標(biāo)準(zhǔn)中有這個概念荐操,但是大多數(shù)數(shù)據(jù)庫沒有提供支持芜抒,并且不常用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市托启,隨后出現(xiàn)的幾起案子宅倒,更是在濱河造成了極大的恐慌,老刑警劉巖屯耸,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拐迁,死亡現(xiàn)場離奇詭異,居然都是意外死亡疗绣,警方通過查閱死者的電腦和手機线召,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來多矮,“玉大人缓淹,你說我怎么就攤上這事哈打。” “怎么了讯壶?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵料仗,是天一觀的道長。 經(jīng)常有香客問我伏蚊,道長立轧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任躏吊,我火速辦了婚禮氛改,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘颜阐。我一直安慰自己,他們只是感情好吓肋,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布凳怨。 她就那樣靜靜地躺著,像睡著了一般是鬼。 火紅的嫁衣襯著肌膚如雪肤舞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天均蜜,我揣著相機與錄音李剖,去河邊找鬼。 笑死囤耳,一個胖子當(dāng)著我的面吹牛篙顺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播充择,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼德玫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了椎麦?” 一聲冷哼從身側(cè)響起宰僧,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎观挎,沒想到半個月后琴儿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡嘁捷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年造成,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雄嚣。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡谜疤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情夷磕,我是刑警寧澤履肃,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站坐桩,受9級特大地震影響尺棋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜绵跷,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一膘螟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧碾局,春花似錦荆残、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至像啼,卻和暖如春俘闯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背忽冻。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工真朗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人僧诚。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓遮婶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親湖笨。 傳聞我的和親對象是個殘疾皇子蹭睡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容