2017-01-25 7 views
1

Нужна помощь в оптимизации запросов сервера SQL, который является следующим:Оптимизация запросов для недельных данных за месяц

enter declare @sDate datetime 
declare @eDate datetime 

SET @sDate = '2017-01-01' 
SET @eDate = '2017-01-31' 

SELECT  
    @sDate AS [StartDate], 
    DATEADD(day,6, @sDate) [ENDDATE],      
    SUM(CASE WHEN GS.[Status] = 'Open' THEN 1 ELSE 0 END) [rcOpen], 
    SUM(CASE WHEN GS.[Status] = 'Closed' THEN 1 ELSE 0 END) [rcClosed] 
    FROM GS 
    WHERE  
    (GS.[ModifiedDate] > @sDate) 
    AND 
    (GS.[ModifiedDate] <= DATEADD(day,6, @sDate)) 
UNION 
SELECT  
    DATEADD(day,7, @sDate) AS [StartDate], 
    DATEADD(day,13, @sDate) [ENDDATE],      
    SUM(CASE WHEN GS.[Status] = 'Open' THEN 1 ELSE 0 END) [rcOpen], 
    SUM(CASE WHEN GS.[Status] = 'Closed' THEN 1 ELSE 0 END) [rcClosed] 
    FROM GS 
    WHERE  
    (GS.[ModifiedDate] > DATEADD(day,7, @sDate)) 
    AND 
    (GS.[ModifiedDate] <= DATEADD(day,13, @sDate)) 
UNION 
SELECT  
    DATEADD(day,14, @sDate) AS [StartDate], 
    DATEADD(day,20, @sDate) [ENDDATE],      
    SUM(CASE WHEN GS.[Status] = 'Open' THEN 1 ELSE 0 END) [rcOpen], 
    SUM(CASE WHEN GS.[Status] = 'Closed' THEN 1 ELSE 0 END) [rcClosed] 
    FROM GS 
    WHERE  
    (GS.[ModifiedDate] > DATEADD(day,7, @sDate)) 
    AND 
    (GS.[ModifiedDate] <= DATEADD(day,20, @sDate)) 
UNION 
SELECT  
    DATEADD(day,21, @sDate) AS [StartDate], 
    DATEADD(day,27, @sDate) [ENDDATE],      
    SUM(CASE WHEN GS.[Status] = 'Open' THEN 1 ELSE 0 END) [rcOpen], 
    SUM(CASE WHEN GS.[Status] = 'Closed' THEN 1 ELSE 0 END) [rcClosed] 
    FROM GS 
    WHERE  
    (GS.[ModifiedDate] > DATEADD(day,21, @sDate)) 
    AND 
    (GS.[ModifiedDate] <= DATEADD(day,27, @sDate)) 
UNION 

SELECT  
    DATEADD(day,27, @sDate) AS [StartDate], 
    @eDate [ENDDATE],      
    SUM(CASE WHEN GS.[Status] = 'Open' THEN 1 ELSE 0 END) [rcOpen], 
    SUM(CASE WHEN GS.[Status] = 'Closed' THEN 1 ELSE 0 END) [rcClosed] 
    FROM GS 
    WHERE  
    (GS.[ModifiedDate] > DATEADD(day,27, @sDate)) 
    AND 
    (GS.[ModifiedDate] <= @eDate) 

и результат должен быть следующим:

StartDate    ENDDATE     rcOpen rcClosed 
2017-01-01 00:00:00.000 2017-01-07 00:00:00.000 NULL NULL 
2017-01-08 00:00:00.000 2017-01-14 00:00:00.000 NULL NULL 
2017-01-15 00:00:00.000 2017-01-21 00:00:00.000 12  5 
2017-01-22 00:00:00.000 2017-01-28 00:00:00.000 NULL NULL 
2017-01-28 00:00:00.000 2017-01-31 00:00:00.000 NULL NULL 

Может быть, мне нужно использовать КТР (общие табличные выражения) для еженедельных данных, как указано здесь

how to get the start and end dates of all weeks between two dates in SQL server?

declare @sDate datetime, 
     @eDate datetime; 

select @sDate = '2013-02-25', 
     @eDate = '2013-03-25'; 


;with cte as 
(
    select @sDate StartDate, 
    DATEADD(wk, DATEDIFF(wk, 0, @sDate), 6) EndDate 
    union all 
    select dateadd(ww, 1, StartDate), 
    dateadd(ww, 1, EndDate) 
    from cte 
    where dateadd(ww, 1, StartDate)<= @eDate 
) 
select * 
from cte 

ответ

0

Если вы не можете добавить таблицу даты или цифры в вашей базе данных, используя производную таблицу, порожденную КТР вы упоминаете, вероятно, лучший путь вперед:

declare @sDate datetime, 
     @eDate datetime; 

select @sDate = '2013-02-25', 
     @eDate = '2013-03-25'; 


;with cte as 
(
    select @sDate StartDate, 
    DATEADD(wk, DATEDIFF(wk, 0, @sDate), 6) EndDate 
    union all 
    select dateadd(ww, 1, StartDate), 
    dateadd(ww, 1, EndDate) 
    from cte 
    where dateadd(ww, 1, StartDate)<= @eDate 
) 
SELECT 
    CTE.StartDate 
    ,CTE.EndDate 
    ,SUM(CASE WHEN GS.[Status] = 'Open' THEN 1 ELSE 0 END) [rcOpen] 
    ,SUM(CASE WHEN GS.[Status] = 'Closed' THEN 1 ELSE 0 END) [rcClosed] 
FROM CTE 
    LEFT JOIN GS 
     ON CTE.StartDate < GS.[ModifiedDate] 
      AND CTE.EndDate >= GS.[ModifiedDate] 
GROUP BY CTE.StartDate 
     ,CTE.EndDate 
ORDER BY CTE.StartDate 
+0

Привет iamdave, я пробовал этот путь, но получил следующую ошибку: GROUP BY, HAVING или агрегатные функции не разрешены в рекурсивной части рекурсивного общего выражения таблицы 'cte' –

+0

@DevDeveloper Вы скопировали мой код в точку? Там * не * '' by ',' having' или агрегатная функция в рекурсивной части моего 'cte' ... – iamdave

+0

извините мою ошибку, результат следующий (что не показывает недели с нулевым значением) 'StartDate \t \t EndDate rcOpen \t rcClosed 2017-01-15 00: 00: 00.000 \t 2017-01-22 00: 00: 00,000 \t \t 12 5' –

-1

Возможно, вы можете использовать UNION ALL вместо UNION.

+0

Союз также работает хорошо, но мне нужно, чтобы оптимизировать выше запрос. –

+0

@DevDeveloper 'union all' быстрее, чем' union', поскольку он не проверяет и не удаляет повторяющиеся строки. – iamdave

+0

Спасибо, очень благодарен –

0

Этот запрос будет работать лучше, чем рекурсивный КТР.

declare @sDate datetime = '2017-01-01'; 
declare @eDate datetime = '2017-01-31'; 

WITH X AS (
SELECT DISTINCT 
     DATEADD(DAY, - (DATEPART(WEEKDAY, [Dates])-1), [Dates]) [WeekStart] 
    , DATEADD(DAY, 7- (DATEPART(WEEKDAY, [Dates])), [Dates]) [WeekEnd] 
FROM (
     SELECT DISTINCT DATEADD(DAY , rn -1 , @sDate) [Dates] 
     FROM (
       Select TOP (DATEDIFF(DAY, @sDate, @eDate)) 
         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) rn 
       FROM master..spt_values a 
         CROSS JOIN master..spt_values b 
      )a 
    ) b 
) 
SELECT [WeekStart] 
     , [WeekEnd] 
     , SUM(CASE WHEN GS.[Status] = 'Open' THEN 1 ELSE 0 END) [rcOpen], 
     , SUM(CASE WHEN GS.[Status] = 'Closed' THEN 1 ELSE 0 END) [rcClosed] 
FROM X 
LEFT JOIN GS ON GS.[ModifiedDate] <= CTE.[WeekEnd] 
       AND GS.[ModifiedDate] >= CTE.[WeekStart] 
0

Другой способ сделать это

declare @sDate datetime 
declare @eDate datetime 

SET @sDate = '2017-01-01' 
SET @eDate = '2017-01-31' 

--A recursive CTE for fetching the weeks range 
;WITH CTE AS 
(
    SELECT @sDate SDATE 
    , DATEADD(DD,6,@sDate) AS TO_DTE 

    UNION ALL 

    SELECT DATEADD(DD,1,TO_DTE) 
    , CASE 
     WHEN DATEADD(DD, 7, TO_DTE) > @eDate 
      THEN @eDate 
     ELSE DATEADD(DD, 7, TO_DTE) 
     END 
    FROM CTE 
    WHERE DATEADD(DD, 1, TO_DTE) <= @eDate 


) 
/* An Intermediate result of CTE to better understand 
+-------------------------+-------------------------+ 
|   SDATE   |   TO_DTE   | 
+-------------------------+-------------------------+ 
| 2017-01-01 00:00:00.000 | 2017-01-07 00:00:00.000 | 
| 2017-01-08 00:00:00.000 | 2017-01-14 00:00:00.000 | 
| 2017-01-15 00:00:00.000 | 2017-01-21 00:00:00.000 | 
| 2017-01-22 00:00:00.000 | 2017-01-28 00:00:00.000 | 
| 2017-01-29 00:00:00.000 | 2017-01-31 00:00:00.000 | 
+-------------------------+-------------------------+ 
*/ 

SELECT CTE.SDATE 
    ,CTE.TO_DTE 
    ,SUM(CASE WHEN GS.[Status] = 'Open' THEN 1 ELSE 0 END) [rcOpen] 
    ,SUM(CASE WHEN GS.[Status] = 'Closed' THEN 1 ELSE 0 END) [rcClosed] 
FROM GS 
    JOIN CTE 
     ON GS.[ModifiedDate] > CTE.SDATE 
      AND GS.[ModifiedDate] <= CTE.TO_DTE 
GROUP BY CTE.SDATE 
     ,CTE.TO_DTE 
ORDER BY CTE.SDATE 
+0

Shakeer выше запроса CTE также отлично работает, но мне нужно использовать CTE для извлечения данных из таблицы. –

0
declare @sDate datetime, 
     @eDate datetime; 

select @sDate = '2013-02-25', 
     @eDate = '2013-03-25'; 


;with cte as 
(
    select @sDate StartDate, 
    DATEADD(dd,(7 - (DATEPART(dw,DATEADD(month,DATEDIFF(mm,0,@SelectedDate),0)) + @@DATEFIRST) % 7) % 7,DATEADD(month,DATEDIFF(mm,0,@sDate),0)) EndDate 
    union all 
    select dateadd(dd, 1, EndDate), 
    dateadd(ww, 1, EndDate) 
    from cte 
    where dateadd(ww, 1, StartDate)<= @eDate 
) 
SELECT 
    CTE.StartDate 
    ,CTE.EndDate 
    ,SUM(CASE WHEN GS.[Status] = 'Open' THEN 1 ELSE 0 END) [rcOpen] 
    ,SUM(CASE WHEN GS.[Status] = 'Closed' THEN 1 ELSE 0 END) [rcClosed] 
FROM CTE 
    Right JOIN CTE 
     ON CTE.StartDate < GS.[ModifiedDate] 
      AND CTE.EndDate >= GS.[ModifiedDate] 
GROUP BY CTE.StartDate 
     ,CTE.EndDate 
ORDER BY CTE.StartDate 

После внесения нескольких изменений в @iamdave ответ выше будет правильный ответ

Смежные вопросы