简体   繁体   中英

Data appear at least once for every month in the last X month

My problem:

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

I want to get all phoneNo that appears at least once for every month in the last X month (X month can be any month between 1-12).

For example: get all phone no. that appears at least once for Every Month in the last 3 months.

I am using SQL Server 2005.

Here is a quick query that comes close to what you want:

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

The where clause filters the data to only include rows in the last @X months. the having clause checks that each month is in the data, by counting the number of distinct months.

The above version of the query assumes that you mean calendar months. So, it has boundary condition problems. If you run it on June 16th, then it looks back one month and makes sure that the phone number appears at least once since May 16th. I am unclear on whether you want to insist that the number appear twice (once in May and once in June) or if once (once during the time period). The solution to this is to move the current date back to the end of the previous month:

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

Here it is. First two CTEs are to find and prepare last X months, third CTE is to group your data by phones and months. At the end just join the two and return where number of matching rows are equal to number of months.

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 - with added some more data that will match for last 3 months

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM