【问题标题】:Query optimization for weekly data for the month当月周数据查询优化
【发布时间】:2017-01-25 12:05:37
【问题描述】:

在 SQL Server 查询优化方面需要帮助,如下所示:

    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  

可能我需要对这里提到的每周数据使用 CTE(公用表表达式)

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

【问题讨论】:

    标签: sql sql-server sql-server-2008 sql-server-2012


    【解决方案1】:

    如果您无法将 Dates 或 Numbers 表添加到数据库中,使用您提到的 CTE 生成的派生表可能是最好的方法:

    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
    

    【讨论】:

    • 嗨 iamdave,我尝试过这种方式,但出现以下错误:递归公用表表达式“cte”的递归部分不允许使用 GROUP BY、HAVING 或聚合函数
    • @DevDeveloper 您是否完全复制了我的代码?我的cte 的递归部分没有 group byhaving 或聚合函数...
    • 对不起,我的错误,结果如下(未显示空值周)'StartDate EndDate rcOpen rcClosed 2017-01-15 00:00:00.000 2017-01-22 00:00:00.000 12 5'
    • @DevDeveloper 将JOIN 更改为LEFT JOIN
    • @iamdeve 非常感谢,我必须使用 Right Join 而不是 Left Join,然后我得到了所需的结果。
    【解决方案2】:

    另一种方法

    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
    

    【讨论】:

    • Shakeer 以上 CTE 查询也可以正常工作,但我需要使用 CTE 从表中获取数据。
    【解决方案3】:

    此查询将比递归 CTE 执行得更好。

    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]
    

    【讨论】:

      【解决方案4】:
      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 上面的答案中进行一些更改后将是正确的答案

      【讨论】:

        【解决方案5】:

        也许您可以使用UNION ALL 而不仅仅是UNION

        【讨论】:

        • Union 也可以正常工作,但我需要优化上述查询。
        • @DevDeveloper union allunion 快​​,因为它不会检查然后删除重复的行。
        • 谢谢,非常感谢
        猜你喜欢
        • 2021-09-14
        • 2013-03-08
        • 2021-01-04
        • 1970-01-01
        • 2011-02-27
        • 1970-01-01
        • 2019-03-30
        • 2017-01-11
        • 1970-01-01
        相关资源
        最近更新 更多