我的问题:
表: trans_detail :
PhoneNo | Datetime
01234 | 2013-01-05 20:40:10
01245 | 2013-04-02 21:00:13
05678 | 2013-04-16 01:24:07
04567 | 2013-07-23 07:00:00
etc | etc
我希望获得在过去X个月中每月至少出现一次的所有phoneNo
(X月可以是1-12之间的任何月份)。
例如:获取所有电话号码。在过去3个月中每个月至少出现一次。
我正在使用SQL Server 2005。
答案 0 :(得分:2)
这是一个接近您想要的快速查询:
select PhoneNo
from trans_detail d
where d.datetime >= dateadd(mm, -@X, getdate())
group by PhoneNo
having count(distinct year(datetime)*12+month(datetime)) = @X
where
子句将数据过滤为仅包含过去@X
个月的行。 having
子句通过计算不同月份的数量来检查每个月是否在数据中。
上述版本的查询假设您指的是日历月份。因此,它有边界条件问题。如果你在6月16日运行它,它会回顾一个月,并确保自5月16日以来电话号码至少出现一次。我不清楚你是否想要坚持这个数字出现两次(一次是五月一次,一次是六月一次),或者是一次(一次是在一段时间内)。解决方案是将当前日期移回上个月末:
select PhoneNo
from trans_detail d cross join
(select cast(getdate() - day(getdate) + 1 as date) as FirstOfMonth const
where d.datetime >= dateadd(mm, -@X, FirstOfMonth) and
d.datetime < FirstOfMonth
group by PhoneNo
having count(distinct year(datetime)*12+month(datetime)) = @X
答案 1 :(得分:1)
在这里。前两个CTE将在最近的X个月内找到并准备,第三个CTE是通过电话和月份对您的数据进行分组。最后,只需加入两个并返回匹配行数等于月数的位置。
DECLARE @months INT
SET @Months = 3
;WITH CTE_Dates AS
(
SELECT GETDATE() AS Dt
UNION ALL
SELECT DATEADD(MM,-1,Dt) FROM CTE_Dates
WHERE DATEDIFF(MM, Dt,GETDATE()) < @months-1
)
, CTE_Months AS
(
SELECT MONTH(Dt) AS Mn, YEAR(Dt) AS Yr FROM CTE_Dates
)
, CTE_Trans AS
(
SELECT PhoneNo, MONTH([Datetime]) AS Mn, YEAR([Datetime]) AS Yr FROM dbo.trans_detail
GROUP BY PhoneNo, MONTH([Datetime]), YEAR([Datetime])
)
SELECT PhoneNo FROM CTE_Months m
LEFT JOIN CTE_Trans t ON m.Mn = t.Mn AND m.Yr = t.Yr
GROUP BY PhoneNo
HAVING COUNT(*) = @months
SQLFiddle Demo - 添加了一些将在过去3个月内匹配的更多数据