1

编辑: begin_date 和 end_date 是任何表中的类型 DATE 列。

我有以下维度表,它提供了从 1980 年到 2500 年每个月的总天数:

CREATE TABLE total_days
    (
from_date     DATE,
to_date       DATE,
days_in_month SMALLINT
    );

from_date   to_date     days_in_month
1980-01-01  1980-01-31  31
1980-02-01  1980-02-29  29
...
2500-11-01  2500-11-30  30
2500-12-01  2500-12-31  31

如果要向 begin_date 添加 360 个月,我应该如何构造 SQL 查询以获得准确的 end_date?.. 我是否需要以任何方式更改维度表以实现我的目标?

编辑:必须在不使用任何本机 SQL 日期算术函数的情况下执行日期算术。必须通过在维度表中查找 begin_date 来完成。

4

6 回答 6

3

我想你有你的理由 - 这是一个非常简单的技巧 - 假设事实表每个月都有一行 - 添加一个代表月份编号的新列,从 1 开始并按时间顺序自动递增,而不是重新开始每年。

SELECT B.* 
FROM SO_total_days2 A
INNER JOIN SO_total_days2 B ON B.monthnumber = A.monthnumber + 360
WHERE A.from_date =  '2010-01-01'

from_date   to_date     days_in_month monthnumber
1980-01-01  1980-01-31  31    1
1980-02-01  1980-02-29  29    2
1980-03-03  1980-03-31  31    3
...
1981-01-01  1981-01-31  31    13
1981-12-01  1981-12-31  31    24
...
1985-01-01  1985-01-31  31    49
1985-12-01  1985-12-31  31    60
于 2012-07-03T21:35:08.643 回答
2

这就是我想象你的“事实表”的样子:

declare @dt datetime
    set @dt = '7-1-2012'

;
with date_table as  (
        select  @dt as [Start Date],
                dateadd(d,-1,dateadd(mm,1,@dt)) as [End Date],
                datepart(d,dateadd(d,-1,dateadd(mm,1,@dt))) as [Days]

        union ALL

        select  dateadd(mm, 1, [Start Date]) as  [Start Date],
                dateadd(d,-1,dateadd(mm,1,dateadd(mm, 1, [Start Date]))) as [End Date], 
                datepart(d,dateadd(d,-1,dateadd(mm,1,dateadd(mm, 1, [Start Date])))) as [Days]

        from    date_table
        where   dateadd(mm, 1, [Start Date]) <= dateadd(m,500,@dt))

select  [Start Date], [End Date], [Days]
into    #temp
from    date_table

option (MAXRECURSION 0)

这是选择日期。(注意这些语句中没有包含 DATEADD 或 DATEPART)

select  finish.[Start Date], finish.[End Date], finish.[Days]
from    (select rownum
         from   (select [Start Date], [End Date], [Days], row_number() over (order by [Start Date]) as rownum
                    from    #temp) as x
         where  x.[Start Date] = '2012-07-01 00:00:00.000' ) as start 

        join    (select [Start Date], [End Date], [Days], 
                        row_number() over (order by [Start Date]) as rownum
                 from   #temp) as finish
            on finish.rownum = start.rownum + 360

我在下面阅读了您的评论...如果您想总结日子或其他事情,这就是您可以做到的:(因此从 2012 年 7 月 1 日开始,持续 360 个月... date_diff_days 结果将是360 个月的总天数...使用我制作的#temp 表...我假设它与您的事实表相似...我有 10957 天)

select  sum(dayscount.[Days]) as date_diff_days
from    (select rownum
         from   (select [Start Date], [End Date], [Days], row_number() over (order by [Start Date]) as rownum
                    from    #temp) as x
         where  x.[Start Date] = '2012-07-01 00:00:00.000' ) as start 

        join    (select [Start Date], [End Date], [Days], 
                        row_number() over (order by [Start Date]) as rownum
                 from   #temp) as finish
            on finish.rownum = start.rownum + 360

        join (select    [Start Date], [End Date], [Days], 
                        row_number() over (order by [Start Date]) as rownum
                 from   #temp) as dayscount
            on dayscount.rownum >= start.rownum and 
                dayscount.rownum < finish.rownum 
于 2012-07-03T16:49:40.110 回答
2

如果我要与数据库无关,我会稍微更改一下事实表:

CREATE TABLE total_days
(
  year          INT,
  month         TINYINT,
  from_date     DATE,
  to_date       DATE,
  days_in_month SMALLINT
);

year  month  from_date   to_date     days_in_month
------------------------------------------------
1980    1    1980-01-01  1980-01-31   31
1980    2    1980-02-01  1980-02-29   29
...
2500   11    2500-11-01  2500-11-30   30
2500   12    2500-12-01  2500-12-31   31

然后你可以使用类似的东西:

SELECT td.* 
FROM 
      total_days AS td 
   CROSS JOIN
      ( SELECT year, month
        FROM total_days 
        WHERE from_date <= @StartingDate 
          AND @StartingDate <= to_date
      ) AS st
   CROSS JOIN
      ( SELECT 360 AS add_months ) AS param
WHERE td.year = st.year + ( st.month -1 + add_months ) / 12
  AND td.month = 1 + ( st.month - 1 + add_months ) % 12 )
;

或更简单的(但更难优化效率:

WHERE 12 * td.year + td.month = 
      12 * st.year + st.month + add_months
于 2012-07-03T17:26:40.760 回答
1

为什么是事实表?大多数数据库对日期/时间操作都有本机支持。在 MS SQL Server 中,您可以使用DATEADD执行此操作。

我看到您用“informix”标记了您的问题,但没有在您的问题中指定任何版本详细信息。 这是来自 IBM Informix 11.50 的 ADD_MONTHS 函数。

于 2012-07-03T16:25:02.053 回答
0

你可以使用间隔

mysql> SELECT '2008-12-31 23:59:59' + INTERVAL 1 month;
+------------------------------------------+
| '2008-12-31 23:59:59' + INTERVAL 1 month |
+------------------------------------------+
| 2009-01-31 23:59:59                      |
+------------------------------------------+
1 row in set (0.00 sec)


mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2012-07-03 12:27:46 |
+---------------------+
1 row in set (0.00 sec)

mysql> SELECT now() + INTERVAL 30 month;
+---------------------------+
| now() + INTERVAL 30 month |
+---------------------------+
| 2015-01-03 12:27:49       |
+---------------------------+
1 row in set (0.00 sec)

编辑:

mysql> SELECT STR_TO_DATE('01,5,2013','%d,%m,%Y') + interval 30 month;
+---------------------------------------------------------+
| STR_TO_DATE('01,5,2013','%d,%m,%Y') + interval 30 month |
+---------------------------------------------------------+
| 2015-11-01                                              |
+---------------------------------------------------------+
1 row in set (0.00 sec)

编辑2:

mysql> show create table tiempo;
+--------+------------------------------------------------------------------------------------------------+
| Table  | Create Table                                                                                   |
+--------+------------------------------------------------------------------------------------------------+
| tiempo | CREATE TABLE `tiempo` (
  `fecha` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+--------+------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select fecha + interval 20 month from tiempo;
+---------------------------+
| fecha + interval 20 month |
+---------------------------+
| NULL                      |
| 2001-10-02 02:02:02       |
+---------------------------+
2 rows in set (0.00 sec)
于 2012-07-03T16:28:22.630 回答
0

如果您的起始日期与列出的完全相同,并且您总是添加月份,您可以使用这个:

SELECT max (to_date)
  FROM (SELECT ROW_NUMBER () OVER (ORDER BY from_date) AS Row,
                from_date,
                to_date,
                days_in_month
         FROM total_days
        WHERE from_date > '1/1/1982'
      GROUP BY from_date, to_date, days_in_month) MyDates
 WHERE Row <= 360
于 2012-07-03T21:23:51.447 回答