繁体   English   中英

DB2 Sql如何使用case语句?

[英]DB2 Sql how to use the case statement?

我正在尝试提取在2个工作日内到期的事件的所有事件结束日期。 因此,对于星期五和星期四,我希望​​日期在4天或更短的时间内结束,对于星期六的日期希望在3天之内结束,对于在两天之内结束的周三日期,对于在dateval列中列出的所有公共假期,我希望+3 。

下面的脚本不起作用,它仅将日期保留+2天。 我了解我需要使用案例声明,但实际上我不了解如何实现该声明。 有人有什么想法吗?

select event_end_date
from mdmins.table

/*separating by date to find expiring dates*/ 
where  (  (dayofweek(c.event_end_date) in (5,6) /*Friday & Thursday*/ 
and    date(c.event_end_date) < current_date + 4 days 
and    date(c.event_end_date) >= current_date) 
or     (dayofweek(c.event_end_date) in (1,2,3,4) /*All other days of week*/ 
and    date(c.event_end_date) < current_date + 2 days 
and    date(c.event_end_date) >= current_date) 
or     (dayofweek(c.event_end_date) = 7 /*Saturday - not that this should be needed, but just in case*/ 
and    date(c.event_end_date) < current_date + 3 days 
and    date(c.event_end_date) >= current_date) 
or     (date(c.event_end_date) < (select dateval from mdmins.tempdate where dateval = (current date + 3 days)) /*a holiday is on in 3 days, so 2 working days before*/ 
and    date(c.event_end_date) >= current_date) ) 

从逻辑上讲,一周数据之间唯一不同的是您的预期范围,因此将逻辑限制为使用案例:

...
where date(c.event_end_date) between current_date and current_date +
  case
    when dayofweek(c.event_end_date) in (5, 6) then 4
    when dayofweek(c.event_end_date) in (1, 2, 3, 4) then 2
    else 3
  end days
or (date(c.event_end_date) < (select dateval
  from mdmins.tempdate
  where dateval = (current date + 3 days)) 
  and date(c.event_end_date) >= current_date)
where ((date(c.event_end_date) between current_date and current_date +
  case
    when dayofweek(current date) in (5,6) then 4
    when dayofweek(current date) in (1, 2, 3, 4) then 2
    else 3
  end days)
  or    date(c.event_end_date) < (select dateval
      from mdmins.tempdate
      where dateval = (current date + 3 days)) 
      and date(c.event_end_date) >= current_date )

这是一个经典示例,说明了为什么要使用包含所有日期的日历以及大量附加信息。 您将可以执行以下操作:

WITH Desired_Dates AS (SELECT MIN(calendarDate) AS startRange,
                              MAX(calendarDate) + 1 DAY AS endRange
                       FROM(SELECT calendarDate
                            FROM Calendar
                            WHERE calendarDate >= CURRENT_DATE
                                  AND dayOfWeekISO IN (1, 2, 3, 4, 5)
                                  AND isHolday = '0'
                            ORDER BY calendarDate
                            FETCH FIRST 3 ROWS ONLY) D)
SELECT C.<column_list
FROM <Your_Table> C
JOIN Desired_Dates D
  ON C.event_end_date >= D.startRange
     AND C.event_end_Date < D.endRange

(请注意,我专门使用ISO星期几,其中星期一为1。星期日是1,在美国是星期天,从给定日期导出星期几的功能受当前的异想天开文化设置。此外,在event_end_date类似于时间戳的情况下,您希望使用专有的结束范围
实际上,这有很大的机会使用仅索引的信息来获取所需的日期(假设有相关的索引),并且在任何情况下都只会在CTE中获取一次数据。

如果您没有日历表,则可以创建一个:

WITH Working_Dates AS (SELECT CURRENT_DATE - 1 DAY AS calendarDate, 
                              0 AS workingDayNum, '0' AS isWorkingDay
                       FROM SYSIBM/SYSDUMMY1
                       UNION ALL 
                       SELECT calendarDate, 
                              workingDayNum + CASE WHEN isWorkingDay = 1
                                                   THEN 1
                                                   ELSE 0 END AS workingDayNum,
                              isWorkingDay
                       FROM (SELECT calendarDate, workingDayNum,
                                    CASE WHEN DAYOFWEEK_ISO(WD.calendarDate) IN (6, 7)
                                              OR Holiday.dateval IS NOT NULL 
                                         THEN '0'
                                         ELSE '1' END AS isWorkingDay
                             FROM (SELECT calendarDate + 1 DAY, workingDayNum
                                   FROM Working_Dates
                                   WHERE workingDayNum < 2) WD
                             LEFT JOIN mdmins.tempdate Holiday
                                    ON Holiday.dateval = WD.calendarDate) WD),

     Desired_Dates AS (SELECT MIN(calendarDate) AS startRange,
                              MAX(calendarDate) + 1 DAY AS endRange
                       FROM Working_Date
                       WHERE isWorkingDay = '1')

SELECT C.<column_list
FROM <Your_Table> C
JOIN Desired_Dates D
  ON C.event_end_date >= D.startRange
     AND C.event_end_Date < D.endRange

这是使用递归CTE循环从当前日期(一个日期之前)到经过三个工作日之间的几天。 (我必须提前一天开始,所以我只需要编写一次“这是一个工作日”逻辑,这也是所有嵌套的原因)。

请注意,您的原始尝试或任何现有的答案都不会考虑这些因素:

  1. 如果在星期五或星期一放假(跳过5天,而不是4天)会怎样?
  2. 如果顺序有多个假期(跳过的天数未知)会怎样?

通过建立实际工作日列表,我们可以使自己与问题隔离。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM