最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

PostgreSQL中NULL陷阱的排除過濾指南

 更新時(shí)間:2026年05月17日 14:49:12   作者:倒流時(shí)光三十年  
文章講述了在SQL中處理NULL值時(shí)遇到的常見問題,尤其在使用三值邏輯時(shí)容易出現(xiàn)問題,通過具體例子展示了如何避免隱式過濾NULL值,并提出了清晰的解決方案,同時(shí),還列舉了其他常見的NULL值陷阱,并提供了快速驗(yàn)證字段NULL情況的方法,需要的朋友可以參考下

一、背景:看似簡單的需求

在一次數(shù)據(jù)集成任務(wù)中,遇到了這樣一個(gè)業(yè)務(wù)過濾需求:

當(dāng)銷售區(qū)域?yàn)?quot;拉美(LA)"時(shí),需要排除 region = 'BR' 并且 order_status = 'CANCELED' 的訂單數(shù)據(jù)。但有一個(gè)特別要求:如果這兩個(gè)字段中任意一個(gè)為 NULL,該行數(shù)據(jù)必須保留。

需求很清晰,但實(shí)際寫 SQL 時(shí),才發(fā)現(xiàn)這里面藏著一個(gè)很經(jīng)典的坑——SQL 的 NULL 三值邏輯。

二、最初的寫法及其隱患

直覺上,"排除某個(gè)組合"會寫成:

AND NOT (region = 'BR' AND order_status = 'CANCELED')

這段 SQL 在大多數(shù)場景下跑起來是"正確"的,但它實(shí)際上依賴了 SQL NULL 三值邏輯的一個(gè)"副作用"來保留 NULL 行——這是隱式的,而非明確表達(dá)的意圖,屬于代碼意圖不清晰的隱患。

三、SQL 的三值邏輯(Three-Valued Logic)

這是理解 NULL 問題的基礎(chǔ)。

和編程語言中的布爾兩值邏輯(true / false)不同,SQL 采用的是三值邏輯

含義
TRUE條件成立
FALSE條件不成立
UNKNOWN不確定(NULL 參與運(yùn)算的結(jié)果)

核心規(guī)則:WHERE 子句只保留結(jié)果為 TRUE 的行,UNKNOWNFALSE 都會被過濾。

NULL 參與任何比較運(yùn)算,結(jié)果幾乎都是 UNKNOWN

NULL = 'CANCELED'    → UNKNOWN
NULL != 'CANCELED'   → UNKNOWN
NULL AND TRUE        → UNKNOWN
NOT NULL             → UNKNOWN

四、NOT (A AND B)遇到 NULL 時(shí)的完整分析

還原本文場景,逐行分析:

AND NOT (region = 'BR' AND order_status = 'CANCELED')
regionorder_statusA='BR'B='CANCELED'A AND BNOT(A AND B)WHERE 結(jié)果
'BR''CANCELED'TRUETRUETRUEFALSE? 被排除
'BR''OTHER'TRUEFALSEFALSETRUE? 保留
'US''CANCELED'FALSETRUEFALSETRUE? 保留
NULL'CANCELED'UNKNOWNTRUEUNKNOWNUNKNOWN?? 被過濾!
'BR'NULLTRUEUNKNOWNUNKNOWNUNKNOWN?? 被過濾!
NULLNULLUNKNOWNUNKNOWNUNKNOWNUNKNOWN?? 被過濾!

結(jié)論:NOT (A AND B) 無法保留 NULL!NULL 行因結(jié)果是 UNKNOWN 而被悄悄過濾。

五、為什么"跑起來沒報(bào)錯"就以為是對的?

這正是最危險(xiǎn)的地方。

如果在數(shù)據(jù)質(zhì)量較好的表中,region 字段實(shí)際上從不出現(xiàn) NULL(比如它來自一個(gè)外鍵關(guān)聯(lián),能關(guān)聯(lián)上的必然有值),那這段 SQL 跑起來結(jié)果看上去完全正確。

但一旦:

  • 上游數(shù)據(jù)質(zhì)量下降,出現(xiàn) NULL
  • 表結(jié)構(gòu)調(diào)整,字段變?yōu)榭煽?/li>
  • 換了一張數(shù)據(jù)較"臟"的表

原本"正確"的 SQL 就會悄無聲息地少數(shù)據(jù),排查起來極其困難。

六、正確寫法:顯式聲明 NULL 保留

AND (region IS NULL OR region != 'BR' OR order_status IS NULL OR order_status != 'CANCELED')

邏輯含義:滿足以下任意一個(gè)條件就保留這行數(shù)據(jù):

  1. region 是 NULL
  2. region 不等于 'BR'
  3. order_status 是 NULL
  4. order_status 不等于 'CANCELED'

唯一被排除的,是同時(shí)滿足:region = 'BR' order_status = 'CANCELED'(且兩者都不為 NULL)。

七、三種寫法對比

寫法region=NULL 時(shí)order_status=NULL 時(shí)意圖清晰度推薦
NOT (A AND B)?? 隱式過濾?? 隱式過濾? 差?
A IS NULL OR A!='BR' OR B IS NULL OR B!='CANCELED'? 明確保留? 明確保留? 好?
NOT (A='BR' AND B='CANCELED' AND A IS NOT NULL AND B IS NOT NULL)? 明確保留? 明確保留一般可接受

八、延伸:其他高頻 NULL 陷阱

陷阱 1:!=不等于不能過濾 NULL

-- ? 錯誤:order_status 是 NULL 的行也會被過濾掉
WHERE order_status != 'CANCELED'

-- ? 正確:明確保留 NULL
WHERE order_status != 'CANCELED' OR order_status IS NULL

陷阱 2:NOT IN遇到子查詢有 NULL,全部結(jié)果為空

-- ? 危險(xiǎn):子查詢結(jié)果中有一個(gè) NULL,整個(gè)查詢返回空!
WHERE order_id NOT IN (SELECT order_id FROM blacklist_orders)

-- ? 安全寫法:過濾子查詢中的 NULL
WHERE order_id NOT IN (
    SELECT order_id FROM blacklist_orders WHERE order_id IS NOT NULL
)

-- ? 更推薦:用 NOT EXISTS,天然不受 NULL 影響
WHERE NOT EXISTS (
    SELECT 1 FROM blacklist_orders WHERE blacklist_orders.order_id = t.order_id
)

陷阱 3:聚合函數(shù)中的 NULL

COUNT(*)           -- 統(tǒng)計(jì)所有行,NULL 也計(jì)入
COUNT(order_status) -- 忽略 NULL 行,兩者結(jié)果可能不同!

SUM(amount)        -- NULL 行被忽略,不是當(dāng) 0 處理
AVG(amount)        -- 分母只統(tǒng)計(jì)非 NULL 行,結(jié)果可能偏高

九、快速驗(yàn)證字段是否有 NULL

在寫過濾條件之前,先查一下字段的 NULL 情況,是一個(gè)好習(xí)慣:

-- 檢查字段 NULL 數(shù)量
SELECT
    COUNT(*) AS total,
    COUNT(region) AS region_not_null,
    COUNT(*) - COUNT(region) AS region_null_count,
    COUNT(order_status) AS status_not_null,
    COUNT(*) - COUNT(order_status) AS status_null_count
FROM orders
WHERE geo = 'LA';

十、總結(jié):黃金法則

凡是業(yè)務(wù)上需要"保留 NULL"或"排除 NULL"的場景,必須用 IS NULL / IS NOT NULL 顯式處理,絕不能依賴三值邏輯的副作用。

記住這三句話:

? 顯式優(yōu)于隱式 —— 意圖要寫清楚,不要靠"副作用"
? 先查 NULL 分布 —— 動手寫條件前,先確認(rèn)字段是否可空
? UNKNOWN ≠ FALSE —— NULL 參與運(yùn)算結(jié)果是 UNKNOWN,WHERE 會過濾它

附:本文最終落地的 SQL 寫法(MyBatis XML)

<!-- 只在 geo = LA 時(shí)追加此過濾條件 -->
<if test="geo == 'LA'">
    AND (region IS NULL OR region != 'BR'
         OR order_status IS NULL OR order_status != 'CANCELED')
</if>

讀法:明確排除"region 確實(shí)等于 BR 且 order_status 確實(shí)等于 CANCELED"的行,其余所有行(包括任意字段為 NULL 的行)一律保留。意圖清晰,無歧義,無副作用依賴。

番外:用 COALESCE 能解決嗎? 能,比如這樣:

 <if test="geo == 'LA'">
    and not (COALESCE(region_cd,'') = 'BR' AND COALESCE (order_status,'') = 'CREDIT NOTE')
</if>

為什么本文沒有選擇 COALESCE?

雖然 COALESCE 可行,但在本場景中有幾個(gè)明顯缺點(diǎn):

? 缺點(diǎn) 1:占位符存在歧義風(fēng)險(xiǎn)

? 缺點(diǎn) 2:索引失效,影響查詢性能

? 缺點(diǎn) 3:可讀性可能不太好

反正合適就好吧!

以上就是PostgreSQL中NULL陷阱的排除過濾指南的詳細(xì)內(nèi)容,更多關(guān)于PostgreSQL NULL陷阱排除過濾的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • PostgreSQL流復(fù)制(主從復(fù)制)詳細(xì)教程

    PostgreSQL流復(fù)制(主從復(fù)制)詳細(xì)教程

    本文詳細(xì)介紹了PostgreSQL流復(fù)制技術(shù),流復(fù)制通過WAL日志實(shí)時(shí)同步主從庫數(shù)據(jù),支持異步和同步兩種模式,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-11-11
  • postgresql 中position函數(shù)的性能詳解

    postgresql 中position函數(shù)的性能詳解

    這篇文章主要介紹了postgresql 中position函數(shù)的性能詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 詳解如何定位postgreSQL數(shù)據(jù)庫中未被使用過的索引

    詳解如何定位postgreSQL數(shù)據(jù)庫中未被使用過的索引

    在生產(chǎn)環(huán)境上,由于不規(guī)范的優(yōu)化措施,數(shù)據(jù)庫中可能存在大量的索引,并且相當(dāng)一部分的索引重未被使用過,今天帶大家如何找出這些索引,本文給大家介紹了定位postgreSQL數(shù)據(jù)庫中未被使用過的索引的方法,需要的朋友可以參考下
    2024-03-03
  • shell腳本操作postgresql的方法

    shell腳本操作postgresql的方法

    PostgreSQL支持大部分的SQL標(biāo)準(zhǔn)并且提供了很多其他現(xiàn)代特性,如復(fù)雜查詢、外鍵、觸發(fā)器、視圖、事務(wù)完整性、多版本并發(fā)控制等這篇文章主要介紹了shell腳本操作postgresql,需要的朋友可以參考下
    2022-12-12
  • PostGreSql 判斷字符串中是否有中文的案例

    PostGreSql 判斷字符串中是否有中文的案例

    這篇文章主要介紹了PostGreSql 判斷字符串中是否有中文的案例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 在PostgreSQL中查看有哪些用戶的三種方法

    在PostgreSQL中查看有哪些用戶的三種方法

    本文主要介紹了PostgreSQL查看用戶(角色)的三種方法:SQL查詢系統(tǒng)表(pg_roles/pg_user)、元命令(\du)及pg_shadow視圖,適用于不同場景,如日常管理或腳本處理,并有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2025-09-09
  • 使用Postgresql 實(shí)現(xiàn)快速插入測試數(shù)據(jù)

    使用Postgresql 實(shí)現(xiàn)快速插入測試數(shù)據(jù)

    這篇文章主要介紹了使用Postgresql 實(shí)現(xiàn)快速插入測試數(shù)據(jù),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • postgresql 將逗號分隔的字符串轉(zhuǎn)為多行的實(shí)例

    postgresql 將逗號分隔的字符串轉(zhuǎn)為多行的實(shí)例

    這篇文章主要介紹了postgresql 將逗號分隔的字符串轉(zhuǎn)為多行的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • postgresql關(guān)于like%xxx%的優(yōu)化操作

    postgresql關(guān)于like%xxx%的優(yōu)化操作

    這篇文章主要介紹了postgresql關(guān)于like%xxx%的優(yōu)化操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • Postgresql 查看SQL語句執(zhí)行效率的操作

    Postgresql 查看SQL語句執(zhí)行效率的操作

    這篇文章主要介紹了Postgresql 查看SQL語句執(zhí)行效率的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02

最新評論

湘潭市| 永德县| 萝北县| 瑞昌市| 眉山市| 黔江区| 天津市| 陆丰市| 桐城市| 舞阳县| 凉山| 宝山区| 白玉县| 准格尔旗| 丰城市| 昌黎县| 泽州县| 扎兰屯市| 富源县| 宽城| 迁西县| 黄大仙区| 呼图壁县| 宝应县| 大兴区| 隆林| 新蔡县| 通城县| 桃江县| 西丰县| 堆龙德庆县| 常德市| 河间市| 马龙县| 福州市| 泸西县| 永善县| 斗六市| 齐河县| 区。| 黑龙江省|