【问题标题】:List all working dates between two dates in SQL列出 SQL 中两个日期之间的所有工作日期
【发布时间】:2015-03-11 11:12:59
【问题描述】:

我有生成两个日期之间的日期列表的 SQL 代码,但我想从给定的两个日期生成工作日(工作日),

DECLARE @MinDate DATE = '20140101', @MaxDate DATE = '20140106';
SELECT TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
    Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1,@MinDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;

这是我的代码,所以请任何人建议我单独获取工作日列表。 在线资源有代码来查找天数而不是列出所有日期,这是我的困惑。

【问题讨论】:

  • 已经有人建议找到工作日的好方法here
  • 每周减去两天?

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


【解决方案1】:

试试这个:

DECLARE @MinDate DATE = '20140101',
        @MaxDate DATE = '20140106'

;WITH N1 (N) AS (SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
N4 (N) AS (SELECT ROW_NUMBER() OVER(ORDER BY N1.N) FROM N3 AS N1 CROSS JOIN N3 AS N2)
SELECT  Date = DATEADD(DAY, N - 1, @MinDate)
FROM    N4
WHERE 
  N < DATEDIFF(DAY, @MinDate, @MaxDate) + 2 AND
  DATEDIFF(DAY, 1 - N, @MinDate) % 7 NOT IN (5,6)

结果:

Date
2014-01-01
2014-01-02
2014-01-03
2014-01-06

【讨论】:

  • DATEDIFF(d,1 - N, @MinDate) % 7 NOT IN (5,6) 中使用模 7 是可靠的,无论 sql server 设置如何,也不依赖于语言。
  • @Used_By_Already:使这个查询独立于设置的不是模7,而是intdatetime的隐式转换。然而,问题是这个解决方案有一个错误。如果您尝试将@MinDate 更改为20140102,您将得到不正确的结果。也许 t-clausen.dk 表示这个版本的 DATEDIFF:DATEDIFF(DAY, 0, DATEADD(DAY, N - 1, @MinDate)) % 7 NOT IN (5,6)
  • 我指的不是设置独立的原因,而是“使用模 7”。我试图描述“% 7”做了什么并提供了一个好处(可能很差),即 (5,6) 的结果与设置无关。关于 dateadd() 的需要,您可能确实是正确的,我会让作者对此作出回应。干杯。
【解决方案2】:

将原始查询设为sub-select,它会生成两个给定日期之间的所有日期,然后在outer query 中进行过滤。

SET DATEFIRST 1

select [Date] from
(
SELECT  TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
    Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1,@MinDate)
FROM    sys.all_objects a
    CROSS JOIN sys.all_objects b
)
where datename(dw,[Date]) not in ('Saturday','Sunday')

【讨论】:

  • 完美无瑕,除非出于某种原因,我的 SQL 资源管理器不会让表成为表。
  • 设置 DateFirst 对代码中的 DateDiff、DateAdd 或 DateName 函数没有影响。该行可以删除而没有任何影响。此外,您需要为 () 中的隐含表提供别名,否则它将无法在 SQL Server 中运行(例如 ... Cross Join sys.all_objects b) MyTemp where datename(....
【解决方案3】:
DECLARE @MinDate DATE = '20140101', @MaxDate DATE = '20140106';
SELECT  TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
    Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1,@MinDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b
WHERE datename(dw,@MinDate) NOT IN ('Saturday','Sunday') 
      AND datename(dw,@MaxDate) NOT IN ('Saturday','Sunday') ;

【讨论】:

  • 感谢您的回复马特,但周末(周六和周日)没有被过滤。我不想在我的代码中包含周末日期。
  • 当比较检查周六和周日的日期部分不可靠时,这取决于 datefirst 的设置,默认值可能因数据库而异
  • 是的,我认为它可能是,我删除第二个版本
  • 我仍然没有得到正确的输出,例如,如果我将这些值作为开始日期和结束日期 '2015/12/13'、'2015/12/27' 传递,则没有日期正在生成。
  • 因为您的开始日期和结束日期有周末日期,如果您使用它们将无法工作,因为没有包括在内,请尝试 '2015/12/14' & '2015/12/25'跨度>
【解决方案4】:

很久以前,我建立了一个日历表来回答像你这样的问题。除了易用性之外,主要好处是您可以查看针对日历表的查询并说:“这显然正确。”

select cal_date, day_of_week
from calendar
where day_of_week in ('Mon', 'Tue', 'Wed', 'Thu', 'Fri')
  and cal_date between '2014-01-01' and '2014-01-06'
order by cal_date;
cal_date day_of_week -- 2014-01-01 周三 2014-01-02 星期四 2014-01-03 周五 2014-01-06 周一

我也有工作日的视图,所以我可以改为查询它。

select cal_date, day_of_week
from weekdays
where cal_date between '2014-01-01' and '2014-01-06'
order by cal_date;

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 2020-11-20
  • 2017-06-12
  • 2022-01-04
相关资源
最近更新 更多