2017-04-07 9 views
0

以下の2つのクエリの違いを理解しようとしています。 2番目は構文エラーをスローします。誰か助けてもらえますか?Oracle sql WITH句とEXTRACT関数

1.

select 
    extract(year from (sysdate - to_date('2002-12-25')) year to month) Y 
from dual; 

2.

with age(d) as 
(
    select (sysdate - to_date('2002-12-25')) from dual 
) 
select 
    extract(year from (age.d) year to month) Y 
from age; 

エラー: ORA-30083:構文エラーが間隔値の式 30083. 00000で発見された - 「構文エラーが間隔値で発見されました式 " *原因:間隔値の解析中に構文エラーが見つかりました

+0

非常に有益なメッセージ – Jens

答えて

1

なぜこの仕事をしてあなたの質問は、にビットを単純化することができます。

select (sysdate - date '2002-12-25') year to month from dual; 

(SYSDA 
------ 
+14-03 

が、同じ呼び出しにsysdate - date '2002-12-25'によって生成同じ番号を差し込むことでまたは括弧なしで、ありません

select (5217.4197) year to month from dual; 

ORA-30083: syntax error was found in interval value expression 

問題は2つの数値が実際には異なることです。iネイティブに。 @hinoffが示唆したように、あなたはそれらを検討するdump()機能を使用することができます。

select dump(sysdate - date '2002-12-25') 
from dual; 

DUMP(SYSDATE-DATE'2002-12-25') 
----------------------------------- 
Typ=14 Len=8: 97,20,0,0,195,143,0,0 

select dump(5217.4197) from dual; 

DUMP(5217.4197)    
---------------------------- 
Typ=2 Len=5: 194,53,18,42,98 

タイプ2はnumberとしてdocumentedです。さらにMoS文書ID 1031902.6で説明されています。

明示的に2型数に計算を変換する場合は、同じエラーを取得します:タイプ14は、文書化されていない内部表現のようだ、とOracleができている

select (cast(sysdate - date '2002-12-25' as number)) year to month from dual; 

ORA-30083: syntax error was found in interval value expression 

- 内部 - それを変換します通常のタイプ2番号では不可能なやり方で、ある区間との間を行き来する。

numtodsinterval(5217.4197, 'DAY')で数字をインターバルに変換することはできますが、1日間隔と1年間隔は互換性がないため、その年数を抽出することはできません。 、1年の日数が変わるため)。 year-

select (systimestamp - timestamp '2002-12-25 00:00:00') year to month from dual; 

(SYSTI 
------ 
+14-03 

select dump(systimestamp - timestamp '2002-12-25 00:00:00') from dual; 

DUMP(SYSTIMESTAMP-TIMESTAMP'2002-12-2500:00:00') 
------------------------------------------------------------------------ 
Typ=190 Len=24: 97,20,0,0,9,0,0,0,38,0,0,0,44,0,0,0,24,177,20,9,10,0,0,0 

も文書化区間のいずれかのタイプではなく、内部のいずれかに変換することができます。

あなたが代わりに日付のタイムスタンプでそれを避けるためにしようとした場合にも、同様の問題を参照してくださいね月または日から秒まで。あなたのCTEでそれを使用しようとしても失敗します。 extract(year from age.d)を使用すると、この時点でDS間隔とみなされ、extract(year from (age.d) year to month)がORA-30083に戻っているため、「ORA-30076:抽出元の抽出フィールドが無効です」というメッセージが表示されます。

あなたは、月のように他のユニットへの間隔から切り替えたほうが良いかもしれません:

with age(m) as 
(
    select months_between(sysdate, date '2002-12-25') from dual 
) 
select 
    trunc(age.m/12) Y 
from age; 

     Y 
---------- 
     14 

あなたにも月数をしたい場合は、trunc(remainder(age.m, 12))を使用することができます。

それとも、本当に間隔をしたい場合は、CTEでそれを変換:

with age(ym) as 
(
    select numtoyminterval(
    months_between(sysdate, date '2002-12-25'), 'MONTH') from dual 
) 
select 
    extract(year from age.ym) Y 
from age; 

またはあなたの元に近い:

興味深いことに
with age(ym) as 
(
    select (sysdate - date '2002-12-25') year to month from dual 
) 
select 
    extract(year from age.ym) Y 
from age; 

the documentationが示唆これは本当に許可されていません - 」間隔値を生成する6つの組み合わせは、区間式 "で有効で、date-dateはone of those sixではありません。それは、タイプ14が数字タイプよりも間隔に近いことを示唆しているかもしれません。

+0

をお知らせください。さまざまな関連するビットを説明する時間をとっていただきありがとうございます。 – Slkrasnodar

1

2番目の問合せでは、 NUMBERの値はsysdate - to_date('2002-12-25')です。番号EXTRACT年からはできません。

最初のクエリでは、数値を日付間隔のデータ型の1つに変換し直します。

-- datatype: internal NUMBER of a DATE subtraction 
SELECT dump(sysdate - to_date('2002-12-25', 'YYYY-MM-DD')) 
    FROM dual; 

-- datatype: INTERVAL YEAR TO MONTH 
SELECT dump((sysdate - to_date('2002-12-25', 'YYYY-MM-DD')) year to month) 
    FROM dual; 

-- datatype: NUMBER 
SELECT dump(extract(year from (sysdate - to_date('2002-12-25', 'YYYY-MM-DD')) year to month)) 
    FROM dual; 

DUMP returns a VARCHAR2 value containing the data type code, length in bytes, and internal representation of expr.