SQL 表的完整性--約束

--表的完整性

--缺省值
--若表字段未明確聲明缺省值,則默認缺省值爲NULL
--缺省值在表定義中類型後定義的

CREATE TABLE Products (
    product_no integer,
    name text,
    price numeric DEFAULT 9.99
);

DROP TABLE Products;
--序列對象暫時還未創建
/*--nextval()從一個序列對象提供後繼的值
CREATE TABLE Products (
    product_no integer DEFAULT nextval('Products_product_no_seq'),
    name text,
    price numeric 
);*/
--也可以這樣寫

CREATE TABLE Products (
    products_no SERIAL
);
DROP TABLE Products;
--2.約束
--表中數據必須是表達式爲真,否則會引發錯誤
--2.1:檢查約束

CREATE TABLE Products (
    product_no SERIAL,
    name text,
    price numeric CHECK(price > 0)
);
DROP TABLE Products;
--可以給檢查約束設置名字
CREATE TABLE Products (
    product__no SERIAL,
    name text,
    price numeric CONSTRAINT positive_price CHECK(price > 0)
);
DROP TABLE Products;
--2.1.2 表約束 當表中某約束需要綜合引用表中各字段,則需要表約束
CREATE TABLE Products (
    product_no SERIAL,
    name text,
    price numeric CONSTRAINT positive_price CHECK(price > 0),
    discounted_price numeric CONSTRAINT positive_discounted_price CHECK(discounted_price > 0),
    CONSTRAINT price_gt_dicounted CHECK(price > discounted_price)
);
--CONSTRAINT price_gt_discounted引用了其他定義字段且不再字段定義後面,是表約束
DROP TABLE Products;
--字段約束和表約束即檢查約束若無明確指定並不隔絕表達式返回NULL的值,如果需要非空,則需要添加非空約束
--2.2  非空約束
--再字段類型定義後以NOT NULL指定
--非空約束可以看成字段約束的一種等同於 CHECK(column_name IS NOT NULL)但非空約束效率一般更高
CREATE TABLE Products (
    product_no  integer NOT NULL,
    name text  NOT NULL,
    price numeric NOT NULL
);
DROP TABLE Products;
--2.3  唯一約束
--單一字段唯一 寫成字段約束
CREATE TABLE Products (
    product_no integer,
    name text UNIQUE,
    price numeric
);

DROP TABLE Products;
--單一字段唯一 寫成表約束

CREATE TABLE Products (
    product_no integer,
    name text,
    price numeric,
    UNIQUE(name)
);
DROP TABLE Products;
--組合字段唯一  必須表約束

CREATE TABLE Products (
    product_no integer,
    name text,
    price numeric,
    pos integer,
    UNIQUE(name,pos)
);

DROP TABLE Products;
--NULL在多字段唯一約束下被認爲是不等的,所以我們爲了程序的健壯性需要添加非空約束
--給唯一約束命名

CREATE TABLE Products (
    product_no integer,
    name text NOT NULL,
    price numeric,
    pos integer NOT NULL,
    CONSTRAINT product_unique UNIQUE(name,pos)
);
DROP TABLE Products;
--非空約束和唯一約束的組合其實在技術上是等同於主鍵約束的
--2.4 主鍵約束

CREATE TABLE Products (
    product_no integer,
    name text UNIQUE,
    price numeric UNIQUE,
    pos integer,
    PRIMARY KEY (name,pos),
    UNIQUE(name,price)
);

--2.5 外鍵約束 
--使得表中某字段與另一表某字段具有相同行爲 保證了表的參照完整性
--單一字段外鍵
CREATE TABLE Pro_Record (
    pro_name text REFERENCES Products(name),
    price numeric
    --or use under method
);

DROP TABLE Pro_Record;

--組合字段外鍵


CREATE TABLE Pro_Record (
    pro_name text,
    price numeric,
    FOREIGN KEY(pro_name,price) REFERENCES Products(name,price)
);
--引用的單一或組合字段需要滿足唯一約束才能指定爲外鍵
DROP TABLE Pro_Record;
DROP TABLE Products;

--注:外鍵所以引發的刪除問題--更新行爲也是類似
--假如存在學生表Student和Stu_Record表,Student_Record引用了學生表的學號,那麼刪除學生表的某條記錄會有什麼行爲呢?
--下列刪除的定義在後面,寫在這裏是爲了方便調試其行爲
DROP TABLE Student_Record;
DROP TABLE Student;
DROP TABLE DR1;
DROP TABLE DR2;
DROP TABLE R1;
DROP TABLE R2;
CREATE TABLE Student (
    number numeric(8,0) PRIMARY KEY
    --maybe have a lot....
);

CREATE TABLE Student_Record (
    stu_number numeric(8,0) REFERENCES Student(number) --equal to NO ACTION
);

INSERT INTO Student(number) VALUES (20161000),(20162000),(20163000),(20164000);

SELECT * FROM Student;
SELECT * FROM Student_Record;

INSERT INTO Student_Record(stu_number) VALUES (20161000),(20162000),(20163000),(20164000);
--刪除Student存在於Student_Record的值
--缺省行爲  拋出錯誤 刪除操作被撤銷
DELETE FROM Student WHERE number = 20161000;

CREATE TABLE R1 (
    code numeric(8,0) PRIMARY KEY
);

CREATE TABLE DR1 (
    code numeric(8,0) REFERENCES R1(code) ON DELETE RESTRICT
);
CREATE TABLE R2 (
    code numeric(8,0) PRIMARY KEY
);
CREATE TABLE DR2 (
    code numeric(8,0) REFERENCES R2(code) ON DELETE CASCADE
);

INSERT INTO R1(code) VALUES (20161000);
INSERT INTO DR1(code) VALUES (20161000);
INSERT INTO R2(code) VALUES (20161000),(20162000);
INSERT INTO DR2(code) VALUES (20161000);

DELETE FROM R1 WHERE code = 20161000;
DELETE FROM R2 WHERE code = 20161000;

--查看記錄
--CASCADE保證了數據的級聯刪除:即先刪除DR2數據再無障礙的刪除R2數據
--RESTRICT 禁止刪除DR2中存在的數據
SELECT * FROM R1;
SELECT * FROM R2;
SELECT * FROM DR1;
SELECT * FROM DR2;
--RESTRICT 和 默認行爲NO ACTION區別:RESTRICT反應比NO ACTION快,NO ACTION等到事務結束時才反應出錯
--除了NO ACTION CASCADE RESTRICT等行爲外還有 SET NULL 和 SET DEFAULT


--2.6 排他約束
--排他約束:排他約束保證了表中任意兩行的被約束字段必須是約束操作符爲假
CREATE TABLE Price (
    price INT,
    EXCLUDE USING btree(price WITH =) --保證插入的價格不相同
);

INSERT INTO Price(price) VALUES (200);
INSERT INTO Price(price) VALUES (300);
INSERT INTO Price(price) VALUES (200);
SELECT * FROM Price;
DROP TABLE Price;
約束種類 作用 語句
檢查約束/字段約束 通過在字段類型後用[CONSTRAINT CHECK_NAME] CHECK(expression)添加字段約束,使得避免使表達式爲假的髒數據(若無明確指定則無法避免NULL) [CONSTRAINT CHECK_NAME] CHECK(expression)
檢查約束/表約束 通過在表定義中添加[CONSTRAINT CHECK_NAME] CHECK(expression)添加約束,表約束可以引用表中多個字段,而字段約束只能引用自身字段 [CONSTRAINT CHECK_NAME] CHECK(expression)
唯一約束 通過設定唯一約束,使得字段不得相同(NULL除外) [CONSTRAINT CHECK_NAME] UNIQUE(a,b….)
非空約束 使得字段不得爲空 NOT NULL
主鍵 設置主鍵使得字段內各值不能相同(包括NULL) [CONSTRAINT CHECK_NAME]PRIMARY KEY(a,b…)
外鍵 設置外鍵可以使得表A和表B具有參照性,含外鍵的表裏元素必須是引用表的存在的 [CONSTRAINT FOREIGN_KEY_NAME] FOREIGN KEY (a,b…) REFERENCES B(a,b…) {[ON DELETE][ON UPDATE] [NO ACTION / RESTRICT / CASCADE]}/{SET DEFAULT / SET NULL}
排他約束 避免表中任意兩行使得字段操作表達式爲真,若爲真則操作出錯,爲假和NULL可以 [CONSTAINT CHECK_NAME] EXCLUDE UISNG 搜索途徑名(字段名 WITH 操作符)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章