如何编写SQL查询筛选过去一年每月均有预订的客户信息
找出过去一年每月都有预订的客户

先看你的需求:要找出过去一年中每个月都有预订记录的客户,并展示他们的全部信息。你提到想用分组统计月份数的思路是对的,但现有代码的方向有点偏——你直接按月份分组了,这样没法关联到具体的客户,而且SELECT *和GROUP BY DATEPART(MONTH, ...)的组合在大多数SQL引擎里是不合法的(分组后只能选分组列或聚合函数)。
下面给你一步步拆解实现方法:
核心思路
要确认一个客户是否每个月都有预订,我们需要:
- 先过滤出过去一年的预订记录(避免包含更早的数据干扰统计)
- 按客户分组,统计该客户有多少个不同的月份产生了预订
- 筛选出月份数等于12的客户(因为一年12个月,每个月都有就刚好12个不同月份)
- 最后关联客户表和个人表,获取这些客户的全部信息
具体SQL实现
-- 第一步:先统计符合条件的客户ID WITH CustomerMonthlyReservations AS ( SELECT Reserva.CEDULA, -- 统计该客户过去一年有多少个不同的预订月份 COUNT(DISTINCT DATEPART(MONTH, Reserva.FECHAINICIO)) AS MonthCount FROM Reserva -- 筛选过去一年的预订记录,这里用DATEADD确保范围准确 WHERE Reserva.FECHAINICIO >= DATEADD(YEAR, -1, GETDATE()) AND Reserva.FECHAINICIO < GETDATE() GROUP BY Reserva.CEDULA -- 只保留每个月都有预订的客户(12个不同月份) HAVING COUNT(DISTINCT DATEPART(MONTH, Reserva.FECHAINICIO)) = 12 ) -- 第二步:关联获取客户的全部信息 SELECT Persona.*, Cliente.* FROM Persona INNER JOIN Cliente ON Persona.CEDULA = Cliente.CEDULA INNER JOIN CustomerMonthlyReservations ON Cliente.CEDULA = CustomerMonthlyReservations.CEDULA;
代码说明
- CTE部分:
CustomerMonthlyReservations先筛选过去一年的预订,按客户分组后统计不同月份的数量,用HAVING子句留下月份数为12的客户。 - 关联查询:把筛选出的客户ID和
Persona、Cliente表关联,就能拿到这些客户的全部信息了。 - 日期过滤:用
DATEADD(YEAR, -1, GETDATE())获取一年前的今天,确保只统计过去12个月的数据,避免跨年的重复月份干扰(比如去年1月和今年1月会被算成同一个月份,但我们只需要过去连续12个月)。
如果你的SQL引擎不支持CTE(比如某些老版本),也可以用子查询的方式实现:
SELECT Persona.*, Cliente.* FROM Persona INNER JOIN Cliente ON Persona.CEDULA = Cliente.CEDULA INNER JOIN ( SELECT Reserva.CEDULA FROM Reserva WHERE Reserva.FECHAINICIO >= DATEADD(YEAR, -1, GETDATE()) AND Reserva.FECHAINICIO < GETDATE() GROUP BY Reserva.CEDULA HAVING COUNT(DISTINCT DATEPART(MONTH, Reserva.FECHAINICIO)) = 12 ) AS QualifiedCustomers ON Cliente.CEDULA = QualifiedCustomers.CEDULA;
另外要注意:如果客户在同一个月有多次预订,COUNT(DISTINCT ...)会确保只算一次这个月份,这样统计的是有预订的不同月份数,而不是总预订次数,这正是我们需要的。
内容的提问来源于stack exchange,提问作者Camilo
相关产品推荐
相关产品推荐

