sql >> データベース >  >> RDS >> PostgreSQL

Postgresqlで動的な12営業日ビューを取得するにはどうすればよいですか?

    これはCTEで解決できます:

    WITH business_days_back AS (
      WITH RECURSIVE bd(back_day, go_back) AS (
        -- Go back to the previous Monday, allowing for current_date in the weekend
        SELECT CASE extract(dow from current_date)
                 WHEN 0 THEN current_date - 6
                 WHEN 6 THEN current_date - 5
                 ELSE current_date - extract(dow from current_date)::int + 1
               END,
               CASE extract(dow from current_date)
                 WHEN 0 THEN 7
                 WHEN 6 THEN 7
                 ELSE 12 - extract(dow from current_date)::int + 1
               END
        UNION
        -- Go back by the week until go_back = 0
        SELECT CASE
             WHEN go_back >= 5 THEN back_day - 7
             WHEN go_back > 0 THEN back_day - 2 - go_back
           END,
           CASE
             WHEN go_back >= 5 THEN go_back - 5
             WHEN go_back > 0 THEN 0
           END
        FROM bd
      )
      SELECT back_day FROM bd WHERE go_back = 0
    )
    SELECT * FROM my_table WHERE analysis_date >= (SELECT * FROM business_days_back);

    説明:

    • 内部CTEは、前の月曜日に戻ってcurrent_dateを補正することから始まります。 それは週末の日に当てはまります。
    • 再帰項は、丸1週間前に戻ることで行を追加します(back_day - 7 カレンダーの日付とgo_back - 5 営業日)go_back = 0まで 。
    • 外部CTEはback_dayを返します go_back = 0の日付 。したがって、これはスカラークエリであり、フィルタ式のサブクエリとして使用できます。

    12の数字を変更するだけで、振り返る営業日数を変更できます。 および7 最初のSELECTで 内側のCTEで。ただし、値は前の月曜日に戻るような値にする必要があります。そうしないと、最初のSELECTが同じであるため、クエリが失敗します。 内側のCTEの。

    はるかに柔軟な(そしておそらくより高速な*)ソリューションは、次の関数を使用することです。

    CREATE FUNCTION business_days_diff(from_date date, diff int) RETURNS date AS $$
    -- This function assumes Mon-Fri business days
    DECLARE
      start_dow int;
      calc_date date;
      curr_diff int;
      weekend   int;
    BEGIN
      -- If no diff requested, return the from_date. This may be a non-business day.
      IF diff = 0 THEN
        RETURN from_date;
      END IF;
    
      start_dow := extract(dow from from_date)::int;
      calc_date := from_date;
    
      IF diff < 0 THEN -- working backwards
        weekend := -2;
        IF start_dow = 0 THEN -- Fudge initial Sunday to the previous Saturday
          calc_date := calc_date - 1;
          start_dow := 6;
        END IF;
        IF start_dow + diff >= 1 THEN -- Stay in this week
          RETURN calc_date + diff;
        ELSE                             -- Work back to Monday
          calc_date := calc_date - start_dow + 1;
          curr_diff := diff + start_dow - 1;
        END IF;
      ELSE -- Working forwards
        weekend := 2;
        IF start_dow = 6 THEN -- Fudge initial Saturday to the following Sunday
          calc_date := calc_date + 1;
          start_dow := 0;
        END IF;
        IF start_dow + diff <= 5 THEN -- Stay in this week
          RETURN calc_date + diff;
        ELSE                             -- Work forwards to Friday
          calc_date := calc_date + 5 - start_dow;
          curr_diff := diff - 5 + start_dow;
        END IF;
      END IF;
    
      -- Move backwards or forwards by full weeks
      calc_date := calc_date + (curr_diff / 5) * 7;
    
      -- Process any remaining days, include weekend
      IF curr_diff % 5 != 0 THEN
        RETURN calc_date + curr_diff % 5 + weekend;
      ELSE
        RETURN calc_date;
      END IF;
    END; $$ LANGUAGE plpgsql STRICT IMMUTABLE;

    この関数は、計算に任意の日付と将来の任意の日数を取ることができます(diffの正の値 )または過去(diffの負の値 )、今週内の差分を含みます。また、営業日の日付をスカラーとして返すため、クエリでの使用は非常に簡単です。

    SELECT * 
    FROM table
    WHERE analysis_date >= business_days_diff(current_date, -12);
    

    それとは別に、テーブルからフィールドを渡して、次のようなファンキーなことを行うこともできます。

    SELECT t1.some_value - t2.some_value AS value_diff
    FROM table t1
    JOIN table t2 ON t2.analysis_date = business_days_diff(t1.analysis_date, -12);
    

    つまり、特定の営業日数の分離で自己参加します。

    この関数は、月曜日から金曜日の営業日を想定していることに注意してください。

    *この関数は、スカラー値に対して単純な算術演算のみを実行します。 CTEは、反復と結果のレコードセットをサポートするために、あらゆる種類の構造を設定する必要があります。




    1. INSERTおよびAUTO-INCREMENT列を使用したSQLステートメントのエラー

    2. MySQLトランザクションでのレイテンシの処理

    3. Oracle用のSQL挿入を生成しています

    4. SpringJDBCTemplate-1つのクエリで複数のパラメータを使用して複数の結果を取得する方法