0

我的问题:

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

我希望phoneNo在过去 X 个月中每个月至少出现一次(X 月可以是 1-12 之间的任何一个月)。

例如:获取所有电话号码。在过去 3 个月中每个月至少出现一次。

我正在使用 SQL Server 2005。

4

2 回答 2

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 日以来至少出现一次。我不清楚您是否要坚持该数字出现两次(一次在 5 月和一次在 6 月)或是否一次(在该时间段内一次)。对此的解决方案是将当前日期移回上个月的月底:

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
于 2013-06-16T13:50:28.933 回答
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 个月的更多数据

于 2013-06-16T14:01:36.493 回答