標準 SQL-92 不支援 `DELETE ... JOIN`,標準做法使用子查詢配合 `IN`/`EXISTS` 將外部條件映射為刪除條件。
-- 刪除品種為 'Shitzu' 的所有庫存記錄
DELETE FROM Inventory
WHERE BreedID IN (
SELECT BreedID FROM Breed WHERE BreedName = 'Shitzu'
);
DELETE FROM Inventory i
WHERE EXISTS (
SELECT 1 FROM Breed b
WHERE b.BreedID = i.BreedID
AND b.BreedName = 'Shitzu'
);
-- 1. 驗證將被刪除的資料
SELECT * FROM Inventory
WHERE BreedID IN (SELECT BreedID FROM Breed WHERE BreedName = 'Shitzu');
-- 2. 確認無誤後,執行 DELETE
DELETE FROM Inventory
WHERE BreedID IN (SELECT BreedID FROM Breed WHERE BreedName = 'Shitzu');
絕對不要跳過步驟 1,`DELETE` 無 `WHERE` 或條件錯誤將導致資料永久遺失。
SQL Server、MySQL、PostgreSQL、Oracle (特定語法) 支援:
-- SQL Server / MySQL 語法
DELETE i
FROM Inventory i
JOIN Breed b ON i.BreedID = b.BreedID
WHERE b.BreedName = 'Shitzu';
-- Oracle 需用別名關聯
DELETE FROM Inventory i
WHERE EXISTS (SELECT 1 FROM Breed b WHERE b.BreedID = i.BreedID AND b.BreedName = 'Shitzu');
建議:生產環境優先使用標準 `EXISTS` 子查詢,可移植性最強,優化器成熟。
SQL-92 `DELETE` 單陳述式僅能指定一個目標表。解決方案:
| 場景 | 優化策略 | 索引建議 |
|---|---|---|
| 大量刪除 (百萬列+) | 分批刪除 (每批 5000-10000),迴圈 + `WAITFOR DELAY` 降低鎖升級 | 子查詢條件欄位建立索引 |
| 高併發 OLTP | 使用 `ROWLOCK` 提示避免表鎖;評估 `READ COMMITTED SNAPSHOT` 隔離級別 | 被刪表主鍵 + 外鍵欄位索引 |
| 歸檔後刪除 | 先 `INSERT INTO Archive ... SELECT ...` 再 `DELETE`,同一交易 | 歸檔表分區表按時間分區 |
DECLARE @BatchSize INT = 5000, @RowCount INT = 1;
WHILE @RowCount > 0
BEGIN
DELETE TOP (@BatchSize) FROM Inventory
WHERE BreedID IN (SELECT BreedID FROM Breed WHERE BreedName = 'Shitzu');
SET @RowCount = @@ROWCOUNT;
-- 可選:短暫延遲釋放鎖
WAITFOR DELAY '00:00:00.050';
END;
| 錯誤寫法 | 問題 | 修正 |
|---|---|---|
| `DELETE FROM A, B WHERE A.id = B.id` | 標準 SQL 語法錯誤 | 用子查詢或標準 JOIN 刪除語法 |
| `DELETE FROM A WHERE id IN (SELECT id FROM B)` | 子查詢回傳多欄位 | 子查詢 `SELECT` 單一欄位 |
| 未測試直接刪除生產資料 | 不可逆資料遺失 | 強制執行「先 SELECT 驗證」流程 |
| 子查詢效能差 (全表掃描) | 缺少索引或統計過期 | 建立覆蓋索引,`UPDATE STATISTICS` |
下一篇將進入串行資料類型篇:`CHAR`、`VARCHAR`、`NCHAR`、`NVARCHAR`、`TEXT`、`VARCHAR(MAX)` 儲存機制、排序規則、Unicode 處理與遷移策略。