大表的T-SQL查找期间/具有间隙的注册

时间:2019-04-05 18:56:21

标签: sql-server

我现在编写了代码,该代码在每个Cust_ID的每个期间内加入/检查请求期间的每个日期。但我认为应该是其他性能更高的解决方案。

是的,我做了作业,看到了很多答复,但是没有一个为我需要的问题提供明确的解决方案。感谢您的帮助。

这是一个测试数据,两个Cust都有空白。如何显示有缺口的Cust(超过1天)

-- DROP TABLE #t

SELECT * 
INTO #t 
FROM 
    (SELECT 
         1 Cust_ID,  
         CAST('2003/10/14' AS DATE) StartDate, 
         CAST('2006/11/07' AS DATE) EndDate 
     UNION
     SELECT 1, '2006/11/09', '2011/06/15'  
     UNION
     SELECT 1, '2011/08/22', '2012/10/23'  
     UNION
     SELECT 2, '2008/11/09', '2015/06/15'  
     UNION
     SELECT 2, '2015/08/22', '2017/10/23'  
     UNION
     SELECT 2, '2017/10/26', '2019/10/23'
    ) f   --         SELECT  * FROM #t

数据:

+---------+--------------+------------+
| Cust_ID | StartDate    |  EndDate   |
+---------+--------------+------------+
| 1       | 2003-10-14   | 2006-11-07 |
| 1       | 2006-11-09   | 2011-06-15 |
| 1       | 2011-08-22   | 2012-10-23 |
| 2       | 2008-11-09   | 2015-06-15 |
| 2       | 2015-08-22   | 2017-10-23 |
| 2       | 2017-10-26   | 2019-10-23 |
+---------+--------------+------------+

===============================================================是我为简单起见就通过多步骤解决方案

-------------------------------------------------------------------------------- ---Set params for Period to check, and @BreakDays
 DECLARE @Period_Start  DATEtime = '2018-1-1', 
         @Period_End    DATEtime = '2018-12-31',
         @BreakDays      INT = 0;       -- 0 ==> no any single day break

    IF OBJECT_ID( 'Tempdb..#Calendar') IS NOT NULL DROP TABLE #Calendar                                      ---   select * from #Calendar
    IF OBJECT_ID( 'Tempdb..#t_all') IS NOT NULL DROP TABLE #t_all                                            ---   select * from #t_all



-------------------------------------------------------------------------------- Create DateDim for period  
    DECLARE @CalRows  INT = (   SELECT DATEDIFF(DAY,@Period_Start ,@Period_End+1) )                             --- set number of entries in #Calendar

    SELECT TOP (DATEDIFF(DAY, @Period_Start, @Period_End + 1))                                                  ---   added 1 day to match number
        DATEADD(dd,ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1,@Period_Start) dt                               ---   select * from #Calendar
    INTO #Calendar
    FROM sys.all_columns sc1,         sys.all_columns sc2;                                                      ---   drop table #Calendar







 SELECT * INTO #t_all FROM (
SELECT  1 Cust_ID,  CAST('2003/10/14' AS DATE) StartDate, CAST('2006/11/07' AS DATE)  EndDate UNION
SELECT 1,             '2006/11/09' ,           '2011/06/15'  union
SELECT 1,             '2011/08/22' ,           '2012/10/23'  union
SELECT 2,         '2008/11/09' , '2015/06/15'  union
SELECT 2,         '2015/08/22' , '2017/10/23'  UNION
SELECT 2,         '2017/10/26' , '2019/10/23'        ) f   --         SELECT  * FROM #t

    WHERE 1=1
    --    AND  StartDate  <=  @Period_End                 -- end of period to search
    --   AND  EndDate    >=  @Period_Start               -- Start of period to search


   IF OBJECT_ID( 'Tempdb..#result') IS NOT NULL DROP TABLE #result                                 --    SELECT top 100 * from #result

------------------------------------------------------------------  final step join to each date and verify
        ;with cte as (
           SELECT t.*,  c.dt
           FROM   #t_all  t
           join #Calendar c on c.dt  between t.StartDate  and t.EndDate     
        )
         SELECT Cust_ID, count(Distinct dt) DDin, @CalRows - COUNT(Distinct dt) DDshort, @Period_Start  Period_Start , @Period_End  Period_End
         INTO #result
         FROM cte
         group by Cust_ID
         --  Having @CalRows - COUNT(Distinct dt) <= @BreakDays   --184



   SELECT * FROM #result   WHERE DDShort >=  @BreakDays

1 个答案:

答案 0 :(得分:0)

我将答案完全基于您问题的标题,因为细节对我而言毫无意义。如果您要查找记录之间的日期间隔,VAR是您的朋友-它从上一条记录中检索值。

Lag()

将导致

SELECT Cust_ID, StartDate, EndDate,
  DATEDIFF(day, LAG(EndDate) OVER (PARTITION BY Cust_ID ORDER BY EndDate), StartDate)
  AS GapInDays
FROM Table_1