2012-07-02 14 views
6

私は、日付として 'YYYY-MM-DD'形式の列を持つテーブルを持っています。 selectを使用して、月単位ですべてのデータを取得できますか? 2012-01-xxから2013-04-xxまでのすべてのデータを必要としているとします。だから私は基本的に下記のようなSQLクエリを探しています:Postgresqlは月の範囲から選択します

SELECT * FROM table WHERE date IN BETWEEN '2012-01' AND '2013-04' (INVALID QUERY) 

毎月ので、私は開始条件を調整するために上記のクエリを変更することができます「01」で始まります。

SELECT * FROM table WHERE date IN BETWEEN '2012-01-01' AND '2013-04' (INVALID QUERY) 

ここで問題は終了日が付いています。指定された日付が無効な場合、クエリが失敗するため、月の長さ、うるう年の年齢などのすべての要素を考慮して、指定した月の最後の日付を手動で計算する必要があります。だから私はこのような何かをやっている:

SELECT * FROM table WHERE date IN BETWEEN '2012-01-01' AND 'VALID_MONTH_END_DATE' (VALID Query) 

私はこの有効な終了日の計算を避ける方法があるかどうか知りたいですか?

明確化

私は次の月の最初の日の上に考えているが、その12月、来月は来年の1月になる場合でも、私は、言って、いくつかのロジックを適用する必要があります。私は、SQLのみのソリューションが可能かどうかを知りたがっていますか?

答えて

4

ショットの価値これは、環境報告では非常に一般的な必要性です。私は上記のすべての答えは、実用的なソリューションを提供しますが、一つの方法または他では不完全である...そして、あなたが使用できる

CREATE OR REPLACE FUNCTION public.fn_getlastofmonth (
    date 
) 
RETURNS date AS 
$body$ 
begin 
    return (to_char(($1 + interval '1 month'),'YYYY-MM') || '-01')::date - 1; 
end; 
$body$ 
LANGUAGE 'plpgsql' 
VOLATILE 
CALLED ON NULL INPUT 
SECURITY INVOKER 
COST 100; 

これらの日付操作に対応するために

WHERE date >= '2012-01-01' 
    AND date < fn_getlastofmonth('2013-04-01') 
10

BETWEENの日付範囲の比較は避けてください。 >=<を使用するほうが、日付と日付/時刻の列/値と同じように機能するため、使用することをお勧めします。

一つの方法(あなたは、外部の日付を構築することができる場合):

​​

ます。また、日付計算を使用することができます。

WHERE date >= DATE '2012-01-01' 
    AND date < DATE ('2013-04-01' + INTERVAL '1 MONTH') 

またはOVERLAPSオペレータ:

WHERE (date, date) OVERLAPS 
     (DATE '2012-01-01', DATE '2013-05-01') 

ますまた、Postgresのドキュメントを読むべきです:Date/Time Functions and Operators

manual explains here理由OVERLAPS作品この方法:

開始と終了は、それが 表す場合に等しくない限り、期間は半開区間を表すと考えられるたびに、< =時間<端を開始 その1つの時間インスタント。これは、例えば、2つの共通のエンドポイントを有する期間が重複しないことを意味する。

+0

オーバーラップがうまく動作します。私は先月が12月のときに立ち往生しています。 –

+0

どこからパラメータを取得しますか?アプリケーション?ウェブ?別のクエリ?あなたは文字列か整数(年、月)を持っていますか? –

+1

'date'に' interval'を追加するときは注意が必要です。結果は 'timestamp'です。しかし、上記の例では動作します。大事な場合は結果を 'date'にキャストしてください。 「n月」の間隔を追加すると、関連する月の実際の日数にかかわらず、結果として同じ日が常に表示されます。正確な日数を追加し、 'date'に' integer'を追加すると、 'date'が返されます。 –

0

をいくつかの関数を作成しました。私はSQL専用のソリューション(機能なし)を探していたので、上記のソリューションのベストヒントを組み合わせています。

私の質問のための理想的なソリューションは次のようになります。私は「エポックとして開始と終了のためのデフォルトの日付値を渡していますので、私はここにオーバーラップ機能を使用していない

SELECT * FROM table 
WHERE date >= '2012-01-01' AND date < date('2013-04-01') + interval '1 month' 

EDIT ' そしていま'。ユーザーが任意の時間範囲を指定していない場合、クエリは次のようになります。例の両方のために完璧に上記のコード作業しながら、

SELECT * FROM table 
WHERE date >= 'epoch' AND date < 'now' 

オーバーラップ機能は、「エポック」を扱うことができないと「今」と与え、SQLエラーが発生しました。

PS:私は正しい方法ですべての答えをupvotedし、このソリューションに私を導いた。

+0

私はあなたが ' - interval '1 day''部分を削除する必要があると思います。試してみましょう。テーブルの日付は「2013-04-30」です。 –

+0

私は毎月のデータを探しています。私は何年から何yyyy-mmにすべてのデータを取得する必要があると言う。私の終了日は常にyyyy-mm-01です。これに月を加えて1日を減算します。 –

+1

'SELECT * FROM table WHERE(日付、日付)オーバーラップ( '2012-01-01'、日付( '2013-04-01')+インターバル '1ヶ月' - インターバル '1日') 'の値が' 2013-04-30'のテーブルに 'date'があるときに'それは返されますか? –

0
SET search_path=tmp; 

DROP TABLE zdates; 
CREATE TABLE zdates 
     (zdate timestamp NOT NULL PRIMARY KEY 
     , val INTEGER NOT NULL 
     ); 
-- some data 
INSERT INTO zdates(zdate,val) 
SELECT s, 0 
FROM generate_series('2012-01-01', '2012-12-31', '1 day'::interval) s 
     ; 

UPDATE zdates 
SET val = 1000 * random(); 

DELETE FROM zdates 
WHERE random() < 0.1; 

-- CTE to round the intervals down/up to the begin/end of the month 
WITH zope AS (
     SELECT date_trunc('month', zdate)::date AS zbegin 
     , date_trunc('month', zdate+interval '1 month')::date AS zend 
     , val AS val 
     FROM zdates 
     ) 
SELECT z.zbegin 
     , z.zend 
     , COUNT(*) AS zcount 
     , SUM(val) AS zval 
FROM zope z 
GROUP BY z.zbegin, z.zend 
ORDER BY z.zbegin, z.zend 
     ; 

結果:私は最後の日付を知っているとき

CREATE TABLE 
INSERT 0 366 
UPDATE 366 
DELETE 52 
    zbegin | zend | zcount | zval 
------------+------------+--------+------- 
2012-01-01 | 2012-02-01 |  28 | 13740 
2012-02-01 | 2012-03-01 |  28 | 14923 
2012-03-01 | 2012-04-01 |  26 | 13775 
2012-04-01 | 2012-05-01 |  25 | 11880 
2012-05-01 | 2012-06-01 |  25 | 12693 
2012-06-01 | 2012-07-01 |  25 | 11082 
2012-07-01 | 2012-08-01 |  26 | 13254 
2012-08-01 | 2012-09-01 |  28 | 13632 
2012-09-01 | 2012-10-01 |  28 | 16461 
2012-10-01 | 2012-11-01 |  23 | 12622 
2012-11-01 | 2012-12-01 |  24 | 12554 
2012-12-01 | 2013-01-01 |  28 | 14563 
(12 rows) 
関連する問題