AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 168089
Accepted
Peter PitLock
Peter PitLock
Asked: 2017-03-25 05:25:33 +0800 CST2017-03-25 05:25:33 +0800 CST 2017-03-25 05:25:33 +0800 CST

将一年中的每一天与 DATEFIRST = 1 和 DATEFIRST = 7 进行比较

  • 772

要获取周列表,我只需运行此(在线找到):

SET DATEFIRST 7
;with DateCTE   as
(
    select cast('01/01/2017' as datetime) DateValue
    union all
    select DateValue + 1
    from    DateCTE  
    where   DateValue + 1 < '1/1/2018'
)


Select
    cast(CAST(DateValue AS CHAR(11)) AS DateTime) AS [FullDate],
    DATEPART(wk, DateValue) AS WeekOfYear,
    DATEPART(yy, DateValue) AS CalendarYear 
from   DateCTE
OPTION (MAXRECURSION 0)

在此处输入图像描述

显然,如果我设置 DATEFIRST = 1,那么它会得到不同的结果。

在此处输入图像描述

我需要比较一张表中的日期,而不使用表变量。这就是我想要实现的目标: 在此处输入图像描述

因此,我希望在两个 CTE 中看到相同的 365 天,

我想比较基于不同 DateFirsts 的 WeekOfYear。

我不知道如何有效地做到这一点。我只能让它工作,当我

  1. 创建表变量 1 并为 DateFirst7 运行 CTE
  2. 创建表变量 2 并为 DateFirst1 运行 CTE

这是低效的,我正在寻找一种更好的方法来做到这一点。

有一些事情不利于此 1. 我不知道如何在查询中设置 DateFirst。我只知道在cte之前怎么设置。2. 我想为此使用嵌套 CTE,但 OPTION (MAXRECURSION 0) 不适用于嵌套 CTE

这可能吗 - 使用 CTE 获得所需的结果?

sql-server cte
  • 3 3 个回答
  • 705 Views

3 个回答

  • Voted
  1. Best Answer
    Andriy M
    2017-03-25T14:55:43+08:002017-03-25T14:55:43+08:00

    我开始尝试修复 Max Vernon 的答案,以便它适用于任何一年,但最终采用了两种不同的方法。

    方法 1. 聪明

    在这种方法中,我直接从一年中第一个基于星期日的星期日的偏移量计算基于星期日的周数。

    一年的第一个星期日为基础的星期日可以这样得到:

    SET DATEFIRST 1;
    SELECT DATEADD(DAY, -(DATEPART(WEEKDAY, @FirstDayOfYear) % 7), @FirstDayOfYear);
    

    您将 1 月 1 日作为工作日作为天数并从 1 月 1 日减去它,除非该日期是星期日,在这种情况下您什么都不减(这就是它的… % 7用途)。对于基于星期一的周数,上述公式的结果将始终是星期日,在这种情况下,它将是一年中第一个基于星期日的星期的星期日。

    在继续计算基于星期日的周数之前,这里是另一个将任何日期转换为同一年 1 月 1 日的公式:

    SELECT DATEADD(DAY, 1 - DATEPART(DAYOFYEAR, @Date), @Date);
    

    基本上,获取日期并减去它的 DAYOFYEAR 值并添加一天。

    现在这里是一个查询,它使用 Max Vernon 的 CTE 集、上面的两个公式和另一个获取实际周数的公式:

    SET DATEFIRST 1;
    WITH Nums AS (
        SELECT v.Num 
        FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) v(Num)
    )
    , Dates AS
    (
        SELECT Date = DATEADD(DAY
                    , ROW_NUMBER() OVER (ORDER BY n1.Num, n2.Num, n2.Num)
                    , N'2016-12-31T00:00:00')
        FROM Nums n1 --10 rows
            CROSS JOIN Nums n2 --100 rows
            CROSS JOIN Nums n3 --1000 rows, add more cross joins for more rows
    )
    SELECT [Date] = FORMAT(d.Date, 'dddd MMM dd, yyyy')
        , WeekOfYearStartingMonday = DATEPART(WEEK, d.Date)
        , WeekOfYearStartingSunday = DATEDIFF(DAY, y.Sunday1, d.Date) / 7 + 1
    FROM Dates AS d
    CROSS APPLY (
        SELECT DATEADD(DAY, 1 - DATEPART(DAYOFYEAR, d.Date), d.Date)
    ) AS x (January1)
    CROSS APPLY (
        SELECT DATEADD(DAY, -(DATEPART(WEEKDAY, x.January1) % 7), x.January1)
    ) AS y (Sunday1)
    ORDER BY d.Date;
    

    方法二、利用系统漏洞

    此方法完全不同,因为它依赖于 DATEDIFF 函数的内置特性。

    您可能知道,设置 DATEFIRST 会影响 和 等函数的DATEPART(WEEK)结果DATEPART(WEEKDAY)。与它们不同,DATEDIFF(WEEK)不遵守 DATEFIRST 设置。它始终计算差异,就好像 DATEFIRST 设置为 7,即始终将周视为基于星期日的周。

    知道这一点后,您可以计算 1 月 1 日与同年任何日期之间的周差,加 1 并将其用作基于星期日的周数:

    SET DATEFIRST 1;
    WITH Nums AS (
        SELECT v.Num 
        FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) v(Num)
    )
    , Dates AS
    (
        SELECT Date = DATEADD(DAY
                    , ROW_NUMBER() OVER (ORDER BY n1.Num, n2.Num, n2.Num)
                    , N'2016-12-31T00:00:00')
        FROM Nums n1 --10 rows
            CROSS JOIN Nums n2 --100 rows
            CROSS JOIN Nums n3 --1000 rows, add more cross joins for more rows
    )
    SELECT [Date] = FORMAT(d.Date, 'dddd MMM dd, yyyy')
        , WeekOfYearStartingMonday = DATEPART(WEEK, d.Date)
        , WeekOfYearStartingSunday = DATEDIFF(WEEK, x.January1, d.Date) + 1
    FROM Dates AS d
    CROSS APPLY (
        SELECT DATEADD(DAY, 1 - DATEPART(DAYOFYEAR, d.Date), d.Date)
    ) AS x (January1)
    ORDER BY d.Date;
    
    • 4
  2. Hannah Vernon
    2017-03-25T10:55:40+08:002017-03-25T10:55:40+08:00

    您可以模拟修改DATEFIRST设置,因为这是一个众所周知的公式,您只需更改一周的第一天。

    SET DATEFIRST 1;
    ;WITH Nums AS (
        SELECT v.Num 
        FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) v(Num)
    )
    , Dates AS
    (
        SELECT Date = DATEADD(DAY
                    , ROW_NUMBER() OVER (ORDER BY n1.Num, n2.Num, n2.Num)
                    , N'2016-12-31T00:00:00')
        FROM Nums n1 --10 rows
            CROSS JOIN Nums n2 --100 rows
            CROSS JOIN Nums n3 --1000 rows, add more cross joins for more rows
    )
    SELECT [Date] = FORMAT(d.Date, 'dddd MMM dd, yyyy')
        , WeekOfYearStartingMonday = DATEPART(WEEK, d.Date)
        , WeekOfYearStartingSunday = CASE WHEN DATEPART(WEEKDAY, d.Date) = 7
                                          THEN DATEPART(WEEK, d.Date) 
                                          ELSE DATEPART(WEEK, d.Date) - 1 
                                     END
    FROM Dates d
    ORDER BY d.Date;
    GO
    

    结果的前几周:

    +------------------------+---------------------- --+--------------------------+
    | 日期 | 一年中的一周开始星期一 | 星期日开始星期日 |
    +------------------------+---------------------- --+--------------------------+
    | 2017 年 1 月 1 日星期日 | 1 | 1 |
    | 2017 年 1 月 2 日星期一 | 2 | 1 |
    | 2017 年 1 月 3 日星期二 | 2 | 1 |
    | 2017 年 1 月 4 日,星期三 | 2 | 1 |
    | 2017 年 1 月 5 日星期四 | 2 | 1 |
    | 2017 年 1 月 6 日星期五 | 2 | 1 |
    | 2017 年 1 月 7 日星期六 | 2 | 1 |
    | 2017 年 1 月 8 日星期日 | 2 | 2 |
    | 2017 年 1 月 9 日星期一 | 3 | 2 |
    | 2017 年 1 月 10 日星期二 | 3 | 2 |
    | 2017 年 1 月 11 日,星期三 | 3 | 2 |
    | 2017 年 1 月 12 日星期四 | 3 | 2 |
    | 2017 年 1 月 13 日,星期五 | 3 | 2 |
    | 2017 年 1 月 14 日星期六 | 3 | 2 |
    | 2017 年 1 月 15 日星期日 | 3 | 3 |
    | 2017 年 1 月 16 日星期一 | 4 | 3 |
    | 2017 年 1 月 17 日星期二 | 4 | 3 |
    | 2017 年 1 月 18 日,星期三 | 4 | 3 |
    | 2017 年 1 月 19 日星期四 | 4 | 3 |
    | 2017 年 1 月 20 日星期五 | 4 | 3 |
    | 2017 年 1 月 21 日星期六 | 4 | 3 |
    | 2017 年 1 月 22 日星期日 | 4 | 4 |
    | 2017 年 1 月 23 日星期一 | 5 | 4 |
    +------------------------+---------------------- --+--------------------------+
    • 3
  3. RDFozz
    2017-03-25T14:07:01+08:002017-03-25T14:07:01+08:00

    边缘案例的乐趣。Max 的解决方案适用于 2017 年,因为 2017 年是从星期日开始的。如果您扩大日期范围,您会发现从星期日开始的年份都可以。然而,如果一年从一周中的任何一天开始,第一个星期日之前的部分周将始终显示为第 0 周。一些企业可能希望它是第 0 周(因为它是部分周),或前一个星期日的一部分年,或其他 - 然而,星期一日期的部分周是第 1 周,而不是第 0 周,所以我们有一个差异。

    我看到解决它的最简单方法是检查这一年是否从星期日开始。如果是,则使用 Max 的原始代码WeekOfYearStartingSunday;如果没有,只需在他拥有的基础上加一个:

    SET DATEFIRST 1;
    ;WITH Nums AS (
        SELECT v.Num 
        FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) v(Num)
    )
    , Dates AS
    (
        SELECT Date = DATEADD(DAY
                    , ROW_NUMBER() OVER (ORDER BY n1.Num, n2.Num, n2.Num)
                    , N'2016-12-31T00:00:00')
        FROM Nums n1 --10 rows
            CROSS JOIN Nums n2 --100 rows
            CROSS JOIN Nums n3 --1000 rows
            CROSS JOIN Nums n4 --10000 rows, add more cross joins for more rows
    )
    SELECT [Date] = FORMAT(d.Date, 'dddd MMM dd, yyyy')
        , WeekOfYearStartingMonday = DATEPART(WEEK, d.Date)
        , WeekOfYearStartingSunday = CASE WHEN DATEPART(WEEKDAY, DATEADD(YEAR, DATEPART(YEAR, d.date) - 1900, 0)) = 7
                                          -- Jan 1 is a Sunday
                                          THEN CASE WHEN DATEPART(WEEKDAY, d.Date) = 7
                                                    THEN DATEPART(WEEK, d.Date) 
                                                    ELSE DATEPART(WEEK, d.Date) - 1 
                                               END
    
                                          -- Jan 1 is NOT a Sunday
                                          ELSE CASE WHEN DATEPART(WEEKDAY, d.Date) = 7
                                                    THEN DATEPART(WEEK, d.Date) + 1
                                                    ELSE DATEPART(WEEK, d.Date)
                                               END
                                     END
    FROM Dates d
    -- WHERE added to just show first and last 9 days of each year; remove to see all dates
    WHERE (DATEPART(MONTH, d.date) = 12 AND DATEPART(DAY, d.date) > 22)
       OR (DATEPART(MONTH, d.date) = 1 AND DATEPART(DAY, d.date) < 10)
    ORDER BY d.Date;
    GO
    

    这是前六年的第一天和最后一天(年份从除星期四以外的每一天开始——由于闰年,它会走得更远):

    +-------------------------+--------------------------+--------------------------+
    | Date                    | WeekOfYearStartingMonday | WeekOfYearStartingSunday |
    +-------------------------+--------------------------+--------------------------+
    | Sunday Jan 01, 2017     |                        1 |                        1 |
    | Monday Jan 02, 2017     |                        2 |                        1 |
    | Tuesday Jan 03, 2017    |                        2 |                        1 |
    | Wednesday Jan 04, 2017  |                        2 |                        1 |
    | Thursday Jan 05, 2017   |                        2 |                        1 |
    | Friday Jan 06, 2017     |                        2 |                        1 |
    | Saturday Jan 07, 2017   |                        2 |                        1 |
    | Sunday Jan 08, 2017     |                        2 |                        2 |
    | Monday Jan 09, 2017     |                        3 |                        2 |
    | Saturday Dec 23, 2017   |                       52 |                       51 |
    | Sunday Dec 24, 2017     |                       52 |                       52 |
    | Monday Dec 25, 2017     |                       53 |                       52 |
    | Tuesday Dec 26, 2017    |                       53 |                       52 |
    | Wednesday Dec 27, 2017  |                       53 |                       52 |
    | Thursday Dec 28, 2017   |                       53 |                       52 |
    | Friday Dec 29, 2017     |                       53 |                       52 |
    | Saturday Dec 30, 2017   |                       53 |                       52 |
    | Sunday Dec 31, 2017     |                       53 |                       53 |
    | Monday Jan 01, 2018     |                        1 |                        1 |
    | Tuesday Jan 02, 2018    |                        1 |                        1 |
    | Wednesday Jan 03, 2018  |                        1 |                        1 |
    | Thursday Jan 04, 2018   |                        1 |                        1 |
    | Friday Jan 05, 2018     |                        1 |                        1 |
    | Saturday Jan 06, 2018   |                        1 |                        1 |
    | Sunday Jan 07, 2018     |                        1 |                        2 |
    | Monday Jan 08, 2018     |                        2 |                        2 |
    | Tuesday Jan 09, 2018    |                        2 |                        2 |
    | Sunday Dec 23, 2018     |                       51 |                       52 |
    | Monday Dec 24, 2018     |                       52 |                       52 |
    | Tuesday Dec 25, 2018    |                       52 |                       52 |
    | Wednesday Dec 26, 2018  |                       52 |                       52 |
    | Thursday Dec 27, 2018   |                       52 |                       52 |
    | Friday Dec 28, 2018     |                       52 |                       52 |
    | Saturday Dec 29, 2018   |                       52 |                       52 |
    | Sunday Dec 30, 2018     |                       52 |                       53 |
    | Monday Dec 31, 2018     |                       53 |                       53 |
    | Tuesday Jan 01, 2019    |                        1 |                        1 |
    | Wednesday Jan 02, 2019  |                        1 |                        1 |
    | Thursday Jan 03, 2019   |                        1 |                        1 |
    | Friday Jan 04, 2019     |                        1 |                        1 |
    | Saturday Jan 05, 2019   |                        1 |                        1 |
    | Sunday Jan 06, 2019     |                        1 |                        2 |
    | Monday Jan 07, 2019     |                        2 |                        2 |
    | Tuesday Jan 08, 2019    |                        2 |                        2 |
    | Wednesday Jan 09, 2019  |                        2 |                        2 |
    | Monday Dec 23, 2019     |                       52 |                       52 |
    | Tuesday Dec 24, 2019    |                       52 |                       52 |
    | Wednesday Dec 25, 2019  |                       52 |                       52 |
    | Thursday Dec 26, 2019   |                       52 |                       52 |
    | Friday Dec 27, 2019     |                       52 |                       52 |
    | Saturday Dec 28, 2019   |                       52 |                       52 |
    | Sunday Dec 29, 2019     |                       52 |                       53 |
    | Monday Dec 30, 2019     |                       53 |                       53 |
    | Tuesday Dec 31, 2019    |                       53 |                       53 |
    | Wednesday Jan 01, 2020  |                        1 |                        1 |
    | Thursday Jan 02, 2020   |                        1 |                        1 |
    | Friday Jan 03, 2020     |                        1 |                        1 |
    | Saturday Jan 04, 2020   |                        1 |                        1 |
    | Sunday Jan 05, 2020     |                        1 |                        2 |
    | Monday Jan 06, 2020     |                        2 |                        2 |
    | Tuesday Jan 07, 2020    |                        2 |                        2 |
    | Wednesday Jan 08, 2020  |                        2 |                        2 |
    | Thursday Jan 09, 2020   |                        2 |                        2 |
    | Wednesday Dec 23, 2020  |                       52 |                       52 |
    | Thursday Dec 24, 2020   |                       52 |                       52 |
    | Friday Dec 25, 2020     |                       52 |                       52 |
    | Saturday Dec 26, 2020   |                       52 |                       52 |
    | Sunday Dec 27, 2020     |                       52 |                       53 |
    | Monday Dec 28, 2020     |                       53 |                       53 |
    | Tuesday Dec 29, 2020    |                       53 |                       53 |
    | Wednesday Dec 30, 2020  |                       53 |                       53 |
    | Thursday Dec 31, 2020   |                       53 |                       53 |
    | Friday Jan 01, 2021     |                        1 |                        1 |
    | Saturday Jan 02, 2021   |                        1 |                        1 |
    | Sunday Jan 03, 2021     |                        1 |                        2 |
    | Monday Jan 04, 2021     |                        2 |                        2 |
    | Tuesday Jan 05, 2021    |                        2 |                        2 |
    | Wednesday Jan 06, 2021  |                        2 |                        2 |
    | Thursday Jan 07, 2021   |                        2 |                        2 |
    | Friday Jan 08, 2021     |                        2 |                        2 |
    | Saturday Jan 09, 2021   |                        2 |                        2 |
    | Thursday Dec 23, 2021   |                       52 |                       52 |
    | Friday Dec 24, 2021     |                       52 |                       52 |
    | Saturday Dec 25, 2021   |                       52 |                       52 |
    | Sunday Dec 26, 2021     |                       52 |                       53 |
    | Monday Dec 27, 2021     |                       53 |                       53 |
    | Tuesday Dec 28, 2021    |                       53 |                       53 |
    | Wednesday Dec 29, 2021  |                       53 |                       53 |
    | Thursday Dec 30, 2021   |                       53 |                       53 |
    | Friday Dec 31, 2021     |                       53 |                       53 |
    | Saturday Jan 01, 2022   |                        1 |                        1 |
    | Sunday Jan 02, 2022     |                        1 |                        2 |
    | Monday Jan 03, 2022     |                        2 |                        2 |
    | Tuesday Jan 04, 2022    |                        2 |                        2 |
    | Wednesday Jan 05, 2022  |                        2 |                        2 |
    | Thursday Jan 06, 2022   |                        2 |                        2 |
    | Friday Jan 07, 2022     |                        2 |                        2 |
    | Saturday Jan 08, 2022   |                        2 |                        2 |
    | Sunday Jan 09, 2022     |                        2 |                        3 |
    | Friday Dec 23, 2022     |                       52 |                       52 |
    | Saturday Dec 24, 2022   |                       52 |                       52 |
    | Sunday Dec 25, 2022     |                       52 |                       53 |
    | Monday Dec 26, 2022     |                       53 |                       53 |
    | Tuesday Dec 27, 2022    |                       53 |                       53 |
    | Wednesday Dec 28, 2022  |                       53 |                       53 |
    | Thursday Dec 29, 2022   |                       53 |                       53 |
    | Friday Dec 30, 2022     |                       53 |                       53 |
    | Saturday Dec 31, 2022   |                       53 |                       53 |
    +-------------------------+--------------------------+--------------------------+
    
    • 3

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve