T-SQL Найти периоды / Зачисления с пробелами для больших таблиц - PullRequest
0 голосов
/ 05 апреля 2019

Теперь у меня есть код, который делает это присоединением / проверкой каждой даты запрашиваемого периода для каждого периода для каждого 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 голосов
/ 05 апреля 2019

Я полностью основываю этот ответ на заголовке вашего вопроса, потому что детали для меня не имеют смысла.Если вы ищете промежутки в датах между записями, Lag() ваш друг - он извлекает значение из предыдущей записи.

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

приведет к

Cust_ID StartDate   EndDate     GapInDays
1       2003-10-14  2006-11-07  NULL
1       2006-11-09  2011-06-15  2
1       2011-08-22  2012-10-23  68
2       2008-11-09  2015-06-15  NULL
2       2015-08-22  2017-10-23  68
2       2017-10-26  2019-10-23  3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...