3. SQL查询基础回顾

在医疗数据查询中,最常用的四类SQL子句几乎覆盖了日常取数的绝大多数场景:SELECT决定“取哪些列”,WHERE决定“取哪些行”,ORDER BY决定“结果如何排序”,LIMIT决定“最多返回多少行”。本节以患者列表(patient)与就诊记录(visit)两张典型表为对象,回顾这四类子句的直接应用方式,并说明它们在真实医疗查询中的组合逻辑。

一、SELECT:明确输出字段,避免 SELECT *

患者列表查询通常需要患者标识、姓名、性别、出生日期、联系电话等字段。假设患者表结构为:patient(patient_id, name, gender, birth_date, phone, id_card, create_time)。查询在院患者基本信息可写为:

SELECT patient_id, name, gender, birth_date, phone
FROM patient;

在工程实践中应尽量避免 SELECT *。原因有三:一是医疗表常包含身份证号、住址等敏感字段,全列返回会扩大数据暴露面;二是宽表返回大量无关列会增加网络传输与内存开销;三是显式列名能让下游使用方清楚知道结果集结构。若确实需要全部字段,也应显式列出,便于审计。

SELECT还支持列别名与简单表达式。例如计算患者年龄(以当前日期为参照):

SELECT patient_id,
       name,
       TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) AS age
FROM patient;

这里 AS age 为结果列命名,方便后续在报表或程序中使用。注意不同数据库的日期函数存在差异,MySQL使用TIMESTAMPDIFF,PostgreSQL可用AGE或DATE_PART,实际项目中应统一到目标数据库方言。

二、WHERE:用条件缩小结果集

WHERE用于过滤行,是医疗查询中使用频率最高的子句。常见条件包括等值判断、范围判断、集合判断与空值判断。例如查询2024年1月1日之后建档的女性患者:

SELECT patient_id, name, gender, birth_date
FROM patient
WHERE gender = 'F'
  AND create_time >= '2024-01-01';

在就诊记录表visit(visit_id, patient_id, visit_date, dept_id, doctor_id, diagnosis, fee)中,查询某科室在指定时间段内的就诊记录:

SELECT visit_id, patient_id, visit_date, diagnosis, fee
FROM visit
WHERE dept_id = 101
  AND visit_date BETWEEN '2024-03-01' AND '2024-03-31';

需要注意几个易错点。第一,字符串与日期常量要用单引号包裹,数值型字段不加引号。第二,BETWEEN ... AND ... 是闭区间,若visit_date含时间部分,需明确边界是否包含当天末尾时刻。第三,判断空值必须用 IS NULL 或 IS NOT NULL,不能用 = NULL,因为NULL参与比较的结果是未知。第四,IN 适合枚举多个科室或诊断编码,LIKE 适合姓名或诊断名称的模糊匹配,但前导通配符 LIKE '%xx' 通常无法使用索引,应谨慎使用。

三、ORDER BY:让结果可预期

ORDER BY用于对结果排序,默认升序ASC,降序需显式写DESC。患者列表常按建档时间倒序,让最新患者排在前面:

SELECT patient_id, name, create_time
FROM patient
ORDER BY create_time DESC;

就诊记录常按就诊日期倒序,同一天再按费用降序:

SELECT visit_id, patient_id, visit_date, fee
FROM visit
ORDER BY visit_date DESC, fee DESC;

多列排序时,数据库先按第一列排序,第一列相同再按第二列排序。排序字段应尽量选择有索引的列,否则大数据量下会产生额外排序开销。此外,若排序列存在NULL,不同数据库对NULL的排序位置默认不同,MySQL中NULL最小,PostgreSQL中NULL最大,跨库迁移时需显式处理。

四、LIMIT:控制返回行数

LIMIT用于限制返回行数,常用于分页与快速预览。查询最近10条就诊记录:

SELECT visit_id, patient_id, visit_date, diagnosis
FROM visit
ORDER BY visit_date DESC
LIMIT 10;

分页查询可写成 LIMIT 20 OFFSET 40,表示跳过前40行取20行,即第3页(每页20条)。需要强调的是,LIMIT必须与ORDER BY配合才有稳定语义。若不加排序,数据库返回的行顺序不保证,分页结果可能重复或遗漏。在医疗场景中,患者列表分页、就诊记录分页都应固定排序键,例如 ORDER BY visit_date DESC, visit_id DESC,用唯一列作为最后排序键消除并列歧义。

五、四类子句的组合执行顺序

一条完整查询中,逻辑执行顺序为:FROM → WHERE → SELECT → ORDER BY → LIMIT。WHERE在分组与排序之前过滤行,ORDER BY在SELECT之后对结果排序,LIMIT最后截断。理解这一顺序有助于判断条件应写在哪一层。例如“查询费用最高的前5条就诊记录”,应先按fee降序排序,再取前5条,而不能在WHERE中写 fee > 某值 来近似替代,因为阈值未知。

患者列表与就诊记录查询:四类子句组合与执行顺序 patient 患者表 patient_id / name gender / birth_date visit 就诊记录表 visit_id / patient_id visit_date / dept_id / fee FROM 确定数据来源表 WHERE 过滤行:性别/日期/科室 SELECT 选择输出列与别名 ORDER BY 排序:日期/费用降序 LIMIT 截断:前N条/分页 结果集示例(就诊记录) visit_id patient_id visit_date fee V20240301 P1001 2024-03-28 320.00 V20240302 P1007 2024-03-27 280.50 V20240303 P1012 2024-03-26 150.00 V20240304 P1003 2024-03-25 96.00 V20240305 P1020 2024-03-24 75.00 按 visit_date DESC 排序,LIMIT 5 关键原则:LIMIT 必须与 ORDER BY 配合;WHERE 过滤行、SELECT 选列、ORDER BY 定序、LIMIT 截断,逻辑顺序不可颠倒。

六、组合应用示例与结果判读

下面给出一个贴近实际工作的组合查询:查询2024年3月内科(dept_id=101)就诊记录中费用最高的前5条,输出就诊号、患者号、就诊日期、诊断与费用。

SELECT visit_id, patient_id, visit_date, diagnosis, fee
FROM visit
WHERE dept_id = 101
  AND visit_date BETWEEN '2024-03-01' AND '2024-03-31'
ORDER BY fee DESC, visit_id DESC
LIMIT 5;

结果判读时关注三点:第一,返回行数是否不超过5;第二,fee是否严格降序;第三,若存在费用相同的记录,visit_id DESC作为第二排序键保证顺序稳定。若查询结果为空,应依次检查WHERE条件中的科室编号、日期范围与数据实际值是否匹配,而不是直接怀疑SQL语法。

在患者列表查询中,若需要按姓名模糊搜索,建议使用 name LIKE '张%' 这类前缀匹配,可借助索引提升效率;若必须使用 %张%,应评估数据量与响应时间,必要时改用全文检索或搜索引擎方案。
医疗数据涉及患者隐私,查询结果不应包含身份证号、住址等非必要敏感字段;导出或展示前应做脱敏处理,并遵循最小必要原则。

掌握SELECT、WHERE、ORDER BY、LIMIT这四类子句的组合方式,是后续学习多表连接、聚合统计与窗口函数的基础。在患者列表与就诊记录这两类高频查询中,先把字段选准、条件写清、排序定稳、行数控好,就能覆盖大量日常取数需求。