今天我们要聊一个更细节但很重要的话题:GREATEST() 和 LEAST() 这俩函数。你会学到怎么从多个列里找最大和最小值,还有最关键的,NULL 到底会怎么影响它们的结果。
如果你曾经在生活里找过最重要的东西(比如爱情、梦想工作或者最好吃的披萨),你肯定能秒懂 GREATEST() 和 LEAST() 是干嘛的。这俩函数就是帮你在一堆“东西”里找最大或者最小的。只不过这里不是披萨,而是 PostgreSQL 里的数字、日期、字符串啥的。
GREATEST()
GREATEST() 会返回你传进去那堆值里最大的一个。
语法:
GREATEST(value1, value2, ..., valueN)
LEAST()
LEAST() 正好相反:它找最小的那个。
语法:
LEAST(value1, value2, ..., valueN)
例子:
假设我们有个表叫 students_scores,里面存着学生三次考试的分数:
| student_id | exam_1 | exam_2 | exam_3 |
|---|---|---|---|
| 1 | 85 | 90 | 82 |
| 2 | NULL | 76 | 89 |
| 3 | 94 | NULL | 88 |
用 GREATEST() 和 LEAST() 来查:
SELECT
student_id,
GREATEST(exam_1, exam_2, exam_3) AS highest_score,
LEAST(exam_1, exam_2, exam_3) AS lowest_score
FROM students_scores;
结果:
| student_id | highest_score | lowest_score |
|---|---|---|
| 1 | 90 | 82 |
| 2 | 89 | NULL |
| 3 | 94 | NULL |
NULL 怎么影响 GREATEST() 和 LEAST()
现在到了最有意思的部分。表里除了正常的值,还可能有 NULL。 你应该知道,NULL 就是个谜一样的存在,代表没数据或者不知道值是多少。 那如果 NULL 混进了 GREATEST() 和 LEAST() 里,PostgreSQL 会怎么处理呢?
NULL 的行为:
在 PostgreSQL 里,GREATEST() 和 LEAST() 有点特殊:它们在找最大/最小值的时候会忽略 NULL。 注意: 只有一种情况会返回 NULL,那就是所有参数都是 NULL。
例子:
SELECT
GREATEST(10, 20, NULL, 5) AS greatest_value,
LEAST(10, 20, NULL, 5) AS least_value;
结果:
| greatest_value | least_value |
|---|---|
| 20 | 5 |
你看,NULL 被直接无视了,函数只看剩下的(10, 20, 5)然后返回最大和最小。
再看个例子,如果所有参数都是 NULL:
例子:
SELECT
GREATEST(NULL, NULL) AS greatest_nulls,
LEAST(NULL, NULL) AS least_nulls;
结果:
| greatest_nulls | least_nulls |
|---|---|
| NULL | NULL |
怎么避免 NULL 带来的坑?
虽然 PostgreSQL 默认会忽略 NULL,但有时候你可能想让 NULL 当成某个具体的值(比如 0 或者别的默认值)来算最大/最小。这种情况就可以用 COALESCE() 函数。
COALESCE(arg1, arg2, ...) 会返回它参数列表里第一个不是 NULL 的值。这样你可以在把值传给 GREATEST() 或 LEAST() 之前,先把 NULL 换成你想要的值。
例子 1:把 NULL 换成 0
比如说,我们想让没分数(NULL)的情况当成 0。那就用 COALESCE() 把它替换掉。
原始表长这样:
| student_id | exam_1 | exam_2 | exam_3 |
|---|---|---|---|
| 1 | 90 | 85 | 82 |
| 2 | NULL | 89 | NULL |
| 3 | NULL | NULL | 94 |
SQL 查询:
SELECT
student_id,
GREATEST(
COALESCE(exam_1, 0),
COALESCE(exam_2, 0),
COALESCE(exam_3, 0)
) AS highest_score,
LEAST(
COALESCE(exam_1, 0),
COALESCE(exam_2, 0),
COALESCE(exam_3, 0)
) AS lowest_score
FROM students_scores;
结果:
| student_id | highest_score | lowest_score |
|---|---|---|
| 1 | 90 | 82 |
| 2 | 89 | 0 |
| 3 | 94 | 0 |
例子 2:把 NULL 换成别的列的值
有时候你不想用固定值(比如 0),而是想用别的列的值。比如 exam_3 没分数时,就用 exam_1 的分数。
SELECT
student_id,
GREATEST(
exam_1,
exam_2,
COALESCE(exam_3, exam_1)
) AS highest_score
FROM students_scores;
假设表是这样的:
| student_id | exam_1 | exam_2 | exam_3 |
|---|---|---|---|
| 1 | 90 | 85 | 82 |
| 2 | NULL | 89 | NULL |
| 3 | 70 | NULL | NULL |
查询结果:
| student_id | highest_score |
|---|---|
| 1 | 90 |
| 2 | 89 |
| 3 | 70 |
实战案例
案例 1:找最大折扣
| order_id | discount_1 | discount_2 | discount_3 |
|---|---|---|---|
| 101 | 5 | 10 | 7 |
| 102 | NULL | 3 | 8 |
| 103 | 15 | NULL | NULL |
| 104 | NULL | NULL | NULL |
你在用 orders 这个表,每个订单可能有三种不同的折扣。你要找每个订单里最大的那个折扣。
SELECT
order_id,
GREATEST(discount_1, discount_2, discount_3) AS max_discount
FROM orders;
结果:
| order_id | max_discount |
|---|---|
| 101 | 10 |
| 102 | 8 |
| 103 | 15 |
| 104 | NULL |
案例 2:找商品最低价
在 products 表里,商品价格有三种货币(USD、EUR、GBP)。你的任务是找出每个商品的最低价。
| product_id | price_usd | price_eur | price_gbp |
|---|---|---|---|
| 1 | 100 | 95 | 80 |
| 2 | NULL | 150 | 140 |
| 3 | 200 | NULL | NULL |
| 4 | NULL | NULL | NULL |
SELECT
product_id,
LEAST(price_usd, price_eur, price_gbp) AS lowest_price
FROM products;
| product_id | lowest_price |
|---|---|
| 1 | 80 |
| 2 | 140 |
| 3 | 200 |
| 4 | NULL |
如果所有价格都是 NULL,结果也是 NULL
用 GREATEST() 和 LEAST() 时常见的坑
坑 1:因为 NULL 得到意外的结果。
前面我们已经详细说了 NULL 在 PostgreSQL 里对 GREATEST() 和 LEAST() 的影响。最大的问题是,有些同学习惯了别的数据库(那种只要有一个 NULL 就全都变 NULL 的),以为 PostgreSQL 也是这样。
怎么踩坑: 你可能会以为只要参数里有 NULL,函数就一定返回 NULL。结果你会不必要地对所有参数都用 COALESCE(),这样反而让 SQL 变复杂还慢,其实 PostgreSQL 里 NULL 本来就会被忽略。
坑 2:用 GREATEST() 和 LEAST() 比较不兼容的类型。
GREATEST() 和 LEAST() 这俩函数本来就是用来比同一种数据类型的值,或者能自动转换的类型。如果你硬要比完全不兼容的类型,肯定报错。
怎么踩坑: 你会收到个报错,说数据类型不兼容。
GO TO FULL VERSION