【问题标题】:SQL Group records by a custom weekly time rangeSQL 按自定义的每周时间范围分组记录
【发布时间】:2018-10-04 13:12:18
【问题描述】:

这可能很简单,但我一直在想我的问题。

我需要提取周日中午 12 点到周五下午 1 点之间的特定日期范围(2018 年 1 月 - 2018 年 3 月)内的所有记录。按周分组

SELECT col1, 
       Sum(col2) 
FROM   (SELECT * 
        FROM   (SELECT col1, 
                       col2, 
                       Datename(dw, [date_col]) AS day_of_week, 
                       date_col 
                FROM   table 
                WHERE  Datename(dw, [update_date]) != 'Saturday' 
               --eliminate Saturday records 
               ) a 
        WHERE  ( Cast(update_date AS TIME) < '12:00' 
                 AND day_of_week != 'Sunday' ) 
       --eliminate Sunday records before noon 
       ) b 
WHERE  ( day_of_week != 'Friday' 
          OR Cast(update_date AS TIME) > '13:00' ) 

--eliminate Friday records after 1PM

【问题讨论】:

  • 标记您正在使用的 DBMS(即MySQLSQL-Server 等)。
  • 样本数据最好使用DDL + DML。请edit您的问题包括它,您当前的尝试和您想要的结果。更多详情,read this.
  • select @@datefirst 给你什么?与星期几相关的功能依赖于此。
  • 选择@@datefirst 返回7
  • @Salman,语言没问题,但是日期优先设置会如何影响星期名称?

标签: sql sql-server date datetime


【解决方案1】:

已编辑以反映 DATEPART(dw, ...) 的正确返回值

您可以执行逻辑来确定在子查询 SELECT 的 CASE 语句中哪些天/小时组合是有效的,然后在外部查询中按周数分组。这将简化 WHERE 子句。我发现这种风格不那么不透明,更容易长期维护。

以下示例在 Microsoft SQL SERVER 上进行了测试。

SELECT
    DATEPART(wk, Update_Date) AS GroupByWeek
    , col1
    , SUM(col2)
FROM (
    SELECT
        col1
        , col2
        , Update_Date
        , CASE
            WHEN DATEPART(dw, Update_Date) = 1 AND DATEPART(hh, Update_Date) >= 12 THEN 1
            WHEN DATEPART(dw, Update_Date) = 6 AND DATEPART(hh, Update_Date) < 13 THEN 1
            WHEN DATEPART(dw, Update_Date) BETWEEN 2 AND 5 THEN 1
            ELSE 0
        END AS FallsInWindow
    FROM table
) RowsInWindow
WHERE 
    RowsInWindow.Update_Date BETWEEN '2018-01-01' AND '2018-04-01'
    AND RowsInWindow.FallsInWindow = 1
GROUP BY
    DATEPART(wk, Update_Date)
    , col1
ORDER BY GroupByWeek

【讨论】:

  • 为什么需要子查询?
  • DATEPART 可以根据@@DATEFIRST 变量返回不同的值。
  • @CetinBasoz - 您不需要子查询。不过,我发现这种风格更易于阅读和维护。 WHERE 子句使用子查询进行了简化。子查询也可以很容易地放入一个 VIEW 中,它允许确定 FallsInWindow 的逻辑被抽象出来并由其他模块共享。
  • @SalmanA - 感谢您提供有关 @@DATEFIRST 的信息。我不知道那个细节。
  • DATEPART 也应该返回 1 和 7 之间的数字,而不是 0 和 6。
【解决方案2】:

您可以使用以下条件:

WHERE update_date >= '2018-01-01' -- between Jan 2018
AND   update_date <  '2018-04-01' -- and Mar 2018
AND (
    DATENAME(dw, update_date) = 'Sunday' AND CAST(update_date AS TIME) >= '12:00' OR
    DATENAME(dw, update_date) IN ('Monday', 'Tuesday', 'Wednesday', 'Thursday') OR
    DATENAME(dw, update_date) = 'Friday' AND CAST(update_date AS TIME) < '13:00'
)

【讨论】:

  • 我的立场是正确的,这是我的错误。删除我的 cmets。
【解决方案3】:
SELECT col1, Sum(col2)
                FROM   [table] 
                WHERE  Datename(dw, [update_date]) <> 'Saturday'
                OR
                NOT ( Cast(update_date AS TIME) < '12:00' 
                      AND Datename(dw, [update_date]) == 'Sunday' )
                OR 
                NOT ( Datename(dw, [update_date]) == 'Friday' 
                      AND Cast(update_date AS TIME) > '13:00' )
group by col1, datepart(week, update_date);

【讨论】:

  • 这不会按周对数据进行分组。
  • 你怎么知道 col1 不是 week?无论如何,我可以添加另一个分组。
猜你喜欢
  • 2013-03-21
  • 1970-01-01
  • 2021-11-26
  • 2011-03-02
  • 1970-01-01
  • 2010-10-29
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
相关资源
最近更新 更多