2016-06-21 16 views
0

Oracle SQLには非常に基本的な質問reg日付計算があります。私は年齢を計算し、年齢とともにレコードを識別するために、次のロジックを使用しているOracle SQLの日付計算

> = 75:

Date1 = MM-DD-2016 
Date2 = MM-DD-1947 
:上記のロジックは次のシナリオのために、誤って年齢を計算していましたが

(Date1 - Date2)/365.25 >= 75 

ここでは年齢は69歳ですが、それは私の成果に現れています。両方の日付のto_dateを追加した後、クエリはこのレコードを取得しませんでした。

私の質問は、このクエリの以前のto_dateを使用していないし、他のレコードでうまくいきましたが、なぜこのシナリオでは失敗しましたか?

編集:私は追加したい、部分的な日付が入力されたとき、以下のように私のデータベースレコード値を次のようになります。 日付1は1947年6月15日 日付2であるadd_months()機能を使用して2016年6月15日

+0

実際に計算された計算結果を見てきましたか?あなたはあなたのフィルターに合ったような特定の日付をつけられますか?そして...古い日付が間違った世紀ではなく1947年であることを確信していますか?あなたは4桁の年月日を照会/表示していますか(マイナス記号を許可していますか、 'SYYYY')? –

+0

これらはデータベース内の日付で、Date1は6/15/1947で、Date2は6月15日で、月と日はありません。部分日付を入力するとmy dbがこれらの値をとるようです。私は正直なところ、なぜそれがうまくいかず、ちょうどto_date関数を試してみて、それがうまくいくように思っていませんでした。初期のクエリが機能しなかった理由をまだ理解できませんか? – Skn

+0

すでに日付であれば、 'to_date()'は使用しないでください。年が-1947として入力されていないと確信していますか? 'date2 = to_date( ' - 1947-06-15'、 'SYYYY-MM-DD')'のテーブルを照会します。 –

答えて

1

次のとおりです。

where date1 >= add_months(date2, 75*12) 

月の計算は、日数に基づくものよりも正確です。

また、あなたはintervalを使用することができます。

where date1 >= date2 + interval '75' year 
+0

'date2'が2月29日、悲しいことに" ORA-01839:日付が指定された月に有効ではありません "の場合、間隔の計算に失敗します。 –

+0

ありがとうございます。しかし、私の最初のクエリがうまくいかなかった理由を説明できる人はいますか?私は、Oracleがこのクエリを使用して計算する方法を理解しようとしています。 – Skn

+0

元のクエリは近いですが、年間365.25日が近似値です。 12ヶ月はより正確です(ただし、うるう年にはしゃっくりがあります)。 –

0

あなたの代わりに1947年-1947として保存された日付を持っている場合、私はあなたがその結果を取得したい見ることができる唯一の方法は次のとおりです。

with t (Date1, Date2) as (
    select date '2016-06-15', add_months(date '2016-06-15', -12*level) 
    from dual 
    connect by level <= 80 
    union all 
    select date '2016-06-15', date '-1947-06-15' 
    from dual 
) 
select * from t 
where (Date1 - Date2)/365.25 >= 75; 

DATE1  DATE2  
---------- ---------- 
06/15/2016 06/15/1941 
06/15/2016 06/15/1940 
06/15/2016 06/15/1939 
06/15/2016 06/15/1938 
06/15/2016 06/15/1937 
06/15/2016 06/15/1936 
06/15/2016 06/15/1947 

最後のレコードはそこには存在しないように見えます。しかし、私のNLS_DATE_FORMATマスクはMM/DD/YYYY(あなたが見ているものと一致する)です。

alter session set nls_date_format = 'MM/DD/SYYYY'; 

with t (Date1, Date2) as (
    select date '2016-06-15', add_months(date '2016-06-15', -12*level) 
    from dual 
    connect by level <= 80 
    union all 
    select date '2016-06-15', date '-1947-06-15' 
    from dual 
) 
select * from t 
where (Date1 - Date2)/365.25 >= 75; 

DATE1   DATE2  
------------- ------------- 
6/15/ 2016 6/15/ 1941 
6/15/ 2016 6/15/ 1940 
6/15/ 2016 6/15/ 1939 
6/15/ 2016 6/15/ 1938 
6/15/ 2016 6/15/ 1937 
6/15/ 2016 6/15/ 1936 
6/15/ 2016 6/15/-1947 

あるいはさらに良い:私はそれが今年の兆候を示して作る場合には、より理にかなって

with t (Date1, Date2) as (
    select date '2016-06-15', add_months(date '2016-06-15', -12*level) 
    from dual 
    connect by level <= 80 
    union all 
    select date '2016-06-15', date '-1947-06-15' 
    from dual 
) 
select to_char(date1, 'SYYYY-MM-DD') as date1, to_char(date2, 'SYYYY-MM-DD') as date2 
from t 
where (Date1 - Date2)/365.25 >= 75; 

DATE1  DATE2  
----------- ----------- 
2016-06-15 1941-06-15 
2016-06-15 1940-06-15 
2016-06-15 1939-06-15 
2016-06-15 1938-06-15 
2016-06-15 1937-06-15 
2016-06-15 1936-06-15 
2016-06-15 -1947-06-15 

ですから、-1947から日付を見ることができる示すが、1947年からの日付れますそうではありません。そして、それは75年以上前にたくさんある:

select months_between(date '2016-06-15', date '-1947-06-15')/12 as years from dual; 

    YEARS 
---------- 
     3963 

自分の価値観を中心にto_date()を追加する理由は登場するレコードはあなたが暗黙的に日付を文字列に変換してから戻って日付をするだろうということです停止しました同じMM/DD/YYYY形式のマスクを使用します。中間の文字列はでなく、にはマイナス記号が含まれているので、date '-1947-06-15'06/15/1947という文字列になります。それが日付に変換されると、符号はまだ失われており、文字列06/15/1947date '1947-06-15'になります。 3963年前ではなく、今はわずか69年前です。