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