1

私はこれに数時間取り組んできましたが、運がなく、壁にぶつかりました。私のデータは次のようになります。

Date1          Date2
2012-05-06     2012-05-05
2012-03-20     2012-01-05

私がやろうとしているのは、2つの日付の間の毎月のカウントに1を追加することです。したがって、私の出力は理想的には次のようになります。

Year    Month    Sum
2012    2        1

つまり、2つの日付の間の「空の」月をチェックし、それらに1を追加する必要があります。

これは私がこれまでに作成したコードです。基本的に、2つの日付の間の月数をカウントし、それらを月と年にグループ化します。

SELECT 
    EXTRACT(YEAR FROM Date2::date) as "Year", 
    EXTRACT(MONTH FROM Date2::date) as "Month",
    SUM(DATE_PART('year', Date1::date) - DATE_PART('year', Date2::date)) * 12 +
    (DATE_PART('month', Date1::date) - DATE_PART('month', Date2::date))
FROM
    test
GROUP BY 
    "Year", 
    "Month",
ORDER BY
    "Year" DESC, 
    "Month" DESC;

これは私が立ち往生しているところです-「空の」月ごとに実際に1を追加する方法がわかりません。

4

3 に答える 3

3

テスト設定

いくつかのサンプル行を使用して(質問で提供する必要があります):

CREATE TABLE test (
   test_id serial PRIMARY KEY
 , date1   date NOT NULL
 , date2   date NOT NULL
);

INSERT INTO test(date1, date2)
VALUES
   ('2012-03-20', '2012-01-05')  -- 2012-02 lies in between
 , ('2012-01-20', '2012-03-05')  -- 2012-02 (reversed)
 , ('2012-05-06', '2012-05-05')  -- nothing
 , ('2012-05-01', '2012-06-30')  -- still nothing
 , ('2012-08-20', '2012-11-05')  -- 2012-09 - 2012-10
 , ('2012-11-20', '2013-03-05')  -- 2012-12 - 2013-02
;

Postgres9.3以降_

LATERAL結合を使用します:

SELECT to_char(mon, 'YYYY') AS year
     , to_char(mon, 'MM')   AS month
     , count(*) AS ct
FROM  (
   SELECT date_trunc('mon',    least(date1, date2)::timestamp) + interval '1 mon' AS d1
        , date_trunc('mon', greatest(date1, date2)::timestamp) - interval '1 mon' AS d2
   FROM   test
   ) sub1
 , generate_series(d1, d2, interval '1 month') mon  -- implicit CROSS JOIN LATERAL
WHERE  d2 >= d1 -- exclude ranges without gap right away
GROUP  BY mon
ORDER  BY mon;

Postgres9.2以前

いいえLATERAL、まだです。代わりにサブクエリを使用してください。

SELECT to_char(mon, 'YYYY') AS year
     , to_char(mon, 'MM')   AS month
     , count(*) AS ct
FROM  (
   SELECT generate_series(d1, d2, interval '1 month') AS mon
   FROM  (
      SELECT date_trunc('mon',    least(date1, date2)::timestamp) + interval '1 mon' AS d1
           , date_trunc('mon', greatest(date1, date2)::timestamp) - interval '1 mon' AS d2
      FROM   test
      ) sub1
   WHERE  d2 >= d1 -- exclude ranges without gap right away
   ) sub2
GROUP  BY mon
ORDER  BY mon;

結果

 year | month | ct
------+-------+----
 2012 |     2 |  2
 2012 |     9 |  1
 2012 |    10 |  1
 2012 |    12 |  1
 2013 |     1 |  1
 2013 |     2 |  1

db<>fiddleここで
SQLFiddle。

説明

2つの日付の間の完全な暦月を探しています。

これらのクエリは、日付またはタイムスタンプを昇順または降順で処理し、正常に機能するはずです。

start> endの場合、行を返さないため、このWHERE句はオプションです。generate_series()ただし、空の範囲を事前に除外する方が少し速いはずです。

timestampそれを少しきれいにそしてより速くするためのキャスト。理論的根拠:

于 2012-07-27T00:18:56.540 に答える
0

AFAIKでは、postgresqlで日付を簡単に差し引いたり追加したりできます

'2001-06-27 14:43:21'::DATETIME - '2001-06-27 14:33:21'::DATETIME = '00:10:00'::INTERVAL

したがって、あなたの場合、そのリクエスト部分は次のようになります。

DATE_PART('month', Date1::datetime - Date2::datetime) as "MonthInterval"
于 2012-07-26T15:53:54.600 に答える
0

age(timestamp1、timestamp2)=>間隔を返します

間隔から年と月を抽出し、それに応じて追加しようとします。

select extract(year from age(timestamp1、timestamp2))* 12 + extract(month from age(timestamp1、timestamp2))

于 2014-10-09T12:28:06.340 に答える