3

私は PostgreSQL にかなり慣れていませんが、最近私のプロジェクトで、特定の週のすべてのレコードを取得する際に問題が発生しました。もちろん、主な問題は境界週 (1 および 52/53) にあります。

このために、私は関数を書きました:

CREATE OR REPLACE FUNCTION week_dates(_week integer, _year integer) RETURNS date[] AS $$
DECLARE
    result date[];
BEGIN
    WITH RECURSIVE dates(wdate) AS (
        SELECT MAX(date) AS wdate FROM time WHERE woy = _week AND year = _year AND dow > 3
        UNION ALL
        SELECT wdate-1 AS wdate FROM dates WHERE EXTRACT(WEEK from (wdate-1)) = _week 
    ),
    dates2(wdate) AS (
        SELECT MAX(wdate) AS wdate FROM dates 
        UNION ALL
        SELECT wdate+1 AS wdate FROM dates WHERE EXTRACT(WEEK from (wdate+1)) = _week 
    ),
    sorted AS ((SELECT * FROM dates) UNION (SELECT * FROM dates2) ORDER BY wdate ASC)
    -- sorted AS (SELECT wdate FROM dates ORDER BY wdate ASC)
    SELECT array_agg(wdate) INTO result FROM sorted;
    -- SELECT wdate FROM sorted;
    RETURN result;
END;
$$ LANGUAGE plpgsql;

そして、その使用法は、例えば次のとおりです。

SELECT * FROM "some_report_cache_table" WHERE "date" = ANY(week_dates(1, 2013));

これに対するより優れた/より高速な/より簡単なソリューションはありますか (おそらくいくつかの組み込み機能)?

私は PostgreSQL 9.2 を使用しています。週とは、ISO の週を意味します (月曜日から始まります)。

4

2 に答える 2

4

はるかに単純ですが、次のようになります。

CREATE OR REPLACE FUNCTION week_dates(_week integer, _year integer)
  RETURNS SETOF date AS
$func$
SELECT date_trunc('week', ($2::text || '-1-4')::timestamp)::date
       + 7 * ($1 - 1)  -- fix off-by-one
       + generate_series (0,6)
$func$ LANGUAGE sql;

重要な点は、PostgreSQL で日数をinteger追加できることです。を返すので、別の時間にキャストする必要があります。date
date_trunc()timestampdate

私は1月4日から始めます(ここでマニュアルを引用します):

定義 (ISO 8601) では、週は月曜日から始まり、年の最初の週にはその年の 1 月 4 日が含まれます。

この関数は、 orのような不可能な週を喜んで受け入れ、ある程度妥当な結果を返します。それを禁止するには、それを plpgsql 関数にして、入力値をチェックします。-155

これは、配列ではなくセットを返します。代わりに配列にするのは簡単です(SELECT ARRAY(SELECT ...)。しかし、これはより速いはずです。クエリは次のようになります。

SELECT *
FROM   some_report_cache_table
JOIN   week_dates(1, 2013) w("date") USING ("date")

余談: SQL の予約語でdateあるため、列名として使用しないでください。

于 2013-05-17T16:02:14.463 に答える