(这是在DB2 V9.5中)
假设我有一个包含四列的表:
C1: [EmployeeId]
C2: [StartDate] yyyy-mm-dd format
C3: [EndDate] yyyy-mm-dd format
C4: [Age]
组合[EmployeeId + StartDate]构成主键 现在考虑以下示例行:
1 2010-01-16 2010-04-16 29
2 2010-02-16 2010-03-16 33
3 2010-05-16 2010-05-16 31
可以保证所有DAYS在所有日期的所有日期都是第16天。别无他法。
我正在尝试编写一个查询,它将执行以下操作:
对于起始月份小于结束月份的任何行(如第1行),复制其间的每个月的行,包括最后一行。因此,在运行查询后,第1行的新行将为:
1 2010-01-16 2010-04-16 29
1 2010-02-16 2010-04-16 29
1 2010-03-16 2010-04-16 29
1 2010-04-16 2010-04-16 29
对于起始月份和结束月份相同的行,不执行任何操作。对于结束月份是开始月份之后的月份的行,将插入一个新行(请参阅上面的最后一行以了解原因)。
问题:
感谢您的阅读。问题陈述很复杂,我希望我能做一个公平的工作来解释它。任何歧义或不一致:请指出,我会尽快编辑。
答案 0 :(得分:1)
我认为应该这样做:
SELECT e.employee_id, date(extract(year from startdate)||'-'||mm.month_nr||'-'||extract(day from startdate)) as stardate, first_value(e.enddate) over (partition by employee_id order by e.enddate) as enddate FROM ( VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12) ) mm (month_nr) JOIN emp_test e ON mm.month_nr = extract(month from e.startdate) ORDER BY e.employee_id, e.startdate, e.enddate
这当然假设startdate和enddate的数据类型是DATE
这只有在所有日期都在一年内才有效。
我只用DB2 9.7对它进行了测试,但我认为它也适用于9.5。
我认为年度交叉问题有一个解决方案:
WITH yrs (year_month) AS ( SELECT DATE(year_nr||'-'||month_nr||'-16') FROM ( VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12) ) mon (month_nr) CROSS JOIN ( VALUES (2007), (2008), (2009), (2010), (2011), (2012), (2013) ) yr (year_nr) ) SELECT e.employee_id, yrs.year_month as startdate, first_value(e.enddate) over (partition by employee_id order by e.enddate) as enddate FROM emp_test e JOIN yrs ON yrs.year_month between e.startdate and e.enddate
正如您所看到的那些年份被“硬编码”到CTE(公用表表达式)中。最简单的解决方案是生成一个包含所有可能值的“月/年”表 - 基本上是CTE生成的数据。
答案 1 :(得分:0)
FWIW一组属性和元组约束会在某种程度上简化:
CHECK (EXTRACT(DAY FROM StartDate) = 16),
CHECK (EXTRACT(DAY FROM EndDate) = 16),
CHECK (StartDate < EndDate)