创建一个 SQL 函数,如果日期是假期则返回

Posted

技术标签:

【中文标题】创建一个 SQL 函数,如果日期是假期则返回【英文标题】:Creating a SQL Function that return if a date it's an holiday 【发布时间】:2021-12-18 21:30:19 【问题描述】:

我需要创建一个日历,在一行中显示一个月中的所有日期。 然后我需要显示同一个月的另一行,但使用当天的第一个字母(M 表示周一 - S 表示周日等),如果是假日日期,则添加一个字母(C 表示民用,R 表示宗教) .

输出示例:

Date           Day
gennaio  2022, 1,  2, 3, 4, 5,  6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
gennaio  2022, Sr, D, L, M, M, Gr, V, S, D,  L,  M,  M,  G,  V,  S,  D,  L,  M,  M,  G,  V,  S,  D,  L,  M,  M,  G,  V,  S,  D,  L
febbraio 2022, 1,  2, 3, 4, 5,  6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, <null>, <null>, <null>
febbraio 2022, M,  M, G, V, S,  D, L, M, M,  G,  V,  S,  D,  L,  M,  M,  G,  V,  S,  D,  L,  M,  M,  G,  V,  S,  D,  L, <null>, <null>, <null>

我使用包含所有假期日期的表格并从中进行选择以返回那天是否是假期。

我想知道是否有可能以及如何创建一个函数,如果日期是假期则返回而不需要额外的表(我从 2021 年 1 月 1 日到 2025 年 1 月 12 日创建,意思是更早或更晚都会出错)

我是意大利人,由于除复活节外所有假期都是固定的,我想该函数只需要计算复活节日期,我可以插入所有其他假期。

它的想法是通过函数从日期间隔(在我的情况下是从 1-01-2021 到 31-12-2025)中进行选择,然后将其格式化为具有如上所示的 2 列和所有日期和假期。

提前谢谢大家。

【问题讨论】:

函数应该如何知道某天是否是假期?您必须将它们存储在某个地方:在表格中或在代码中硬编码。为清楚起见,最好将所有内容存储在一个地方(在您的情况下是在一个表格中),因为当某些内容存储在表格中并且在代码中计算一个假期时,它可能会令人困惑。 @astentx 是的,我也是这么想的。在我的第一次尝试中,我确实逐年创建了一个包含所有假期的表格。当您学习如何计算复活节时,其他所有日子都保持不变。问题是我的老师不希望我这样做,因为它应该是可以在单个查询中完成的事情 + 一个支持它的函数。一旦完成,你就再也不要碰它了。使用表格,我需要添加不存在的年份。 【参考方案1】:

你可以根据Gauss's Easter algorithm计算复活节:

CREATE OR REPLACE FUNCTION Easter(yyyy IN INTEGER DEFAULT TO_CHAR(SYSDATE, 'YYYY')) RETURN DATE IS

    a INTEGER;
    b INTEGER;
    c INTEGER;
    d INTEGER;
    e INTEGER;
    f INTEGER;
    g INTEGER;
    h INTEGER;
    i INTEGER;
    k INTEGER;
    l INTEGER;
    m INTEGER;
    n INTEGER;
    p INTEGER;
    EM INTEGER;
    ED INTEGER;

BEGIN

    a := yyyy MOD 19;
    b := TRUNC(yyyy / 100);
    c := yyyy MOD 100;
    d := TRUNC(b / 4);
    e := b MOD 4;
    f := TRUNC((b + 8) / 25);
    g := TRUNC((b - f + 1) / 3);
    h := (19*a + b - d - g + 15) MOD 30;
    i := TRUNC(c / 4);
    k := c MOD 4;
    l := (32 + 2*e + 2*i - h - k) MOD 7;
    m := TRUNC((a + 11*h + 22*l) / 451);
    n := TRUNC((h + l - 7*m + 114) / 31);
    p := (h + l - 7*m + 114) MOD 31;
    EM := n;
    ed := p + 1;
    
    RETURN TO_DATE(yyyy||'-'||EM||'-'||ed, 'YYYY-MM-DD');
END Easter;

对于其他日子,你必须提出一些简单的逻辑,例如

TO_CHAR(inputDate, 'MM-DD') = '12-25'

圣诞节。有些假期被定义为“11 月的第三个星期一”,可能是这个:

TRUNC(inputDate) = NEXT_DAY(TRUNC(inputDate, 'MM')-1, 'MONDAY') + 2 * 7

简化示例:

CREATE OR REPLACE FUNCTION IsHoliday(d IN DATE) RETURN BOOLEAN IS
   easter DATE := Easter(TO_CHAR(d, 'YYYY'));
BEGIN

   IF TO_CHAR(d, 'Dy', 'NLS_DATE_LANGUAGE = "American"') IN ('Sat','Sun') THEN RETURN TRUE; -- Weekend
   IF TRUNC(d) = easter + 1 THEN RETURN TRUE; -- Easter Monday
   IF TO_CHAR(d, 'MM-DD') IN ('12-25', '12-26') THEN RETURN TRUE; -- Christmas
   IF TO_CHAR(d, 'MM-DD') = '05-01' THEN RETURN TRUE; -- Festa del Lavoro
   ... some more
   RETURN FALSE;

END IsHoliday;

另一种方法是DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING,例如:

DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING(
   --Wednesday before November 23th 
   'FREQ=DAILY;BYDATE=1122-SPAN:7D;BYDAY=WED', 
   NULL, TRUNC(d, 'YYYY')-1, next_run_date);
IF TRUNC(d) = next_run_date THEN RETURN TRUE;

见more examples

【讨论】:

谢谢,我会尽快实现这些,我会告诉你的。感谢您详尽而快速的回复。 抱歉回复晚了。在你的帮助下,我设法使它工作。非常感谢。

以上是关于创建一个 SQL 函数,如果日期是假期则返回的主要内容,如果未能解决你的问题,请参考以下文章

(My)SQL:如果子查询不是空集,则返回子查询

如果一列为 Null,则 SQL 返回 Null(与 COALESCE() 相反)

如何创建 SQL Server 函数以返回 int?

sql Oracle SQL:返回当前月份第一天的字符串(如果其他月份为ar,则替换SYSDATE的任何日期字段/值

netezza sql中2个日期之间的月份

第四十三章 SQL函数 DATEDIFF