iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 17
1
AI & Data

後端前進PostgreSQL系列 第 17

資料表設計-約束條件-外鍵

  • 分享至 

  • xImage
  •  

昨天介紹的是欄位的約束,現在要來介紹關聯式資料表的約束

之前有提到 主鍵以及外鍵

主鍵就是資料表中,唯一不能為空值的欄位,

之前的文章有提到關聯的方法,可以參考 整理資料表(一) 什麼是關聯式資料表?

今天更深入的了解,主鍵的常見型態,以及外見約束。

id來當主鍵

可以選擇自動遞增型的方式,也有人偏好用UUID(通用唯一識別碼)的格式,以前的購買單機版軟體的時候會有一組序號,讓你可以啟用你購買的軟體,就是類似這樣的ID(不知道會不會現在已經不知道有這種東西了! 哈哈哈xD)

自動遞增型的欄位之前有介紹到,可以不用寫入值,資料表會依照目前的序列自動+1

CREATE TABLE users (
    id bigserial,
    name varchar(255) NOT NULL,
    email varchar(255),
    permission varchar(50),
    created_at timestamp,
    updated_at timestamp,
    CONSTRAINT email_unique UNIQUE (email),
    CONSTRAINT check_permission_in_list CHECK (permission IN ('admin', 'member')),
    CONSTRAINT users_pkey PRIMARY KEY (id)
);

如上方 SQL最後一行,設定 主鍵名稱 users_pkey 指向欄位 id,表示把 id 這個欄位設定為主鍵,必須唯一值且不能為null。

用特別的一段字串或數字來識別這筆資料,稱之為代理的主鍵,就像每個人有身分證,但是身分證只能表示這個人,並無法直接知道這個人的內容,如果全台灣名字不能重複,那也是可以用名字當主鍵,就不用身分證了! 哈哈哈 這舉例有點奇怪應該不太可能發生這樣的設計。

複合式主鍵

也可以結兩個以上的欄位當作主鍵

CREATE TABLE users (
    name varchar(255) NOT NULL,
    email varchar(255),
    address varchar(255),
    permission varchar(50),
    created_at timestamp,
    updated_at timestamp,
    CONSTRAINT email_unique UNIQUE (email),
    CONSTRAINT check_permission_in_list CHECK (permission IN ('admin', 'member')),
    CONSTRAINT users_pkey PRIMARY KEY (name, address)
);

如上方 SQL 假設這個 users 資料表沒有 ID 欄位(我是沒有這樣應用在實際案子中,都會有一個代理鍵 id 來辨識),為了展示複合鍵,不建置 id欄位用 name, address 當複合建,就像最後一行一樣,表示這張資料表中,name 以及 address 的組合只會出現一次,不會有重複。

假設資料表中已經有 王小明,台北市信義區...,如果這時再插入一筆 王小明,台北市信義區... 資料庫就會顯示 users_pkey 已存在的錯誤訊息。

以上是主鍵,外鍵就是可以在另外一張表紀錄跟另外一張表的關聯,這系列一開始的文章有建立 animals 的資料表,表示紀錄動物的資料,每一筆資料如果加上一個欄位 users_id 就可以輕易的對應到 users 資料表中的一個使用者資料,表示使用者的名下有幾隻寵物。

之前有介紹過,當時沒有介紹到外鍵約束,因為想把文章用簡單一點,每一篇不要打太多,不然會懶得看,哈哈哈xD 這也是我最近的體悟,等等題外話的單元再來跟大家說。

外鍵約束

先設想一個情況,假設這個使用者不想使用這個平台了!所以提出了刪除個資的要求,這時候刪除掉 users 這張資料表中的該名使用者,例如 id:王小明,這時候管理資料庫的,因為資料庫複雜,忘記動物的資料,可能有他新建的動物,沒有去刪除,那麼在應用程式讀取資料時,可能會造成,無法去比對動物是哪一位飼主飼養的(莫名其妙變流浪犬!)

所以這時候就要靠外鍵約束的功能了!刪除使用者資料時(刪除使用者 ID:1),顯示錯誤訊息,禁止刪除該使用者,因為他有關聯 animals 的動物資料未刪除,要先刪除動物資料才能刪除該使用者確保資料正確性!

另外示範一下,如果 animals 資料表,插入user_id 不存在於 users 資料表會發生錯誤的範例!

CREATE TABLE users (
    id bigserial,
    name varchar(255),
    CONSTRAINT users_pkey PRIMARY KEY (id)
);

CREATE TABLE animals (
    id bigserial PRIMARY KEY, --建立主鍵也可以這樣寫
    name varchar(255),
    user_id bigint REFERENCES users (id)
);

-- 新增一個使用者名稱為 Victor,若是第一次新建表,應該是會自動寫上 id:1
INSERT INTO users (name)
VALUES ('Victor');

-- 新增一筆動物資料
INSERT INTO animals (name, user_id)
VALUES ('黏黏', 1);

-- 新增一筆動物資料,user_id 不存在於 user 資料表中 將會顯示錯誤!
INSERT INTO animals (name, user_id)
VALUES ('大黑', 2);

上一篇
資料表設計-約束條件
下一篇
添加索引加快查詢速度
系列文
後端前進PostgreSQL30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言