【问题标题】:Refactoring Ideas without Resorting to Inline Views?在不诉诸内联视图的情况下重构想法?
【发布时间】:2011-12-30 09:14:21
【问题描述】:

我创建了一个 SQL 用户定义函数来确定给定日期是否为日本假日。它现在由一大堆函数组成,这些函数第 *n* 次调用同一个内联视图,看起来并不明智。虽然我知道现实生活中最好的解决方案是构建一个日历表,但我不敢放弃我编写的所有代码行。我期待重构想法。谢谢。

函数isholiday(d) 只是捆绑了三个函数;每个都定义了三种类型的日本假期。

DELIMITER //
CREATE FUNCTION isholiday(d date) RETURNS int
BEGIN
DECLARE t int;
CASE WHEN isregularholiday(d) = 1
          THEN SET t = 1;
     WHEN iscarryoverholiday(d) = 1
          THEN SET t = 1;
     WHEN isdentholiday(d) = 1
          THEN SET t = 1;
     ELSE SET t = 0; END CASE;
RETURN t;
END
//

isregularholiday(d) 看起来像这样:

DELIMITER //
CREATE FUNCTION isregularholiday(d date) RETURNS int
BEGIN
DECLARE s int;
DECLARE t int;
SELECT count(*) INTO s
  FROM (SELECT holiday_desc
             , CASE WHEN SUBSTR(holiday_date, 3, 1) = '-'
                         THEN CAST(CONCAT_WS('-', YEAR(d), holiday_date) AS DATE)
                    WHEN holiday_date = 'ATH21'
                         THEN ATHLETIC_DATE(d)
  /*There are six mobile holidays but I shall spare you the other five. */     
               ELSE NULL END cnvt
          FROM holidays
         WHERE YEAR(d) BETWEEN valid_from AND valid_to) **base**
 WHERE cnvt = d;
CASE s WHEN 1 THEN SET t = 1;
       ELSE SET t = 0;
END CASE;
RETURN t;
END
//

函数参数 d(或其月份-日期值)不直接与 holiday_date 列匹配(参见 cnvt = d),因为某些假期的确切日期在功能上取决于年份,因此 CASE 表达式分支为多个功能。该函数将一直引用内联视图base

现在,除了基本的假期外,还有两种类型的假期,而且变化无常。我暂时称它们为结转假期和凹痕假期。结转假期的定义如下: 如果节假日H落在星期日,第一个非节假日的工作日是H的结转节假日。由于有几个节假日夹在一起,H的第一个非节假日工作日不一定是第二天或星期一。

凹假期是两个假期之间的工作日。结转优先于凹痕假期。

由于移动假期,这两种类型的假期都是移动和变化无常的,并且必须按年度计算。 iscarryoverholiday(d) 查询 base 并计算 d 到 d 之前的星期日之间的行数。如果计数等于 d 和上周日之间的日期差,则 d 是结转假日。

isdentholiday(d) 为 d、d-1 和 d+1 调用 isregularholiday()(每个参数的预期值为 0、1、1)。它还为 d 调用 iscarryoverholiday()(以获取 0),因此它读取 base 四次。啊……

我不会用更多的细节来打扰你。我只是想知道我是否可以做一些聪明的事情并定义最接近 MySQL 动态视图的东西。

感谢您阅读本文!

以防万一,此处使用的假期不包括星期日。

【问题讨论】:

  • “虽然我知道现实生活中最好的解决方案是构建一个日历表,但我不敢放弃我编写的所有代码行”。你已经回答并忽略了自己。我们为什么要打扰?
  • “我不敢放弃我写的所有代码行。”为什么不呢,如果出现更好的东西呢? (我曾经在 Oracle 中编写了一个用户定义的函数来将提供的字符串中每个单词的首字母大写,然后我才想到 Oracle 可能已经有一个函数可以做到这一点;我将我的函数称为 f_initcap ...)无论如何,您不必删除现有代码;停止使用它。

标签: mysql sql refactoring


【解决方案1】:

日历表格根本没有任何逻辑。你填充一次,就是这样。

即使您计算并存储了这个 世纪 的每一天(包括不是假期的日子)的假期状态,您仍然会使用不到 0.5 兆字节的磁盘空间。

date               DATE,
isHoliday          TINYINT,
isRegularHoliday   TINYINT,
isCarryOverHoliday TINYINT,
isDentHoliday      TINYINT

添加适当的索引后,您仍然只使用几兆字节。

PK                  (date)
IX_HOLIDAY          (isHoliday, date)
IX_RegularHoliday   (isRegularHoliday, date)
IX_CarryOverHoliday (isCarryOverHoliday, date)
IX_DentHoliday      (isDentHoliday, date)

然后,您可以简单地加入此表以确定日期是否是特定类型的假期。如果需要,您甚至可以在 is????Holiday() 函数中使用该表。

这是计算常量与存储常量的主要示例。你似乎能够做到后者,所以也许你应该......

【讨论】:

    【解决方案2】:

    我写了一个名为“假期清单”的脚本。基本上,它是一个表 UDF,它作为参数传递了一年,它返回一个“假期表”,然后我可以加入它来查找假期。这可以为您提供一个起点和一些关于如何处理假期的想法,您可以将日本假期的规则添加到脚本中......

    http://www.sqlservercentral.com/scripts/Date+Manipulation/74302/

    如果您想要该脚本但无法通过上述链接获得,请告诉我,我会通过电子邮件将其发送给您...该脚本是为 Microsoft SQL 编写的,在 mySQL 下工作可能需要进行一些代码更改,但脚本中没有什么太花哨的地方

    【讨论】:

    • 刚刚查看了您的代码。似乎最重要的部分是返回表格的 UDF。有什么聪明的 MySQL 解决方法吗?
    • 不太了解 mySQL,希望其中一位 mySQLguru 能够加入。新年快乐
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    相关资源
    最近更新 更多