T SQL-统计连续3个月的访问人次

时间:2018-10-05 14:36:59

标签: sql-server tsql date datetime

具有以下数据:

Declare @t Table 
(
Name        Varchar(1),
VisitDate   Date
)

Insert Into @t select 'A','2017-01-05'
Insert Into @t select 'A','2017-03-05'
Insert Into @t select 'A','2017-04-05'
Insert Into @t select 'A','2017-05-05'
Insert Into @t select 'A','2017-08-05'
Insert Into @t select 'B','2017-03-05'
Insert Into @t select 'C','2017-01-05'
Insert Into @t select 'C','2017-02-05'
Insert Into @t select 'C','2017-04-05'
Insert Into @t select 'D','2017-01-05'
Insert Into @t select 'D','2017-02-05'
Insert Into @t select 'D','2017-03-05'
Insert Into @t select 'D','2017-06-05'
Insert Into @t select 'B','2018-01-05'
Insert Into @t select 'B','2018-02-05'
Insert Into @t select 'B','2018-03-05'
Insert Into @t select 'E','2018-01-05'
Insert Into @t select 'E','2018-02-05'
Insert Into @t select 'E','2018-03-05'
Insert Into @t select 'E','2018-06-05'

我需要编写一个查询,该查询将返回任何一年中连续三个月中具有VisitDates的Year&Names。

基于数据,我希望看到:

2017 A
2017 D
2018 B
2018 E

说实话,我不知道从哪里开始使用SQL。

我将不胜感激。

谢谢!

3 个答案:

答案 0 :(得分:1)

通过使用与gaps-and-islands中相同的方法,可以避免联接或多次分析整个数据集。

http://rextester.com/SYHJ40676

WITH
  sequenced AS
(
  SELECT
    Name,
    YEAR(VisitDate)         AS VisitYear,
    MONTH(VisitDate)        AS VisitMonth,
    ROW_NUMBER()
      OVER (PARTITION BY Name, YEAR(VisitDate)
                ORDER BY MONTH(VisitDate)
           )
                            AS MonthSequenceID
  FROM
    @t
  GROUP BY
    Name,
    YEAR(VisitDate),
    MONTH(VisitDate)
)
SELECT DISTINCT
  Name,
  VisitYear
FROM
  sequenced
GROUP BY
  Name,
  VisitYear,
  VisitMonth - MonthSequenceID
HAVING
  COUNT(*) >= 3

答案 1 :(得分:0)

只需将接下来的两个月加入到数据中,然后查看数据的去向:

SELECT DATEPART(year, m1.VisitDate), m1.Name
FROM @t m1
  JOIN @t m2 on m2.Name = m1.Name AND DATEPART(month, m2.VisitDate) = DATEPART(month, m1.VisitDate) + 1
  JOIN @t m3 on m3.Name = m1.Name AND DATEPART(month, m3.VisitDate) = DATEPART(month, m1.VisitDate) + 2

由于在评论中被问到如何解决一年重叠的问题,所以这应该可行:

SELECT DATEPART(year, m1.VisitDate), m1.Name
FROM @t m1
  JOIN @t m2 on m2.Name = m1.Name AND EOMONTH(m1.VisitDate,1) = EOMONTH(m2.VisitDate)
  JOIN @t m3 on m3.Name = m1.Name AND EOMONTH(m1.VisitDate,2) = EOMONTH(m3.VisitDate)

关于EOMONTH的文档:https://docs.microsoft.com/en-us/sql/t-sql/functions/eomonth-transact-sql?view=sql-server-2017

edit:我的答案只是快速破解,并且性能很差,每月有多个实例时会出错。 我建议使用以下答案:https://stackoverflow.com/a/52669713/4903754

答案 2 :(得分:0)

按照postgres SQL 9.5.0的语法写我的代码

首先,我创建了连续几个月的标志,并使用该标志检索了所需的data.lag(),lead()

对于我使用的lag(),lead()函数,我们需要比较它们连续或不连续的日期。

with temp as (

select name,visitdate, 

coalesce(lag(visitdate) over (partition by name order by visitdate),lead(visitdate) over (partition by name order by visitdate))check1,

coalesce(lead(visitdate) over (partition by name order by visitdate),lag(visitdate) over (partition by name order by visitdate)) check2

from TT 

order by 1
),

 t2 as (

select name,

case

when
 (DATE_PART('year', visitdate::date) - DATE_PART('year', check1::date)) * 12 +
              (DATE_PART('month', visitdate::date) - DATE_PART('month', check1::date))=1 

or 

(DATE_PART('year', check2::date) - DATE_PART('year', visitdate::date)) * 12 +
              (DATE_PART('month', check2::date) - DATE_PART('month', visitdate::date))=1 

then 1 else 0

 end as flag

 from temp)

select name ,count(1) from t2 where flag=1  group by name having count(1)>=3

enter image description here