【问题标题】:Function to check if a date is a Christmas day or New Years day检查日期是圣诞节还是元旦的功能
【发布时间】:2021-10-21 02:47:53
【问题描述】:

我正在 SQL Server 中创建一个函数来验证给定日期是圣诞节还是元旦。请告知以下代码是否正常:

Declare @paramDate date
....
IF Month(@paramDate) = 12 and DAY(@paramDate) = 25
     or Month(@paramDate) = 1 and DAY(@paramDate) = 1
BEGIN
   ....

以上是我能想到的最简单的方法,无论是时区还是日期格式

【问题讨论】:

  • “简单”是指最少的字符/行数、最直观的还是其他?
  • @AaronBertrand 是的,这是正确的 ^^,这是一个很好的总结方式
  • @Dreamer:简单一般意味着,最容易理解,而不是最简单。
  • 好的,因为尽量减少字符数作为目标往往会产生相反的效果——它往往会使事情变得更加神秘和不直观。您的意思可能是简洁,而不是简单。
  • 我明白了,那么大多数时候最简单的应该更倾向于intuitive。很酷,我什至在这篇文章中完成了一个英语课,猜猜这是一个很大的胜利

标签: sql sql-server tsql


【解决方案1】:

我会创建一个像这样的表值函数,而不是我怀疑是基于您问题中的语法的标量函数。你的检查很好,我认为它们不能更简单而且仍然很直观,但另一种测试特定日期的方法是与DATEFROMPARTS()进行比较:

CREATE FUNCTION dbo.IsSpecificHoliday
(
  @d date
)
RETURNS table WITH SCHEMABINDING
AS
  RETURN 
  (
      SELECT IsSpecificHoliday = CASE @d
        WHEN DATEFROMPARTS(YEAR(@d), 12, 25) THEN 1
        WHEN DATEFROMPARTS(YEAR(@d), 1,  1) THEN 1
        ELSE 0 END
  );

示例用法:

CREATE TABLE dbo.Dates(TheDate date);

INSERT dbo.Dates(TheDate) VALUES
  ('19701214'),('19991225'),('20400101');

SELECT d.TheDate, f.IsSpecificHoliday
  FROM dbo.Dates AS d 
  CROSS APPLY dbo.IsSpecificHoliday(d.TheDate) AS f;

结果:

TheDate IsSpecificHoliday
1970-12-14 0
1999-12-25 1
2040-01-01 1

您也可以随时考虑使用calendar table(用于此目的和许多其他目的),并在其中有一个计算或预填充的列,如IsSpecificHoliday,然后在日期列上简单地加入该列。

【讨论】:

  • 日历表是一个很好的解决方案
  • @Aaron Bertrand 谢谢啊,很高兴知道 DATEFROMPARTS 函数,所以我想我的代码应该更改为 IF @paramDate =DATEFROMPARTS(YEAR(@paramDate), 12, 25) or @paramDate = DATEFROMPARTS(YEAR(@paramDate), 12, 25)
  • 日历表的性能更好吗?验证两个简单的假期有点矫枉过正
  • 当然,您可以使用IF 代替CASE。我的观点更多是关于确保您使用的是有效的内联表值函数,它可以合并到整体执行计划中,而不是标量值函数(通常)不能(并最终被执行 为每一个痛苦的行)。
  • @Dreamer 没错,这绝对是关于简化逻辑和灵活性而不是性能。如果您有 10 个不同的地方有此 IF 或 CASE 表达式,并且您需要添加 7 月 4 日或复活节或超级马里奥日或其他什么,您只需更新表格而不是这 10 个不同的地方。顺便说一句,祝你复活节好运。
【解决方案2】:

您可以将隐式转换与right() 函数配合使用

示例

Declare @date date = '2021-12-25'

Select case when right(@date,5) in ('12-25','01-01') then 1 else 0 end

显式转换

Declare @date date = '2021-12-25'

Select case when convert(varchar(5),@date,101)  in ('12/25','01/01') then 1 else 0 end

【讨论】:

  • 这种方法不如海报法。
  • 我不认为它本身是 坏,但你肯定在利用这种无证隐式转换,这种转换会继续折磨那些拥有像 @ 这样的代码的人当@StartDate 参数(或变量或列)从datetime 更改为date、datetime2 或datetimeoffset 时为987654325@。除非是代码高尔夫,否则我宁愿显式转换为特定样式。
  • 我知道参数的数据类型,我不知道未记录的隐式转换行为是否总是有效。 (除手动数据类型更改外,其他元素的行为发生了变化,例如视图中的 ORDER BY。)再次执行 显式 转换而不是依赖隐式转换确实不会造成任何伤害,除非目的是争夺最少的字符。还有一次:我不是说它不好。它可以以非常小的增量成本降低风险。
  • (不要介意创建的任何函数的维护者都可以随时以任何理由更改输入参数的类型,甚至无需查看代码,了解所做的假设或关心它可能会改变行为。这与我不喜欢依赖date 作为唯一例外的原因相同,我可以在任何语言中使用yyyy-mm-dd,或者即使在转换列时仍然可以搜索。这些例外非常脆。)
  • @Dreamer 列中的日期值不以任何格式存储。当 SQL Server 需要解释表示日期时间的字符串文字时,您会遇到语言环境问题,例如做DECLARE @d datetime = '2021-07-04 03:00:00.000'; 之类的事情,想知道为什么您会收到 7 月 4 日的报告,而您在欧洲的用户会收到 4 月 7 日的报告。 sqlblog.org/dates
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-28
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
  • 2017-11-29
相关资源
最近更新 更多