【发布时间】: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