0

結果を10進数にキャストして、日数の差を取得しようとしています:

SELECT
CAST( TO_DATE('2999-01-01','yyyy-mm-dd') - TO_DATE('2909-01-01','yyyy-mm-dd') AS DECIMAL )
;

2 番目の日付に 1 か月を追加すると、次のようになります。

SELECT
CAST( TO_DATE('2999-01-01','yyyy-mm-dd') - (TO_DATE('2909-01-01','yyyy-mm-dd') + INTERVAL '1 MONTH' * (1) ) AS DECIMAL )
;

エラーが表示されます: エラー: タイプ間隔を数値にキャストできません

OK、char にキャストして結果を取得できます。

SELECT
CAST( TO_CHAR( TO_DATE('2909-02-10','yyyy-mm-dd') - (TO_DATE('2909-01-01','yyyy-mm-dd') + INTERVAL '1 MONTH' * (1) ), 'DD') AS DECIMAL )
;

ただし、この場合、TO_CHAR キャストで変更された最初のクエリは機能しなくなります。

SELECT
CAST( TO_CHAR(TO_DATE('2999-01-01','yyyy-mm-dd') - TO_DATE('2909-01-01','yyyy-mm-dd'), 'DD') AS DECIMAL )
;

ERROR: 複数の小数点があります。

だから、私の質問は、どうすれば同じ sql ステートメントを使用して日数を取得できますか? 両方の SQL クエリに対して。

4

3 に答える 3

4

最初の 2 つの例をもう一度見てください。外側の CAST ... AS DECIMAL を削除すると、

 ?column? 
----------
    32872

  ?column?  
------------
 32841 days

明らかに違いは「日」にあります。2 番目は、単純な数値ではなく間隔値です。数字だけが必要なので (常に日だけが必要なため)、その部分を抽出する必要があります。次に、好きな精度にキャストできます。

SELECT extract(days FROM '32841 days'::interval)::numeric(9,2);
 date_part 
-----------
  32841.00

Alexandr のフォローアップに対応して編集します。

最初の例はかなり具体的なエラーで失敗します:

SELECT extract(days FROM (TO_DATE('2999-01-01','yyyy-mm-dd') - TO_DATE('2909-01-01','yyyy-mm-dd'))::interval)::numeric(9,2);

ERROR:  cannot cast type integer to interval
LINE 1: ...yyyy-mm-dd') - TO_DATE('2909-01-01','yyyy-mm-dd'))::interval...

ここでは、整数 (最初に望んでいたもの) を取得し、それを間隔にキャストしようとしています (理由はわかりません)。必要な単位がわからないと不平を言っています。32872秒、数時間、数週間、数世紀の間隔で何が必要ですか?

2 番目の例は、単純な整数から「日」の部分を抽出しようとしているため、不平を言っています。もちろん、システムにはそれを行うための extract() 関数はありません。

おそらく一歩下がって、時間をかけて、さまざまな式が返す値を理解する必要があると思います。

ある日付を別の日付から引くと、それらの間の日数が整数として得られます。本当に他に賢明な手段はありません。

日付に間隔を加算 (または減算) すると、タイム スタンプ (タイム ゾーンなし) が得られます。

結果には日、時間、秒などが含まれる可能性があるため、日付からタイムスタンプを引くと間隔が得られます。

間隔があり、日の部分だけが必要な場合は、extract() を使用すると、整数の日数が返されます。

間隔をスカラー数にキャストすることは単位なしでは意味がないため、間隔ではなく数値にキャストする場合は、整数 (または浮動小数点) の日数が必要になります。

したがって、日付と日付の計算に固執するか (簡単)、タイムスタンプを使用していることに気付きますが (柔軟)、それがどれであるかを理解してください。

何が起こっているのかを説明するには、次のようにします (psql で):

CREATE TEMP TABLE tt AS SELECT
  ('2909-01-02'::date - '2909-01-01'::date) AS a,
  ('2909-01-02'::date - '2909-01-02 00:00:00'::timestamp) AS b;
\x
SELECT * FROM tt;
\d tt

これにより、扱っている値と型が表示されます。役立つと思われる列の数だけ繰り返します。

HTH

于 2012-12-11T09:44:02.047 に答える
1

日付で区間演算を行っている場合は、通常、docsに記載されているように、代わりにタイムスタンプを使用する必要があります。

# SELECT extract(days FROM TO_TIMESTAMP('2999-01-01','yyyy-mm-dd') - TO_TIMESTAMP('2909-01-01','yyyy-mm-dd'))

 date_part 
-----------
     32872

# SELECT extract(days FROM TO_TIMESTAMP('2999-01-01','yyyy-mm-dd') - (TO_TIMESTAMP('2909-01-01','yyyy-mm-dd') + '1 month'::interval) );
 date_part 
-----------
     32841
于 2012-12-11T12:25:24.650 に答える
0

間隔を日付に追加した結果は、実際には別の日付ではなくタイムスタンプです (間隔には時間部分が含まれている可能性があります)。そのため、加算の結果を最初に日付に戻す必要があります。

SELECT
CAST( TO_DATE('2999-01-01','yyyy-mm-dd')
       - CAST( (TO_DATE('2909-01-01','yyyy-mm-dd') + INTERVAL '1 MONTH' * (1) ) AS DATE)
      AS DECIMAL )
于 2012-12-11T11:53:42.930 に答える