SQL Server:在单个查询中获取最大与最小记录
获取Patient和Appointment表的最大/最小记录(SQL Server)
首先先确认下你提供的两张表结构,方便理解上下文:
CREATE TABLE Patient ( patientID int, firstName varchar(50) NOT NULL, middleName varchar(50), surName varchar(50) NOT NULL, p_age int NOT NULL, p_gender char(1), p_address varchar(200), p_contact_no int, medicalHistory varchar(500), allergies varchar(200), CONSTRAINT PK_Patient PRIMARY KEY (patientID) ); CREATE TABLE Appointment ( appID int, patientId int, staffId int, appDateTime DateTime, CONSTRAINT PK_Appointment PRIMARY KEY (appID), CONSTRAINT FK_Appointment_Patient FOREIGN KEY (patientId) REFERENCES Patient(patientID) );
接下来分两种常见场景写单个查询,满足你的需求:
场景1:获取整体聚合的最大/最小值(统计类数值)
如果你只是需要统计范围类的数据,比如患者的年龄区间、预约时间的首尾范围,用下面的查询即可,它会返回一行包含所有聚合结果:
SELECT -- 患者年龄相关最值 MAX(p.p_age) AS 最大患者年龄, MIN(p.p_age) AS 最小患者年龄, -- 预约时间相关最值 MIN(a.appDateTime) AS 最早预约时间, MAX(a.appDateTime) AS 最晚预约时间 FROM Patient p LEFT JOIN Appointment a ON p.patientID = a.patientId;
这里用LEFT JOIN是为了确保即使没有预约记录的患者也会被纳入年龄统计,如果只需要统计有预约的患者,换成INNER JOIN即可。
场景2:获取对应最值的完整记录(具体实体信息)
如果需要拿到具体的记录详情(比如最年长患者的姓名、地址,最早预约的患者和医护人员信息),可以用CTE(公共表表达式)+ 排序函数实现,单个查询返回所有目标记录:
WITH 患者年龄排序 AS ( SELECT patientID, firstName, surName, p_age, p_address, -- 按年龄从大到小排序,排名1就是最年长 ROW_NUMBER() OVER(ORDER BY p_age DESC) AS 年龄降序排名, -- 按年龄从小到大排序,排名1就是最年轻 ROW_NUMBER() OVER(ORDER BY p_age ASC) AS 年龄升序排名 FROM Patient ), 预约时间排序 AS ( SELECT appID, patientId, staffId, appDateTime, -- 按时间从早到晚排序,排名1就是最早预约 ROW_NUMBER() OVER(ORDER BY appDateTime ASC) AS 时间升序排名, -- 按时间从晚到早排序,排名1就是最晚预约 ROW_NUMBER() OVER(ORDER BY appDateTime DESC) AS 时间降序排名 FROM Appointment ) -- 合并四类记录 SELECT '最年长患者' AS 记录类型, patientID AS 患者ID, CONCAT(firstName, ' ', surName) AS 患者姓名, p_age AS 年龄, p_address AS 地址, NULL AS 预约ID, NULL AS 医护人员ID, NULL AS 预约时间 FROM 患者年龄排序 WHERE 年龄降序排名 = 1 UNION ALL SELECT '最年轻患者' AS 记录类型, patientID AS 患者ID, CONCAT(firstName, ' ', surName) AS 患者姓名, p_age AS 年龄, p_address AS 地址, NULL AS 预约ID, NULL AS 医护人员ID, NULL AS 预约时间 FROM 患者年龄排序 WHERE 年龄升序排名 = 1 UNION ALL SELECT '最早预约' AS 记录类型, p.patientID AS 患者ID, CONCAT(p.firstName, ' ', p.surName) AS 患者姓名, NULL AS 年龄, NULL AS 地址, a.appID AS 预约ID, a.staffId AS 医护人员ID, CONVERT(VARCHAR, a.appDateTime, 120) AS 预约时间 FROM 预约时间排序 a JOIN Patient p ON a.patientId = p.patientID WHERE a.时间升序排名 = 1 UNION ALL SELECT '最晚预约' AS 记录类型, p.patientID AS 患者ID, CONCAT(p.firstName, ' ', p.surName) AS 患者姓名, NULL AS 年龄, NULL AS 地址, a.appID AS 预约ID, a.staffId AS 医护人员ID, CONVERT(VARCHAR, a.appDateTime, 120) AS 预约时间 FROM 预约时间排序 a JOIN Patient p ON a.patientId = p.patientID WHERE a.时间降序排名 = 1;
小提示
如果存在多个并列的最值(比如有两个患者都是20岁,同为最年轻),上面的查询只会返回其中一条。如果需要返回所有并列记录,把ROW_NUMBER()换成RANK()即可。
内容的提问来源于stack exchange,提问作者u_u-de
相关产品推荐
相关产品推荐

