首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TSQL:全年/每个月的连续期间

TSQL:全年/每个月的连续期间
EN

Stack Overflow用户
提问于 2019-11-19 05:01:31
回答 2查看 122关注 0票数 1

我试图找到所有在2018年期间每个月至少有一天会员资格的Cust

我想出了解决方案,在每个月的开始/中期/结束时检查他们的成员身份,就像下面的片段一样,但我试图找到更智能的解决方案。

我知道,我可以使用理货表的每365天来检查这一点,但可能有更优雅的解决方案?我对SQL有点陌生,我想我在GROUPing领域遗漏了一些东西。

在下面所示的代码片段中,两个Cust都至少有一天的成员资格。

期望输出:

代码语言:javascript
复制
CustID
------
   1
  22

代码:

代码语言:javascript
复制
with data as 
(
    select * 
    from (values (1, 1,   '2017-12-11', '2018-01-16'),   (1, 22,  '2018-01-28', '2018-03-9' ), (1, 333, '2018-03-1', '2018-12-31') ,  -- island
                 (22, 1,  '2017-12-31', '2018-01-11'),   (22, 2,  '2017-2-11',  '2019-12-31')) as t (CustID, ContractID, StartDD, EndDD)     ---      
    )
    select 
        isdate(startDD), isdate(EndDD) 
    from 
        data
), gaps as 
(
    select  
        *,  
        datediff(day, lag(EndDD, 1, StartDD) over (partition by CustID order by StartDD), StartDD) as BreakDD          -- negative is island
    from 
        data
)
select 
    *, 
    datepart(month,StartDD) mmS , datepart(month,EndDD) mmE 
from 
    gaps 
    -- and was active any 1+ day during each of the 12 months in 2018    ????
where 
    1 = 1 
    /* and (cast('1/1/2018' as date) between StartDD and EndDD
            or cast('1/15/2018' as date) between StartDD and EndDD     
            or cast('1/31/2018' as date) between StartDD and EndDD)
       ---- etc..  for each month
       and (      cast('12/1/2018'  as date)   between  StartDD  and  EndDD 
              or  cast('12/15/2018' as date)   between  StartDD  and  EndDD  
              or  cast('12/31/2018' as date)   between  StartDD  and  EndDD  
           ) 
*/ 
--select CustID, max(BreakDD) Max_Days
--from gaps
--group by CustID
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-11-19 09:14:14

试试这个答案。

首先,创建一个函数来返回给定日期之间的所有月份和年份。

函数:

代码语言:javascript
复制
--SELECT * FROM dbo.Fn_GetMonthYear('2017-12-11','2018-01-16')
ALTER FUNCTION dbo.Fn_GetMonthYear(@StartDate  DATETIME,@EndDate    DATETIME)
RETURNS TABLE
AS

    RETURN(
    SELECT  DATEPART(MONTH, DATEADD(MONTH, x.number, @StartDate)) AS [Month]
            ,DATEPART(YEAR, DATEADD(MONTH, x.number, @StartDate)) AS [Year]
    FROM    master.dbo.spt_values x
    WHERE   x.type = 'P'        
    AND     x.number <= DATEDIFF(MONTH, @StartDate, @EndDate)
    )

表模式:

代码语言:javascript
复制
CREATE TABLE #t(CustID INT, ContractID INT, StartDD date, EndDD date)

INSERT INTO #t values (1, 1,   '2017-12-11', '2018-01-16'),   (1, 22,  '2018-01-28', '2018-03-9' ), (1, 333, '2018-03-1', '2018-12-31') ,  -- island
                 (22, 1,  '2017-12-31', '2018-01-11'),   (22, 2,  '2017-2-11',  '2019-12-31')

下面是针对您的需求的 the查询

代码语言:javascript
复制
SELECT CustID
    ,COUNT(DISTINCT [Month]) NoOfMonths
FROM(
    SELECT * 
    FROM #t t
    CROSS APPLY dbo.Fn_GetMonthYear(StartDD,EndDD)
    )D
WHERE [Year] = 2018
GROUP BY CustID
HAVING COUNT(DISTINCT [Month])=12

结果:

代码语言:javascript
复制
CustID  NoOfMonths
1       12
22      12
票数 2
EN

Stack Overflow用户

发布于 2019-11-19 11:50:00

查找2018年期间每个月至少有一天会员的Cust

我认为这意味着必须在'2018-01-01''2018-12-31'之间为每个custid提供数据。

代码语言:javascript
复制
CREATE TABLE #t(CustID INT, ContractID INT, StartDD date, EndDD date)

INSERT INTO #t values (1, 1,   '2017-12-11', '2018-01-16'),   (1, 22,  '2018-01-28', '2018-03-9' ), (1, 333, '2018-03-1', '2018-12-31') ,  -- island
 (22, 1,  '2017-12-31', '2018-01-11'),   (22, 2,  '2017-2-11',  '2019-12-31')

declare @From Datetime='2018-01-01'
declare @To datetime='2018-12-31'

;with CTE as
(
select CustID,min(StartDD)StartDD
,max(EndDD)EndDD
from #t
group by CustID
)
select CustID,StartDD
,EndDD
from CTE
where StartDD<=@From and EndDD>=@To

此脚本不是在所有示例数据中进行测试的。但逻辑是clear.So,它可以进行相应的修正。

因此,告诉哪些样本数据不起作用。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58926959

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档