SELECT DISTINCT
這段查詢在做什麼?
SELECT DISTINCT document_id
FROM public.fleet_rv_model_manuals
WHERE model_id = $1
AND document_id > 0
AND deleted_at_unix_ms IS NULL
ORDER BY document_id;
語意可以拆成三層:
- 篩選:同一個
model_id、有效的document_id、尚未軟刪除 - 去重:同一份
document_id只保留一筆 - 排序:依
document_id由小到大回傳
常見情境:一張「model ↔ document」關聯表裡,同一個 document_id 可能出現多列(例如不同版本、不同語系、或歷史列),但業務上只要「這台 model 有哪些文件 ID 清單」。
DISTINCT 是什麼?
SELECT DISTINCT 會對結果列做去重:選出的欄位組合若完全相同,只保留一列。
| 寫法 | 效果 |
|---|---|
SELECT document_id | 同一 document_id 出現幾次就回幾列 |
SELECT DISTINCT document_id | 同一 document_id 只回一列 |
只對你 SELECT 出來的欄位去重,不是對整張表的主鍵去重。
用表格看差異
假設 fleet_rv_model_manuals 有這些列($1 = 10):
| model_id | document_id | deleted_at_unix_ms |
|---|---|---|
| 10 | 101 | NULL |
| 10 | 101 | NULL |
| 10 | 102 | NULL |
| 10 | 0 | NULL |
| 10 | 103 | 1710000000000 |
| 20 | 101 | NULL |
套用 WHERE 後剩下:
| document_id |
|---|
| 101 |
| 101 |
| 102 |
再套 DISTINCT:
| document_id |
|---|
| 101 |
| 102 |
最後 ORDER BY document_id 依序回傳 101、102。
被濾掉的原因:
document_id = 0→ 不符合document_id > 0deleted_at_unix_ms有值 → 不符合IS NULL(軟刪除)model_id = 20→ 不符合$1
條件逐行說明
| 條件 | 用意 |
|---|---|
model_id = $1 | 參數化查詢,只看指定 model(避免 SQL injection) |
document_id > 0 | 排除無效/佔位用的 0 |
deleted_at_unix_ms IS NULL | 只取未軟刪除的列 |
DISTINCT document_id | 同一文件只出現一次 |
ORDER BY document_id | 讓結果穩定、可預期 |
PostgreSQL 注意事項
ORDER BY 與 DISTINCT
在 PostgreSQL 裡,ORDER BY 的欄位通常要出現在 SELECT 清單中(或可由其推導)。本例排序的是 document_id,與 SELECT 一致,沒問題。
DISTINCT vs GROUP BY
只取唯一值時,兩者常可互換:
-- 寫法 A
SELECT DISTINCT document_id
FROM public.fleet_rv_model_manuals
WHERE model_id = $1
AND document_id > 0
AND deleted_at_unix_ms IS NULL
ORDER BY document_id;
-- 寫法 B(等價意圖)
SELECT document_id
FROM public.fleet_rv_model_manuals
WHERE model_id = $1
AND document_id > 0
AND deleted_at_unix_ms IS NULL
GROUP BY document_id
ORDER BY document_id;
需要聚合(COUNT、MAX…)時改用 GROUP BY;單純去重用 DISTINCT 較直覺。
DISTINCT ON(PostgreSQL 專用)
若要「每個 document_id 保留一整列,且自訂保留哪一列」,可用 DISTINCT ON:
SELECT DISTINCT ON (document_id) *
FROM public.fleet_rv_model_manuals
WHERE model_id = $1
AND document_id > 0
AND deleted_at_unix_ms IS NULL
ORDER BY document_id, created_at_unix_ms DESC; -- 同 document_id 取最新一列
ORDER BY 的第一個欄位必須與 DISTINCT ON 一致。本篇範例只要 ID 清單,用一般 DISTINCT 即可。
小結
DISTINCT:對選出的欄位組合去重。- 本查詢 = 篩出某 model 的有效文件 → 去重 → 排序。
- 關聯表常會對同一外鍵產生多列,列表 API 回「有哪些 ID」時,
DISTINCT很常見。