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 か月を追加する場合、正確な end_date を取得するには SQL クエリをどのように作成すればよいですか?

編集: 日付演算は、ネイティブ 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

なぜファクト テーブルなのか? ほとんどの DB は、日付/時刻操作をネイティブでサポートしています。MS SQL Server では、これをDATEADDで行います。

質問に「informix」のタグを付けましたが、質問でバージョンの詳細を指定していませんでした。 以下は、IBM Informix 11.50 の ADD_MONTHS 関数です。

于 2012-07-03T16:25:02.053 に答える
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 に答える
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 に答える