PostgreSQL 进阶教程 1-1 CASE表达式

文章介绍了SQL中的CASE表达式,包括简单CASE和搜索CASE的使用,强调了两者在数据转换和统计中的作用。通过示例展示了如何用CASE表达式将区域编码转换为新的分类,并统计不同类别的人口数量。同时,文章提到了在PostgreSQL/MySQL中,GROUPBY可以直接引用SELECT中的别名,但不推荐这种做法。最后,文章给出了一个用CASE表达式一次性完成不同条件统计的例子,对比了使用WHERE和UNION的传统方法。

[toc]

第1章 神奇的SQL

1-1 CASE表达式

1-1.1 CASE表达式

简单CASE表达式

CASE sex
    WHEN '1' THEN '男',
    WHEN '2'THEN '女'
    ELSE '其他' 
    END

搜索CASE表达式

CASE WHEN sex ='1' THEN '男'
     WHEN sex ='2' THEN '女'
     ELSE '其他'
     END

两者的执行结果是相同的。简单CASE表达式正如其名,能实现的事比较简单。
简单CASE能做到的事情,搜索CASE表达式也能做到,所以尽量用搜索CASE表达式来写。

注意事项:

  1. 统一各分支返回的数据类型(不要出现某分支返回数值,另一分支返回字符串)
  2. 不要忘了写 END (绝大部分未写END导致的错误)
  3. 养成写 ELSE 子句的习惯(如果不写ELSE,返回值为NULL,如果语法有错,不易查找原因。)
将已有编号方式转换为新的方式并统计

例如有一张表,来统计北京不同地区的人口数量,想要将要以不同郊区的人口数量来统计。

在这里插入图片描述

首先按照Code1.01进行数据环境

Code 1.01

CREATE TABLE code1_01
(area VARCHAR(32) NOT NULL,
population INTEGER NOT NULL);

INSERT INTO code1_01 VALUES 
('东城',25000),('西城',35000),('昌平',6000),('大兴',5000),('怀柔',1000),('密云',1400);

用简单CASE表达式:
Code 1.02

SELECT CASE area
    WHEN  '东城' THEN '市区'
    WHEN  '西城' THEN '市区'
    WHEN  '昌平' THEN '近郊'
    WHEN  '大兴' THEN '近郊'
    WHEN  '怀柔' THEN '远郊'
    WHEN  '密云' THEN '远郊'
    ELSE '其他' 
    END AS area,
    SUM(population)
FROM code1_01
GROUP BY  CASE area
    WHEN  '东城' THEN '市区'
    WHEN  '西城' THEN '市区'
    WHEN  '昌平' THEN '近郊'
    WHEN  '大兴' THEN '近郊'
    WHEN  '怀柔' THEN '远郊'
    WHEN  '密云' THEN '远郊'
    ELSE '其他' 
    END
;

用搜索CASE表达式

Code1.03

SELECT CASE 
    WHEN area = '东城'THEN '市区'
    WHEN area = '西城'THEN '市区'
    WHEN area = '昌平'THEN '近郊'
    WHEN area = '大兴'THEN '近郊'
    WHEN area = '怀柔'THEN '远郊'
    WHEN area = '密云'THEN '远郊'
    ELSE '其他' END AS area,
    SUM(population)
FROM code1_01
GROUP BY CASE 
    WHEN area = '东城'THEN '市区'
    WHEN area = '西城'THEN '市区'
    WHEN area = '昌平'THEN '近郊'
    WHEN area = '大兴'THEN '近郊'
    WHEN area = '怀柔'THEN '远郊'
    WHEN area = '密云'THEN '远郊'
ELSE '其他' END;

进一步简化
Code 1.04

SELECT CASE 
    WHEN area IN ('东城','西城')THEN '市区'
    WHEN area IN ('昌平','大兴')THEN '近郊'
    WHEN area IN ('怀柔','密云')THEN '远郊'
    ELSE '其他' END AS area,
    SUM(population)
FROM code1_01
GROUP BY CASE 
    WHEN area IN ('东城','西城')THEN '市区'
    WHEN area IN ('昌平','大兴')THEN '近郊'
    WHEN area IN ('怀柔','密云')THEN '远郊'
ELSE '其他' END;

如果想要得到如下的结果
在这里插入图片描述

Code 1.05

SELECT CASE 
    WHEN population <=5000 THEN  '小型城市'
    WHEN population >5000 AND population<=10000  THEN '中型城市'
    WHEN population >10000  THEN '大型城市'
    ELSE '其他' END AS "城市等级",
count(area) AS "数量"
FROM code1_01
GROUP BY CASE 
    WHEN population <=5000 THEN  '小型城市'
    WHEN population >5000 AND population<=10000  THEN '中型城市'
    WHEN population >10000  THEN '大型城市'
    ELSE '其他' END;

这个方法也很好,但是SELECT和GROUP BY需要写两条一模一样的CASE函数,后期修改容易出错。

但是对于某些关系型数据库(PostgreSQL/MySql)来说可以采取以下写法。

Code 1.06

SELECT CASE 
    WHEN population <=5000 THEN  '小型城市'
    WHEN population >5000 AND population<=10000  THEN '中型城市'
    WHEN population >10000  THEN '大型城市'
    ELSE '其他' END AS "城市等级",
count(area) AS "数量"
FROM code1_01
GROUP BY "城市等级";

正常情况下GROUP BY 语句比SELECT先执行,所以GROUP BY引用SELECT的别名是不符合规定的。
而PostgreSQL/MySql数据库中,在执行GROUP BY 语句中,先会在SELECT进行扫描(不计算),所以在这些数据库中执行,不会报错。
但是不符合SQL规定,所以不建议采取这种方式,但是会提高语句的可读性。

用一条SQL语句进行不同条件的统计

例如如下图,左边的表为数据,想要达到右边的效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dULQa50R-1673180083510)(image/02笔记SQL进阶教程作者MICK/1673163916106.png)]

Code 1.07 创建数据环境

CREATE TABLE poptbl2 
(area VARCHAR(32) NOT NULL,sex char(2) NOT NULL,population INTEGER NOt NULL);

INSERT INTO poptbl2 VALUES 
('东城','1',55),
('东城','2',65),
('西城','1',85),
('西城','2',95),
('海淀','1',78),
('海淀','2',91),
('丰台','1',86),
('丰台','2',71),
('昌平','1',105),
('昌平','2',115),
('房山','1',95),
('房山','2',87),
('密云','1',93),
('密云','2',88),
('平谷','1',92),
('平谷','2',94);

通常做法是利用WHERE语句,形成两个SELECT,并进行UNION。

Code 1.08 利用WHERE

SELECT area,SUM(population) FROM poptbl2 WHERE sex='1' GROUP BY area
UNION
SELECT area,SUM(population) FROM poptbl2 WHERE sex='2' GROUP BY area;

在这里插入图片描述

用这种方法,工作量并没有减少,而且SQL语句也变的很长,而如果用CASE表达式,可以用一条简单的SQL语句搞定。

Code 1.09

SUM(CASE WHEN sex='2' THEN population ELSE 0 END) AS cnt_m,
SUM(CASE WHEN sex='1' THEN population ELSE 0 END) AS cnt_f
FROM poptbl2
GROUP BY area;

在这里插入图片描述

<think> 嗯,用户想了解PostgreSQL里的LEAST函数,我得好好梳理一下这个函数的要点。用户明确问了使用方法和功能,我需要结合之前提供的四个引用片段来组织答案。 引用[2]里明确说了LEAST函数的作用是取参数列表的最小值,还提到所有参数必须能转换成同一类型,空值会被忽略。这点很重要,得放在功能说明的第一条。引用[4]虽然展示的是系统函数示例,但正好能用来对比说明LEAST是常规函数而非系统管理函数。 数据类型转换这个特性需要强调,比如整数和浮点数混用时的情况。参数数量限制也得提,虽然通常可以支持很多参数。空值处理是个易错点,用户可能会疑惑为什么[NULL,2,3]返回2而不是NULL,需要解释清楚"忽略空值"的逻辑。 示例部分准备用三组典型场景:纯数字比较、带空值的比较、跨类型转换比较。特别是第三组要体现自动转换,timestamp和date的混合输入就很合适。引用出处记得标注在相关描述后面。 注意事项部分要区分LEAST和MIN的区别,一个是行内横向比较一个是纵向聚合。另外错误处理场景也得提醒,比如参数全为NULL时返回NULL可能引发的表达式异常。 相关问题设计要注意梯度:基础用法、空值处理、类型转换是核心知识点;GREATEST作为对称函数值得关联;与MIN的对比能加深理解;组合函数应用展现进阶用法。这样应该能覆盖用户可能延伸的疑问点。 最后检查所有引用标记是否准确对应,特别是功能描述部分要明确指向引用[2],数据类型说明参考了引用[2]和[3]的转换逻辑。避免把系统函数的内容混进来,保持答案聚焦在LEAST本身。 </think> PostgreSQL 中的 `LEAST` 函数用于**从一组值中返回最小值**。以下是其详细功能和使用方法: --- ### 核心功能 1. **返回值列表中的最小值** 输入多个参数,`LEAST` 会从中筛选并返回最小的值。 **示例**: ```sql SELECT LEAST(10, 5, 8, 20); -- 返回 5 ``` 2. **严格的类型兼容性要求** - 所有输入参数必须是**相同数据类型**,或属于**同一数据类型类别**(如整数和浮点数可互相转换)。 - 返回值类型与输入参数转换后的最终类型一致[^2]。 **示例**: ```sql SELECT LEAST(3, 1.5, 2.8); -- 整数与浮点数混合,返回 1.5(浮点数) ``` 3. **自动忽略 NULL 值** - 如果参数中包含 `NULL`,`LEAST` 会跳过它们,仅比较非空值。 - **例外**:当所有参数均为 `NULL` 时,返回 `NULL`[^2]。 **示例**: ```sql SELECT LEAST(10, NULL, 8); -- 返回 8(忽略 NULL) SELECT LEAST(NULL, NULL); -- 返回 NULL ``` --- ### 使用方法详解 #### 基础语法 ```sql LEAST(value1, value2, ..., valueN) ``` #### 常用场景示例 1. **数值比较** ```sql SELECT LEAST(-5, 0, 3, 10); -- 结果: -5 ``` 2. **字符/字符串比较**(按字典序) ```sql SELECT LEAST('apple', 'banana', 'cherry'); -- 结果: 'apple' ``` 3. **日期时间比较** ```sql SELECT LEAST('2023-01-01'::DATE, '2023-05-15'::DATE); -- 返回较早日期 ``` 4. **混合类型(需可转换)** ```sql SELECT LEAST(100, '50'::INTEGER, 200.5); -- 字符串 '50' 转为整数,最终返回 50(整数) ``` --- ### 关键注意事项 1. **类型转换失败会报错** 若参数无法统一转换到同一类型(如 `'abc'` 和 `123`),PostgreSQL 将抛出类型错误[^2]。 **错误示例**: ```sql SELECT LEAST('text', 100); -- 错误:无法将文本转为整数 ``` 2. **与聚合函数 `MIN()` 的区别** - `LEAST` 是**横向比较**(单行内多个列/值)。 - `MIN()` 是**纵向聚合**(单列跨多行)。 **对比示例**: ```sql -- LEAST:比较同一行三个字段 SELECT LEAST(price1, price2, price3) FROM products; -- MIN():找 price 列在所有行中的最小值 SELECT MIN(price) FROM products; ``` 3. **参数数量限制** 支持任意数量参数(通常上限为 100 个,取决于 PostgreSQL 版本配置)。 --- ### 应用场景建议 - **动态定价**:从多个供应商价格中选最低价。 - **优先级调度**:取最早可用的时间戳。 - **数据清洗**:将超出范围的值截断到允许的最小值(如 `LEAST(user_input, 100)`)。 --- ### 相关问题 1. 如果 `LEAST` 的参数包含不同类型的日期格式(如 `TIMESTAMP` 和 `DATE`),PostgreSQL 如何处理? 2. 如何在使用 `LEAST` 时显式处理全 `NULL` 参数的情况以避免意外结果? 3. `LEAST` 函数与 `CASE WHEN` 条件语句在取最小值时的性能差异是什么? 4. 能否在 `GREATEST` 函数中嵌套使用 `LEAST`?请举例说明组合场景。 [^1]: PostgreSQL 系统信息函数基础清单。 [^2]: `LEAST` 函数的核心逻辑与类型处理规则。 [^3]: 数据类型转换与函数行为的一致性说明。 [^4]: PostgreSQL 系统函数调用示例(与 `LEAST` 无关,但展示函数调用格式)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值