刪除這件事,不只是個功能,根本是一門藝術啊!重點是只刪你該刪的,千萬別多刪(不小心刪掉的資料,晚上做夢都會被嚇醒)。今天我們就來學怎麼優雅又正確地刪資料!
刪除資料,就是把一或多筆已經不符合商業邏輯或系統需求的資料列從資料表移除。舉例來說,你可能要刪掉已經畢業的學生,或是那些,嗯,嚴重違反校規的學生資料。又或者,你只是想清理資料表,只留下最新的資訊。
刪除資料這個操作,常見在以下幾種情境:
- 刪除已經不活躍的使用者資料。
- 清空暫存資料的資料表。
- 刪除重複的資料。
- 根據特定商業邏輯,刪除過時的資料。
DELETE 指令語法
要刪資料,我們用 DELETE 指令。基本語法長這樣:
DELETE FROM 資料表
WHERE 條件;
重點說明:
DELETE FROM— 關鍵字,告訴 SQL 要從哪個資料表刪資料。- 資料表 — 你要刪資料的那個表的名字。
WHERE 條件— 用來篩選要刪哪些資料列的條件。你可以用比較運算子、邏輯運算子(AND、OR、NOT),甚至子查詢都可以。
舉例:假設我們有個 students 資料表,要刪掉 ID = 5 的學生:
DELETE FROM students
WHERE id = 5;
這個查詢會從 students 資料表刪掉 id 欄位等於 5 的那一列。
注意: 如果你忘記寫 WHERE 條件,PostgreSQL 會把 所有資料列 都刪掉。這種失誤在 production 系統可是災難級的。
刪除資料表所有資料列
如果你真的要把整個資料表的資料都刪掉,可以直接下沒有 WHERE 條件的查詢。例如:
DELETE FROM students;
這個查詢會把 所有資料 都從 students 資料表刪掉。但資料表的結構還在,只是裡面變空的。
另一種選擇:TRUNCATE
要刪掉整個資料表的所有資料,也可以用 TRUNCATE 指令。它比 DELETE 快,因為不會一筆一筆記錄到 transaction log。舉例:
TRUNCATE TABLE students;
DELETE 跟 TRUNCATE 的差異:
DELETE會把每一筆刪除都記錄到 transaction log,所以可以 rollback。TRUNCATE不支援WHERE條件,也不會一筆一筆記錄,速度快但彈性較低。
如果你只是要清空資料表,TRUNCATE 很適合。但如果你只想刪部分資料,或想要有 rollback 的彈性,還是用 DELETE 比較好。
用複雜條件刪資料
DELETE 的條件不只可以很簡單,也可以很複雜,像是用邏輯運算子(AND、OR、NOT)或子查詢。來看個例子。
例子 1:刪多筆資料 刪掉所有年齡大於 30 歲,且最近 3 個月沒來上課的學生:
DELETE FROM students
WHERE age > 30 AND last_attendance_date < (CURRENT_DATE - INTERVAL '3 months');
這個查詢只會刪掉同時符合兩個條件的學生。
例子 2:用子查詢刪資料
假設我們有個 failed_students 資料表,裡面存放因學業不及格被退學的學生 id。我們要從主資料表 students 把他們刪掉:
DELETE FROM students
WHERE id IN (SELECT student_id FROM failed_students);
這裡子查詢會回傳所有 failed_students 裡的 student_id,然後 DELETE 會把 students 裡對應的資料列刪掉。
小建議
在你真的要刪資料前,先寫個 SELECT 查查你會刪掉哪些資料。確定沒問題,再把 SELECT 換成 DELETE,這樣就會刪掉剛剛查到的那些資料。
實戰範例
假設有個 id = 7 的學生決定轉學,我們要把他的資料從資料表刪掉:
DELETE FROM students
WHERE id = 7;
執行完後,查一下資料表,確認資料真的被刪掉:
SELECT * FROM students WHERE id = 7;
如果查不到 id = 7 的資料,代表刪除成功啦!
警告跟常見錯誤
忘記 WHERE 條件
用 DELETE 最常見的錯誤,就是忘記寫 WHERE。這會導致 整個資料表 都被清空,超級慘。一定要在執行前檢查你的查詢。
來看個健忘造成的慘劇:
DELETE FROM students;
-- 錯誤!全部學生都被刪了。
為了避免這種悲劇,建議你每次要 DELETE 前,先用 SELECT 測試一下 WHERE 條件。例如:
SELECT * FROM students WHERE id = 5;
如果查詢結果沒問題,就可以放心執行 DELETE。
刪除關聯資料
如果資料表有外鍵(FOREIGN KEY),刪資料時可能會出錯。這通常是因為你要刪的那筆資料跟其他表有關聯。舉例來說,如果學生有選課紀錄在 enrollments 資料表,PostgreSQL 不會讓你直接從 students 刪掉他。
這時你可以:
- 在建立外鍵時用
ON DELETE CASCADE,讓刪除自動 cascade。 - 手動先刪掉關聯資料,再刪主資料表的資料。
手動刪關聯資料的範例:
-- 先從 enrollments 刪掉 id = 5 的學生
DELETE FROM enrollments
WHERE student_id = 5;
-- 再刪掉 students 裡 id = 5 的學生
DELETE FROM students
WHERE id = 5;
搭配 transaction 刪資料
如果是很重要的刪除操作,建議用 transaction。這樣如果出錯可以 rollback。
transaction 刪除範例:
BEGIN;
DELETE FROM students
WHERE id = 42;
-- 查查結果
SELECT * FROM students WHERE id = 42;
-- 沒問題就 commit
COMMIT;
-- 有問題就 rollback
-- ROLLBACK;
更多 transaction 的細節,下次講座再聊 :P
GO TO FULL VERSION