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

MySQL COALESCE 空值實(shí)戰(zhàn)詳解

 更新時(shí)間:2026年05月26日 09:05:12   作者:唐青楓  
COALESCE是MySQL里非常常用的空值處理函數(shù),重點(diǎn)講解了其在處理空值、字符串拼接、聚合統(tǒng)計(jì)、LEFTJoin補(bǔ)默認(rèn)值等場(chǎng)景中的使用方法,感興趣的可以了解一下

簡(jiǎn)介

COALESCE 是 MySQL 里非常常用的空值處理函數(shù)。

它的作用很簡(jiǎn)單:從左到右返回第一個(gè)不是 NULL 的值。

最基礎(chǔ)示例:

SELECT COALESCE(NULL, NULL, 'hello', 'world');

結(jié)果:

+-----------------------------------------+
| COALESCE(NULL, NULL, 'hello', 'world') |
+-----------------------------------------+
| hello                                   |
+-----------------------------------------+

因?yàn)?'hello' 是第一個(gè)非 NULL 值,后面的 'world' 不會(huì)作為結(jié)果返回。

如果所有參數(shù)都是 NULL

SELECT COALESCE(NULL, NULL, NULL);

結(jié)果還是:NULL

一句話概括:COALESCE 負(fù)責(zé)給 NULL 找一個(gè)兜底值

它常用于這些場(chǎng)景:

  • 字段為空時(shí)顯示默認(rèn)文字
  • 多個(gè)聯(lián)系方式按優(yōu)先級(jí)取一個(gè)
  • 聚合統(tǒng)計(jì)沒有結(jié)果時(shí)返回 0
  • LEFT JOIN 沒匹配到數(shù)據(jù)時(shí)補(bǔ)默認(rèn)值
  • 拼接字符串時(shí)避免結(jié)果變成 NULL
  • 排序時(shí)給空值一個(gè)排序規(guī)則
  • 批量更新時(shí)保留原值或設(shè)置默認(rèn)值

基本語(yǔ)法

COALESCE(value1, value2, value3, ...)

執(zhí)行規(guī)則:從左到右依次判斷,返回第一個(gè)非 NULL 的值。

示例:

SELECT COALESCE(NULL, 100, 200);

結(jié)果:

100

再看幾個(gè)例子:

SELECT COALESCE('張三', '匿名用戶');

結(jié)果:

張三

SELECT COALESCE(NULL, '匿名用戶');

結(jié)果:匿名用戶

SELECT COALESCE(NULL, NULL);

結(jié)果:

NULL

為什么需要 COALESCE?

SQL 里的 NULL 不是空字符串,也不是 0,而是“不知道、沒有值”。

很多運(yùn)算碰到 NULL 后,結(jié)果也會(huì)變成 NULL

例如:

SELECT 100 + NULL;

結(jié)果:

NULL

字符串拼接也一樣:

SELECT CONCAT('手機(jī)號(hào):', NULL);

結(jié)果:

NULL

這就是 NULL 最容易出問題的地方:只要參與計(jì)算或拼接,整個(gè)結(jié)果可能都沒了。

COALESCE 兜底后:

SELECT 100 + COALESCE(NULL, 0);

結(jié)果:

100

SELECT CONCAT('手機(jī)號(hào):', COALESCE(NULL, '暫無(wú)'));

結(jié)果:

手機(jī)號(hào):暫無(wú)

準(zhǔn)備一組演示數(shù)據(jù)

后面的例子直接使用這幾張表。

DROP TABLE IF EXISTS payments;
DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS departments;

CREATE TABLE departments (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL
);

CREATE TABLE users (
  id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(50),
  nickname VARCHAR(50),
  real_name VARCHAR(50),
  mobile VARCHAR(20),
  backup_mobile VARCHAR(20),
  email VARCHAR(100),
  avatar VARCHAR(255),
  department_id INT,
  last_login_at DATETIME,
  created_at DATETIME NOT NULL,
  INDEX idx_mobile (mobile),
  INDEX idx_department_id (department_id)
);

CREATE TABLE orders (
  id INT PRIMARY KEY AUTO_INCREMENT,
  user_id INT NOT NULL,
  order_no VARCHAR(50) NOT NULL,
  amount DECIMAL(10, 2),
  discount DECIMAL(10, 2),
  sort_no INT,
  updated_at DATETIME,
  created_at DATETIME NOT NULL,
  INDEX idx_user_id (user_id),
  INDEX idx_sort_no (sort_no)
);

CREATE TABLE payments (
  id INT PRIMARY KEY AUTO_INCREMENT,
  order_id INT NOT NULL,
  pay_amount DECIMAL(10, 2),
  refund_amount DECIMAL(10, 2),
  INDEX idx_order_id (order_id)
);

INSERT INTO departments (name) VALUES
('研發(fā)部'),
('銷售部');

INSERT INTO users
(username, nickname, real_name, mobile, backup_mobile, email, avatar, department_id, last_login_at, created_at)
VALUES
('zhangsan', '老張', '張三', '13800000001', NULL, 'zhangsan@example.com', NULL, 1, '2026-01-05 10:00:00', '2026-01-01 10:00:00'),
('lisi', NULL, '李四', NULL, '13900000002', 'lisi@example.com', '/avatar/lisi.png', 2, NULL, '2026-01-02 10:00:00'),
('wangwu', '', '王五', NULL, NULL, 'wangwu@example.com', NULL, NULL, NULL, '2026-01-03 10:00:00'),
(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2026-01-04 10:00:00');

INSERT INTO orders
(user_id, order_no, amount, discount, sort_no, updated_at, created_at)
VALUES
(1, 'A001', 100.00, 10.00, 2, '2026-01-06 10:00:00', '2026-01-05 10:00:00'),
(1, 'A002', 200.00, NULL, NULL, NULL, '2026-01-06 11:00:00'),
(2, 'A003', NULL, NULL, 1, '2026-01-07 10:00:00', '2026-01-07 09:00:00'),
(3, 'A004', 80.00, 5.00, NULL, NULL, '2026-01-08 10:00:00');

INSERT INTO payments (order_id, pay_amount, refund_amount) VALUES
(1, 90.00, NULL),
(2, 200.00, 20.00),
(3, NULL, NULL);

示例一:字段為空時(shí)顯示默認(rèn)值

用戶頭像為空時(shí),顯示默認(rèn)頭像。

SELECT
  id,
  username,
  COALESCE(avatar, '/avatar/default.png') AS show_avatar
FROM users;

結(jié)果類似:

+----+----------+---------------------+
| id | username | show_avatar         |
+----+----------+---------------------+
|  1 | zhangsan | /avatar/default.png |
|  2 | lisi     | /avatar/lisi.png    |
|  3 | wangwu   | /avatar/default.png |
|  4 | NULL     | /avatar/default.png |
+----+----------+---------------------+

這類場(chǎng)景非常適合 COALESCE(字段, 默認(rèn)值)。

示例二:多個(gè)字段按優(yōu)先級(jí)取值

用戶展示名按這個(gè)順序?。?/p>

昵稱 -> 真實(shí)姓名 -> 用戶名 -> 匿名用戶

SQL:

SELECT
  id,
  COALESCE(nickname, real_name, username, '匿名用戶') AS display_name
FROM users;

結(jié)果類似

+----+--------------+
| id | display_name |
+----+--------------+
|  1 | 老張         |
|  2 | 李四         |
|  3 |              |
|  4 | 匿名用戶     |
+----+--------------+

第三行結(jié)果是空字符串,不是 匿名用戶。

原因是:

COALESCE 只判斷 NULL,不會(huì)把空字符串 '' 當(dāng)成 NULL。

如果空字符串也要當(dāng)成空值處理,需要配合 NULLIF。

SELECT
  id,
  COALESCE(
    NULLIF(nickname, ''),
    NULLIF(real_name, ''),
    NULLIF(username, ''),
    '匿名用戶'
  ) AS display_name
FROM users;

這時(shí)第三行會(huì)顯示 王五

示例三:聯(lián)系方式兜底

聯(lián)系方式經(jīng)常不止一個(gè)字段,比如手機(jī)號(hào)、備用手機(jī)號(hào)、郵箱。

SELECT
  id,
  COALESCE(mobile, backup_mobile, email, '無(wú)聯(lián)系方式') AS contact
FROM users;

結(jié)果類似:

+----+---------------------+
| id | contact             |
+----+---------------------+
|  1 | 13800000001         |
|  2 | 13900000002         |
|  3 | wangwu@example.com  |
|  4 | 無(wú)聯(lián)系方式          |
+----+---------------------+

這種寫法比多層 CASE WHEN 更短,也更容易看出優(yōu)先級(jí)。

示例四:金額計(jì)算時(shí)把 NULL 當(dāng)成 0

訂單實(shí)付金額 = 訂單金額 - 優(yōu)惠金額。

直接寫:

SELECT
  order_no,
  amount - discount AS actual_amount
FROM orders;

如果 discountNULL,結(jié)果也會(huì)是 NULL。

推薦寫法:

SELECT
  order_no,
  COALESCE(amount, 0) AS amount,
  COALESCE(discount, 0) AS discount,
  COALESCE(amount, 0) - COALESCE(discount, 0) AS actual_amount
FROM orders;

結(jié)果類似:

+----------+--------+----------+---------------+
| order_no | amount | discount | actual_amount |
+----------+--------+----------+---------------+
| A001     | 100.00 |    10.00 |         90.00 |
| A002     | 200.00 |     0.00 |        200.00 |
| A003     |   0.00 |     0.00 |          0.00 |
| A004     |  80.00 |     5.00 |         75.00 |
+----------+--------+----------+---------------+

金額字段參與計(jì)算時(shí),COALESCE(金額字段, 0) 很常見。

示例五:聚合函數(shù)沒有結(jié)果時(shí)返回 0

SUMAVG 這類聚合函數(shù),在沒有匹配數(shù)據(jù)時(shí)可能返回 NULL。

例如查詢一個(gè)不存在用戶的訂單總額:

SELECT SUM(amount) AS total_amount
FROM orders
WHERE user_id = 999;

結(jié)果:

NULL

使用 COALESCE 兜底:

SELECT COALESCE(SUM(amount), 0) AS total_amount
FROM orders
WHERE user_id = 999;

結(jié)果:

0.00

統(tǒng)計(jì)支付金額、退款金額也很常見:

SELECT
  COALESCE(SUM(pay_amount), 0) AS total_pay_amount,
  COALESCE(SUM(refund_amount), 0) AS total_refund_amount
FROM payments;

注意:COUNT(*) 本身沒有匹配行時(shí)會(huì)返回 0,通常不需要寫成 COALESCE(COUNT(*), 0)。

SELECT COUNT(*) AS order_count
FROM orders
WHERE user_id = 999;

結(jié)果就是:

0

示例六:LEFT JOIN 后補(bǔ)默認(rèn)值

LEFT JOIN 沒匹配到右表數(shù)據(jù)時(shí),右表字段會(huì)是 NULL。

查詢用戶和部門:

SELECT
  u.id,
  COALESCE(u.username, '未命名用戶') AS username,
  COALESCE(d.name, '未分配部門') AS department_name
FROM users AS u
LEFT JOIN departments AS d ON u.department_id = d.id;

結(jié)果類似:

+----+------------+-----------------+
| id | username   | department_name |
+----+------------+-----------------+
|  1 | zhangsan   | 研發(fā)部          |
|  2 | lisi       | 銷售部          |
|  3 | wangwu     | 未分配部門      |
|  4 | 未命名用戶 | 未分配部門      |
+----+------------+-----------------+

這類寫法適合列表頁(yè)、導(dǎo)出報(bào)表、統(tǒng)計(jì)看板。

示例七:拼接字符串時(shí)避免結(jié)果變 NULL

MySQL 的 CONCAT 只要有一個(gè)參數(shù)是 NULL,結(jié)果就會(huì)變成 NULL。

SELECT CONCAT(username, ' / ', mobile) AS user_contact
FROM users;

如果 mobileNULL,整段拼接結(jié)果也會(huì)是 NULL。

使用 COALESCE

SELECT
  CONCAT(
    COALESCE(username, '匿名用戶'),
    ' / ',
    COALESCE(mobile, backup_mobile, email, '無(wú)聯(lián)系方式')
  ) AS user_contact
FROM users;

結(jié)果類似:

+-------------------------------+
| user_contact                  |
+-------------------------------+
| zhangsan / 13800000001        |
| lisi / 13900000002            |
| wangwu / wangwu@example.com   |
| 匿名用戶 / 無(wú)聯(lián)系方式         |
+-------------------------------+

示例八:按更新時(shí)間或創(chuàng)建時(shí)間排序

很多表都有 updated_atcreated_at。

列表排序時(shí),希望優(yōu)先按更新時(shí)間排序;沒有更新時(shí)間時(shí),按創(chuàng)建時(shí)間排序。

SELECT
  order_no,
  updated_at,
  created_at
FROM orders
ORDER BY COALESCE(updated_at, created_at) DESC;

COALESCE(updated_at, created_at) 表示:

有更新時(shí)間就用更新時(shí)間,沒有更新時(shí)間就用創(chuàng)建時(shí)間。

示例九:沒有排序號(hào)的排最后

sort_no 有值的按 sort_no 排,沒有值的排最后。

SELECT
  order_no,
  sort_no
FROM orders
ORDER BY COALESCE(sort_no, 999999) ASC;

結(jié)果類似:

+----------+---------+
| order_no | sort_no |
+----------+---------+
| A003     |       1 |
| A001     |       2 |
| A002     |    NULL |
| A004     |    NULL |
+----------+---------+

這里的 999999 是一個(gè)足夠大的兜底值,讓 NULL 排到后面。

示例十:UPDATE 時(shí)保留舊值

接口更新資料時(shí),有些字段可能沒傳。沒傳的字段通常不希望被更新成 NULL。

假設(shè)傳入的新手機(jī)號(hào)為 @new_mobile,新頭像為 @new_avatar

SET @new_mobile = NULL;
SET @new_avatar = '/avatar/new.png';

UPDATE users
SET
  mobile = COALESCE(@new_mobile, mobile),
  avatar = COALESCE(@new_avatar, avatar)
WHERE id = 1;

含義:

新值不是 NULL 就用新值,新值是 NULL 就保留原字段值。

這種寫法適合“部分字段更新”。不過(guò)如果業(yè)務(wù)允許把字段主動(dòng)清空為 NULL,就不能單純依賴這種寫法,需要區(qū)分“沒傳字段”和“傳了 NULL”。

COALESCE 和 IFNULL 的區(qū)別

IFNULL 是 MySQL 常用函數(shù):

IFNULL(expr1, expr2)

含義:expr1 不是 NULL,返回 expr1;否則返回 expr2。

它只能接收兩個(gè)參數(shù)。

SELECT IFNULL(NULL, '默認(rèn)值');

等價(jià)于:

SELECT COALESCE(NULL, '默認(rèn)值');

COALESCE 可以接收多個(gè)參數(shù):

SELECT COALESCE(nickname, real_name, username, '匿名用戶');

簡(jiǎn)單二選一時(shí),IFNULLCOALESCE 都可以。多級(jí)兜底時(shí),COALESCE 更合適。

另外,COALESCE 是標(biāo)準(zhǔn) SQL,跨數(shù)據(jù)庫(kù)兼容性更好。

COALESCE 和 NULLIF 經(jīng)常一起用

NULLIF(a, b) 的意思是:

如果 a = b,返回 NULL;否則返回 a。

例如:

SELECT NULLIF('', '');

結(jié)果:

NULL

所以它經(jīng)常和 COALESCE 組合,用來(lái)把空字符串、特殊值先轉(zhuǎn)成 NULL,再做兜底。

把空字符串當(dāng)成空值:

SELECT COALESCE(NULLIF(nickname, ''), '匿名用戶') AS display_name
FROM users;

0 當(dāng)成無(wú)效金額:

SELECT COALESCE(NULLIF(amount, 0), 1) AS safe_amount
FROM orders;

上面表示:如果 amount0,先轉(zhuǎn)成 NULL,再兜底為 1。

COALESCE 和 CASE WHEN 的關(guān)系

下面兩段 SQL 邏輯接近。

SELECT COALESCE(nickname, real_name, username, '匿名用戶') AS display_name
FROM users;

CASE WHEN 寫:

SELECT
  CASE
    WHEN nickname IS NOT NULL THEN nickname
    WHEN real_name IS NOT NULL THEN real_name
    WHEN username IS NOT NULL THEN username
    ELSE '匿名用戶'
  END AS display_name
FROM users;

只是判斷 NULL 并按順序兜底時(shí),COALESCE 更短。

如果要寫復(fù)雜條件,比如狀態(tài)、金額區(qū)間、分?jǐn)?shù)等級(jí),CASE WHEN 更適合。

常見坑一:空字符串不是 NULL

SELECT COALESCE('', '默認(rèn)值') AS result;

結(jié)果是空字符串,不是 默認(rèn)值。

因?yàn)椋?/p>

'' 是一個(gè)長(zhǎng)度為 0 的字符串,但它不是 NULL。

如果空字符串也要兜底:

SELECT COALESCE(NULLIF('', ''), '默認(rèn)值') AS result;

結(jié)果:

默認(rèn)值

常見坑二:參數(shù)類型盡量一致

不推薦:

SELECT COALESCE(NULL, 100, '未知');

參數(shù)里既有數(shù)字,又有字符串,后續(xù)參與計(jì)算或排序時(shí)容易引發(fā)隱式類型轉(zhuǎn)換。

推薦保持同一類結(jié)果:

SELECT COALESCE(CAST(score AS CHAR), '未知') AS score_text
FROM users;

或者:

SELECT COALESCE(score, 0) AS score
FROM users;

常見坑三:WHERE 里包字段可能影響索引

不推薦:

SELECT *
FROM users
WHERE COALESCE(mobile, backup_mobile) = '13800000001';

這種寫法把字段包進(jìn)函數(shù)表達(dá)式里,優(yōu)化器更難直接使用普通索引。

可以改成更明確的條件:

SELECT *
FROM users
WHERE mobile = '13800000001'
   OR (mobile IS NULL AND backup_mobile = '13800000001');

如果查詢特別高頻,可以考慮補(bǔ)充合適索引、生成列或在數(shù)據(jù)寫入時(shí)提前維護(hù)一個(gè)統(tǒng)一聯(lián)系方式字段。

常見坑四:不要把缺失數(shù)據(jù)直接偽裝成真實(shí)數(shù)據(jù)

COALESCE 很適合展示兜底,但不一定適合所有統(tǒng)計(jì)場(chǎng)景。

例如平均訂單金額:

SELECT AVG(COALESCE(amount, 0)) AS avg_amount
FROM orders;

這表示:amountNULL 的訂單也按 0 參與平均值計(jì)算。

如果 NULL 的真實(shí)含義是“未知金額”,這樣會(huì)拉低平均值。

另一種寫法:

SELECT AVG(amount) AS avg_amount
FROM orders;

AVG 會(huì)忽略 NULL。

所以統(tǒng)計(jì)時(shí)要先確認(rèn) NULL 的業(yè)務(wù)含義:

NULL 是應(yīng)該當(dāng)作 0,還是應(yīng)該當(dāng)作未知并排除?

這個(gè)區(qū)別會(huì)直接影響報(bào)表結(jié)果。

實(shí)戰(zhàn)建議

  • 展示字段缺省值,用 COALESCE(field, '默認(rèn)值')
  • 多字段優(yōu)先級(jí)取值,用 COALESCE(a, b, c, '兜底值')
  • 金額計(jì)算前,把可為空金額轉(zhuǎn)成 0,例如 COALESCE(discount, 0)
  • SUM 沒有結(jié)果時(shí)返回 0,用 COALESCE(SUM(amount), 0)
  • COUNT(*) 本身會(huì)返回 0,通常不需要再包 COALESCE
  • 空字符串要當(dāng)成空值時(shí),配合 NULLIF(field, '')
  • 只是簡(jiǎn)單二選一,IFNULL 也能用;多級(jí)兜底優(yōu)先用 COALESCE
  • WHERE 中不要隨手把索引字段包進(jìn) COALESCE
  • 參數(shù)返回類型盡量一致,減少隱式轉(zhuǎn)換
  • 統(tǒng)計(jì)場(chǎng)景里先判斷 NULL 的業(yè)務(wù)含義,再?zèng)Q定是否兜底為 0

總結(jié)

COALESCE 的核心就是“按順序找第一個(gè)非 NULL 的值”。

它看起來(lái)只是一個(gè)小函數(shù),但在列表展示、報(bào)表統(tǒng)計(jì)、字符串拼接、多字段兼容、LEFT JOIN 補(bǔ)默認(rèn)值中都非常實(shí)用。

寫 SQL 時(shí),只要遇到“字段可能為空,但結(jié)果不能空”的場(chǎng)景,就可以考慮 COALESCE。同時(shí)要記住兩個(gè)邊界:空字符串不是 NULL,統(tǒng)計(jì)里的 NULL 不一定等于 0。處理好這兩點(diǎn),空值兜底就不容易出錯(cuò)。

到此這篇關(guān)于MySQL COALESCE 空值實(shí)戰(zhàn)詳解的文章就介紹到這了,更多相關(guān)MySQL COALESCE 空值內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

申扎县| 南丹县| 务川| 仪陇县| 青州市| 抚宁县| 曲阳县| 普格县| 侯马市| 油尖旺区| 宜宾县| 神农架林区| 鄄城县| 鹤庆县| 乌鲁木齐市| 江源县| 泰顺县| 平阳县| 墨玉县| 武乡县| 抚宁县| 五莲县| 白城市| 雷州市| 平顶山市| 晋江市| 蒙城县| 海淀区| 霸州市| 集安市| 成武县| 华坪县| 长汀县| 沿河| 修文县| 定远县| 泾源县| 昆明市| 依兰县| 阳东县| 天津市|