在过去的X个月中,数据每月至少出现一次

时间:2013-06-16 13:21:45

标签: sql sql-server sql-server-2005

我的问题:

表: 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。

2 个答案:

答案 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个月内匹配的更多数据