OpenGauss 医院业务表数据操作-简单查询(2)

教程对应分组与聚合函数运算符两大核心章节,基于医院门诊挂号业务表设计,包含完整语法定义、规则说明、业务场景示例 。


前置准备:业务表与测试数据

1. 操作环境说明

  • 执行用户:普通业务用户 user_hospital

  • 数据库:db_cloud_hospital(云院业务库)

  • gsql提示符:db_cloud_hospital=>

  • 核心业务表:t_outpatient_reg(门诊挂号表,覆盖全量业务场景)

2. 业务表结构定义

-- 门诊挂号表(全量字段适配后续所有示例)
DROP TABLE IF EXISTS t_outpatient_reg;
CREATE TABLE t_outpatient_reg (
    reg_id INT PRIMARY KEY,           -- 挂号ID(主键,唯一标识)
    patient_name VARCHAR(50) NOT NULL, -- 用户姓名
    patient_gender CHAR(1),            -- 用户性别(男/女)
    patient_age INT,                    -- 用户年龄
    patient_phone VARCHAR(20),          -- 用户手机号
    department VARCHAR(50) NOT NULL,   -- 就诊科室
    doctor_name VARCHAR(50),           -- 接诊医
    reg_fee NUMERIC(5,2) NOT NULL,     -- 挂号婓
    reg_time DATE DEFAULT CURRENT_DATE  -- 挂号日期(年月日)
);

3. 测试数据(全量覆盖业务场景)

-- 插入12条挂号测试数据
INSERT INTO t_outpatient_reg
VALUES 
(1001, '张三', '男', 35, '13800138000', '内科', '王医', 25.00, '2026-03-24'),
(1002, '李四', '女', 28, '13900139000', '外科', '李医', 30.00, '2026-03-24'),
(1003, '王五', '男', 45, '13700137000', '儿科', '刘医', 20.00, '2026-03-24'),
(1004, '赵六', '女', 32, '13600136000', '内科', '王医', 25.00, '2026-03-25'),
(1005, '阿七', '男', 52, '13500135000', '外科', '张医', 30.00, '2026-03-25'),
(1006, '孙八', '女', 6, '13400134000', '儿科', '刘医', 20.00, '2026-03-25'),
(1007, '周九', '男', 29, '13300133000', '内科', '郑医', 35.00, '2026-03-25'),
(1008, '吴十', '女', 41, '13200132000', '妇产科', '陈医', 40.00, '2026-03-24'),
(1009, '郑十一', '男', 38, '13100131000', '骨科', '杨医', 30.00, '2026-03-24'),
(1010, '王十二', '女', 24, '13000130000', '皮肤科', '黄医', 22.00, '2026-03-25'),
(1011, '张十三', '男', 58, NULL, '内科', '王医', 25.00, '2026-03-24'),
(1012, '李十四', '女', 33, '13800138001', '外科', NULL, 30.00, '2026-03-25');

一、分组查询与聚合函数

本章节核心解决数据分类统计需求,是医院业务中「科室挂号量统计、收入核算、均值分析」的核心技术手段。

1.1 分组查询(GROUP BY)

1. 核心作用

根据指定字段对查询结果进行分组,字段值相同的记录会被合并为一条数据,是分类统计的基础。

2. 完整语法定义

SELECT [查询选项] 字段名[, ...] | 聚合函数 
FROM 数据表名称 
[WHERE 条件表达式]
GROUP BY 分组字段名[, ...];

3. 核心规则说明

  • SELECT 子句中,非聚合函数的普通字段,必须全部出现在 GROUP BY 子句中(openGauss严格语法规范);

  • 可按单个字段分组,也可按多个字段组合分组;

  • WHERE 子句在分组前执行,用于过滤原始数据。

4. 医院业务场景示例

示例1:单字段分组(按科室分组,查询所有挂号科室)
-- 按科室分组,获取所有有挂号记录的科室列表
SELECT department AS 就诊科室
FROM t_outpatient_reg
GROUP BY department;
示例2:多字段组合分组(按科室+挂号日期分组)
-- 统计每个科室、每天的挂号维度数据
SELECT department AS 就诊科室, reg_time AS 挂号日期
FROM t_outpatient_reg
GROUP BY department, reg_time;

1.2 聚合函数

聚合函数用于对一组值进行运算,最终返回单个统计结果,90%的统计场景都需要聚合函数+分组配合使用

1. 常用聚合函数总览

聚合函数 功能描述 医院业务典型场景
COUNT() 返回参数字段的行数,参数为*时统计总记录数 统计科室挂号量、总就诊人数
SUM() 返回参数字段的数值总和,忽略NULL值 统计科室挂号婓总收入、单日营收
AVG() 返回参数字段的数值平均值,忽略NULL值 统计平均挂号婓、用户平均年龄
MAX() 返回参数字段的最大值 查询最高挂号婓、用户最大年龄
MIN() 返回参数字段的最小值 查询最低挂号婓、用户最小年龄

2. 各函数语法与业务示例

(1)COUNT() 计数函数

语法格式

SELECT COUNT(* | 字段名) FROM 数据表名称 [WHERE 条件];

医院场景示例

-- 1. 统计全院总挂号记录数(包含NULL值行)
SELECT COUNT(*) AS 全院总挂号量 FROM t_outpatient_reg;

-- 2. 统计有手机号的用户挂号数(忽略phone为NULL的行)
SELECT COUNT(patient_phone) AS 有效手机号挂号量 FROM t_outpatient_reg;

-- 3. 统计每个科室的挂号量(分组+聚合配合使用,核心场景)
SELECT department AS 就诊科室, COUNT(reg_id) AS 挂号量
FROM t_outpatient_reg
GROUP BY department;
(2)SUM() 求和函数

语法格式

SELECT SUM(数值字段名) FROM 数据表名称 [WHERE 条件];

医院场景示例

-- 1. 统计全院挂号婓总收入
SELECT SUM(reg_fee) AS 全院挂号婓总收入_元 FROM t_outpatient_reg;

-- 2. 统计内科挂号婓总收入
SELECT SUM(reg_fee) AS 内科挂号婓总收入_元 
FROM t_outpatient_reg
WHERE department = '内科';

-- 3. 统计每个科室的挂号婓总收入(分组+聚合)
SELECT department AS 就诊科室, SUM(reg_fee) AS 科室总收入_元
FROM t_outpatient_reg
GROUP BY department;
(3)AVG() 平均值函数

语法格式

SELECT AVG(数值字段名) FROM 数据表名称 [WHERE 条件];

医院场景示例

-- 1. 统计全院挂号用户的平均年龄
SELECT AVG(patient_age) AS 用户平均年龄 FROM t_outpatient_reg;

-- 2. 统计全院平均挂号婓
SELECT AVG(reg_fee) AS 平均挂号婓_元 FROM t_outpatient_reg;

-- 3. 统计每个科室的平均挂号婓(分组+聚合)
SELECT department AS 就诊科室, AVG(reg_fee) AS 科室平均挂号婓_元
FROM t_outpatient_reg
GROUP BY department;
(4)MAX()/MIN() 极值函数

语法格式

SELECT MAX(字段名), MIN(字段名) FROM 数据表名称 [WHERE 条件];

医院场景示例

-- 1. 查询全院最高/最低挂号婓
SELECT MAX(reg_fee) AS 最高挂号婓_元, MIN(reg_fee) AS 最低挂号婓_元
FROM t_outpatient_reg;

-- 2. 查询就诊用户的最大/最小年龄
SELECT MAX(patient_age) AS 最大就诊年龄, MIN(patient_age) AS 最小就诊年龄
FROM t_outpatient_reg;

-- 3. 统计每个科室的最高挂号婓(分组+聚合)
SELECT department AS 就诊科室, MAX(reg_fee) AS 科室最高挂号婓_元
FROM t_outpatient_reg
GROUP BY department;

1.3 分组后筛选(GROUP BY + HAVING)

1. 核心作用

分组聚合后的结果进行条件筛选,仅返回符合条件的分组。

2. 完整语法定义

SELECT [查询选项] 字段名[, ...] | 聚合函数
FROM 数据表名称 
[WHERE 条件表达式]
GROUP BY 分组字段名[, ...]
HAVING 聚合函数条件表达式;

3. 核心规则:HAVING 与 WHERE 的区别

特性 WHERE 子句 HAVING 子句
执行时机 分组前执行,过滤原始行 分组后执行,过滤分组结果
支持内容 仅能使用表中原始字段,不能使用聚合函数 仅能使用GROUP BY字段、聚合函数
性能 先过滤再分组,数据量小,性能更高 先全量分组再过滤,大数据量性能较低

4. 医院业务场景示例

示例1:筛选挂号量超过2条的科室
SELECT department AS 就诊科室, COUNT(reg_id) AS 挂号量
FROM t_outpatient_reg
GROUP BY department
HAVING COUNT(reg_id) > 2;
示例2:筛选挂号婓总收入超过50元的科室
SELECT department AS 就诊科室, SUM(reg_fee) AS 科室总收入_元
FROM t_outpatient_reg
GROUP BY department
HAVING SUM(reg_fee) > 50;
示例3:WHERE + GROUP BY + HAVING 组合使用
-- 先过滤2026-03-24的挂号记录,再按科室分组,最后筛选挂号量≥2的科室
SELECT department AS 就诊科室, COUNT(reg_id) AS 当日挂号量
FROM t_outpatient_reg
WHERE reg_time = '2026-03-24'
GROUP BY department
HAVING COUNT(reg_id) >= 2;

1.4 分组+排序+限量 综合实战

医院业务高频场景:统计各科室挂号核心指标,按总收入降序取前3名

SELECT 
    department AS 就诊科室,
    COUNT(reg_id) AS 总挂号量,
    SUM(reg_fee) AS 总收入_元,
    AVG(reg_fee) AS 平均挂号婓_元,
    MAX(reg_fee) AS 最高挂号婓_元
FROM t_outpatient_reg
GROUP BY department
ORDER BY 总收入_元 DESC
LIMIT 3;

二、运算符详解

运算符是openGauss中构建条件表达式、完成数据运算的核心基础,本章节覆盖算术、比较、逻辑、赋值、位运算符全类型,所有示例均基于门诊挂号表。

2.1 算术运算符

算术运算符用于数值型数据的数学运算,仅支持数值类型字段(如挂号婓、年龄)。

1. 常用算术运算符与规则

运算符 功能描述 核心规则与注意事项
+ 加法运算 浮点数加减运算,结果精度=参与运算数的最大精度
- 减法运算 同上
* 乘法运算 浮点数乘法运算,结果精度=参与运算数的精度和
/ 除法运算 保留小数结果,除数为0时报错
DIV 整数除法 舍弃小数部分,仅返回整数结果
% / MOD 取模/取余运算 返回除法运算的余数
NULL参与运算 - NULL参与任何算术运算,结果均为NULL

2. 医院业务场景示例

示例1:基础算术运算(挂号婓调价)
-- 1. 挂号婓上调5元,查询调价前后对比
SELECT 
    reg_id, patient_name, department,
    reg_fee AS 原挂号婓,
    reg_fee + 5 AS 上调后挂号婓,
    reg_fee * 1.2 AS 涨价20%后挂号婓,
    reg_fee - 2 AS 便宜2元后挂号婓
FROM t_outpatient_reg;

-- 2. 整数除法与普通除法对比
SELECT 
    reg_fee AS 挂号婓,
    reg_fee / 5 AS 普通除法结果,
    reg_fee DIV 5 AS 整数除法结果
FROM t_outpatient_reg;

-- 3. 取模运算(判断挂号婓是否为偶数)
SELECT reg_fee, reg_fee MOD 2 AS 取模结果
FROM t_outpatient_reg;
示例2:NULL值参与算术运算
-- 手机号为NULL的行,运算结果均为NULL
SELECT patient_name, patient_phone, patient_age + 5 AS 年龄加5
FROM t_outpatient_reg
WHERE patient_phone IS NULL;
示例3:精度运算规则
-- 加法:最大精度3,结果精度3
SELECT 1.2 + 1.400 AS 加法精度示例;
-- 乘法:精度1+3=4,结果精度4
SELECT 1.2 * 1.400 AS 乘法精度示例;

2.2 比较运算符

比较运算符用于条件表达式中的值判断,运算结果仅为3种:1(TRUE真)0(FALSE假)NULL(未知),是WHERE子句的核心组成。

1. 常用比较运算符分类与说明

(1)基础比较运算符
运算符 功能描述 核心注意事项
= 相等判断 与NULL比较结果为NULL
<=> 安全相等判断 支持NULL值比较,两个NULL比较返回1(TRUE)
<> / != 不相等判断 与NULL比较结果为NULL
< 小于判断 -
<= 小于等于判断 -
> 大于判断 -
>= 大于等于判断 -
(2)范围与空值判断运算符
运算符 功能描述
BETWEEN ... AND ... 判断值是否在指定闭区间内(包含首尾值)
NOT BETWEEN ... AND ... 判断值是否不在指定闭区间内
IS NULL 判断值是否为NULL
IS NOT NULL 判断值是否不为NULL
IS 判断值是否为TRUE/FALSE/NULL
IS NOT 判断值是否不是TRUE/FALSE/NULL
(3)模糊匹配与正则运算符
运算符 功能描述 核心通配符/规则
LIKE 模糊匹配查询 %匹配任意长度字符串,_匹配单个字符
NOT LIKE 反向模糊匹配 同上
REGEXP 正则表达式匹配 支持正则语法,`

2. 核心使用注意事项

  1. 字符串、日期类型的值,必须用单引号包裹;

  2. 字符串比较默认不区分大小写;

  3. 数字与字符串比较时,会自动转换为同类型后再比较;

  4. =<>等基础运算符与NULL比较,结果均为NULL,空值判断必须用IS NULL/IS NOT NULL

3. 医院业务场景示例

示例1:基础比较运算符
-- 1. 查询挂号婓等于30元的挂号记录
SELECT * FROM t_outpatient_reg WHERE reg_fee = 30.00;

-- 2. 查询年龄大于40岁的用户挂号记录
SELECT * FROM t_outpatient_reg WHERE patient_age > 40;

-- 3. 查询非内科的挂号记录
SELECT * FROM t_outpatient_reg WHERE department != '内科';

-- 4. 安全相等判断<=>(对比=的区别)
-- 结果:仅返回doctor_name为NULL的行
SELECT * FROM t_outpatient_reg WHERE doctor_name <=> NULL;
-- 结果:无返回(=与NULL比较结果为NULL)
SELECT * FROM t_outpatient_reg WHERE doctor_name = NULL;
示例2:范围判断运算符
-- 1. 查询挂号婓在20-30元之间的记录(包含20和30)
SELECT * FROM t_outpatient_reg 
WHERE reg_fee BETWEEN 20.00 AND 30.00;

-- 2. 查询年龄在25-40岁之外的用户记录
SELECT * FROM t_outpatient_reg 
WHERE patient_age NOT BETWEEN 25 AND 40;

-- 3. 查询挂号日期在2026-03-24至2026-03-25之间的记录
SELECT * FROM t_outpatient_reg 
WHERE reg_time BETWEEN '2026-03-24' AND '2026-03-25';
示例3:空值判断运算符
-- 1. 查询未分配接诊医的挂号记录
SELECT * FROM t_outpatient_reg WHERE doctor_name IS NULL;

-- 2. 查询手机号已填写的用户记录
SELECT * FROM t_outpatient_reg WHERE patient_phone IS NOT NULL;
示例4:模糊匹配运算符(LIKE)
-- 1. 查询所有姓张的用户记录(%匹配任意长度字符)
SELECT * FROM t_outpatient_reg WHERE patient_name LIKE '张%';

-- 2. 查询姓名以"医"结尾的接诊医记录
SELECT * FROM t_outpatient_reg WHERE doctor_name LIKE '%医';

-- 3. 查询姓名为3个字的用户记录(_匹配单个字符,2个_匹配2个字符)
SELECT * FROM t_outpatient_reg WHERE patient_name LIKE '___';

-- 4. 查询手机号以138开头的用户记录
SELECT * FROM t_outpatient_reg WHERE patient_phone LIKE '138%';
示例5:正则匹配运算符(REGEXP)
-- 1. 查询姓名中包含"张"或"李"的用户记录(|表示或)
SELECT * FROM t_outpatient_reg WHERE patient_name REGEXP '张|李';

-- 2. 查询手机号以13开头、以0结尾的用户记录(^开头,$结尾)
SELECT * FROM t_outpatient_reg WHERE patient_phone REGEXP '^13.*0$';

2.3 逻辑运算符

逻辑运算符用于多个条件表达式的组合判断,通常与比较运算符配合使用,运算结果为1(TRUE)0(FALSE)NULL(未知)

1. 常用逻辑运算符

运算符 功能描述 核心运算规则
NOT / ! 逻辑非 返回与操作数相反的结果,真→假,假→真,NULL→NULL
AND / && 逻辑与 所有操作数都为真,结果才为真;有一个为假,结果为假
OR / ` `
XOR 逻辑异或 两个操作数一真一假,结果为真;全真/全假,结果为假

2. NULL值参与逻辑运算的规则

  • AND:含NULL时,另一个操作数为真→结果NULL,另一个为假→结果0;

  • OR:含NULL时,另一个操作数为真→结果1,另一个为假→结果NULL;

  • NOTNOT NULL 结果为NULL。

3. 医院业务场景示例

示例1:AND 逻辑与(多条件同时满足)
-- 查询2026-03-24、内科、挂号婓25元的挂号记录
SELECT * FROM t_outpatient_reg
WHERE reg_time = '2026-03-24' 
  AND department = '内科' 
  AND reg_fee = 25.00;
示例2:OR 逻辑或(满足任一条件即可)
-- 查询内科或外科的挂号记录
SELECT * FROM t_outpatient_reg
WHERE department = '内科' OR department = '外科';
示例3:NOT 逻辑非(反向条件)
-- 查询非儿科、非妇产科的挂号记录
SELECT * FROM t_outpatient_reg
WHERE NOT department IN ('儿科', '妇产科');
示例4:XOR 逻辑异或(二选一)
-- 查询"挂号婓大于30元"和"科室是内科"两个条件仅满足一个的记录
SELECT * FROM t_outpatient_reg
WHERE reg_fee > 30.00 XOR department = '内科';
示例5:多运算符组合使用(括号优先执行)
-- 查询(内科或外科)且(年龄大于30岁)的用户记录
SELECT * FROM t_outpatient_reg
WHERE (department = '内科' OR department = '外科')
  AND patient_age > 30;

2.4 赋值运算符

赋值运算符用于字段更新、变量赋值,openGauss支持两种赋值运算符。

运算符 功能描述 核心使用场景 注意事项
= 双重功能:比较判断 + 赋值 UPDATE语句中给字段赋值 WHERE子句中=为比较运算符,SET子句中=为赋值运算符
:= 仅赋值功能 变量赋值,避免与比较运算符歧义 仅用于赋值场景,不会被识别为比较运算符

业务场景示例

示例1:UPDATE中的赋值运算符
-- 将儿科所有挂号婓上调3元(SET子句中=为赋值运算符)
UPDATE t_outpatient_reg
SET reg_fee = reg_fee + 3
WHERE department = '儿科';

-- WHERE子句中=为比较运算符,SET子句中=为赋值运算符
UPDATE t_outpatient_reg
SET doctor_name = '王医'
WHERE reg_id = 1012;
示例2:变量赋值(:=避免歧义)
-- 声明变量并赋值,:=仅作为赋值,不会被识别为比较
\set total_reg_fee := (SELECT SUM(reg_fee) FROM t_outpatient_reg);
-- 查看变量值
SELECT :total_reg_fee AS 全院总挂号婓;

2.5 位运算符

位运算符针对二进制数的每一位进行运算,openGauss会自动将数值转换为64位无符号整数后逐位运算。

运算符 功能描述 核心运算规则
& 按位与 对应二进制位全为1,结果为1,否则为0
` ` 按位或
^ 按位异或 对应二进制位不同,结果为1,否则为0
<< 按位左移 二进制位左移指定位数,高位丢弃,低位补0
>> 按位右移 二进制位右移指定位数,低位丢弃,高位补0
~ 按位取反 二进制位0变1,1变0

示例

-- 按位与:3(011) & 5(101) = 1(001)
SELECT 3 & 5;
-- 按位或:3(011) | 5(101) = 7(111)
SELECT 3 | 5;
-- 按位左移:3(011) << 1 = 6(110)
SELECT 3 << 1;
-- 按位右移:5(101) >> 1 = 2(10)
SELECT 5 >> 1;

2.6 运算符优先级

运算符优先级决定了表达式中运算的先后顺序,优先级越高,越早执行,完整优先级从高到低如下表:

优先级(从高到低) 运算符
1 括号()(最内层括号优先级最高)
2 !、一元负号-、按位取反~
3 ^
4 */DIV%MOD
5 +-
6 <<>>
7 &
8 `
9 =<=>>=><=<<>!=ISLIKEREGEXP
10 NOT
11 AND
12 XOR
13 OR
14 =(赋值)、:=

核心注意事项

  • 不确定优先级时,使用括号 () 包裹需要优先执行的表达式,是最稳妥、可读性最高的方式;

  • 多条件组合时,括号内的表达式会优先执行,避免因优先级导致的逻辑错误。


三、综合实战案例(全知识点融合)

医院业务需求:统计2026-03-24日,各科室的挂号运营指标,筛选出挂号量≥2、平均挂号婓≥25元的科室,按总收入降序排列。

SELECT 
    department AS 就诊科室,
    COUNT(reg_id) AS 当日挂号量,
    SUM(reg_fee) AS 当日总收入_元,
    AVG(reg_fee) AS 当日平均挂号婓_元,
    MAX(patient_age) AS 最大就诊年龄,
    MIN(patient_age) AS 最小就诊年龄
FROM t_outpatient_reg
WHERE reg_time = '2026-03-24'  -- 分组前过滤日期
GROUP BY department
HAVING COUNT(reg_id) >= 2 AND AVG(reg_fee) >= 25  -- 分组后筛选
ORDER BY 当日总收入_元 DESC;  -- 排序

(注:)

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容