web-dev-qa-db-ja.com

SQL日付変換の結果が「無効な数値形式モデルパラメータ」になります。

_Oracle 11g_データベースからいくつかのデータをselectする必要がありますが、次のselectクエリが失敗する理由を理解できないようです。

_SELECT
  INFO_ID,
  INFO_DETAIL, 
  IMPORTANT_FLG, 
  DELETE_FLG, 
  CREATE_TIME, 
  DISPLAY_ORDER
  FROM  TABLE_NAME
  WHERE TO_DATE(TO_CHAR(CREATE_TIME, 'YYYY/MM/DD'), 'YYYY/MM/DD')
  BETWEEN TO_DATE(TO_CHAR(:fromDate, 'YYYY/MM/DD'), 'YYYY/MM/DD') AND TO_DATE(TO_CHAR(:toDate, 'YYYY/MM/DD'), 'YYYY/MM/DD')
  ORDER BY IMPORTANT_FLG DESC NULLS LAST , DISPLAY_ORDER ASC NULLS LAST, CREATE_TIME DESC, INFO_ID ASC
_

クエリは次のエラーメッセージで失敗します:

_ORA-01481: invalid number format model
01481. 00000 -  "invalid number format model"
*Cause:    The user is attempting to either convert a number to a string
       via TO_CHAR or a string to a number via TO_NUMBER and has
       supplied an invalid number format model parameter.
_

変数fromDatetoDateの入力は、_20111010_などの日付文字列です。より具体的な時刻(表と同じ形式)も試しましたが、問題はないようです。

データベースでは、_CREATE_TIME_列はTIMESTAMP(6)タイプであり、たとえば、1つのサンプルは_2011/12/19 08:04:42_です。

これがエラーである理由は何か考えが浮かびますか?

4
julumme

根本原因:

[〜#〜] number [〜#〜][〜#〜] string [〜#〜]に変換していますが、[〜#〜]日付[〜#〜]。 _20111010_は日付ではなく、数値です。また、_'20111010'_は日付ではなく、文字列です。それらは完全に異なります。

  • _20111010_ --[〜#〜] number [〜#〜]
  • _'20111010'_ --[〜#〜] string [〜#〜]
  • TO_DATE('20111010','YYYYMMDD') --[〜#〜] date [〜#〜]

エラー:

_SQL> SELECT TO_CHAR(20111010, 'YYYY/MM/DD') FROM dual;
SELECT TO_CHAR(20111010, 'YYYY/MM/DD') FROM dual
                         *
ERROR at line 1:
ORA-01481: invalid number format model
_

あなたの質問に来る:

_WHERE TO_DATE(TO_CHAR(CREATE_TIME, 'YYYY/MM/DD'), 'YYYY/MM/DD')
  BETWEEN TO_DATE(TO_CHAR(:fromDate, 'YYYY/MM/DD'), 'YYYY/MM/DD') 
AND TO_DATE(TO_CHAR(:toDate, 'YYYY/MM/DD'), 'YYYY/MM/DD')
_

変換とフォーマットが不必要に複雑になっています。

[〜#〜] timestamp [〜#〜]データ型は、[〜#〜] date [〜#〜]データ型の拡張です。 DATEデータ型のdatetime要素に加えて、TIMESTAMPデータ型は、小数点以下0桁から9桁までの精度で秒の小数部を保持します。デフォルトは6です。

データベースでは、CREATE_TIME列はTIMESTAMP(6)タイプであり、たとえば1つのサンプルは2011/12/1908:04:42です。

[〜#〜] timestamp [〜#〜]を扱っているので、TO_TIMESTAMPを使用できます。

DATE/TIMESTAMP演算を実行している間は、データ型をそのままにして、stringに変換しないでください。 TO_CHARdisplayにのみ使用する必要があります。

フィルタ述語を次のように変更します。

_WHERE CREATE_TIME 
BETWEEN TO_TIMESTAMP(:fromDate, 'YYYY/MM/DD') 
AND TO_TIMESTAMP(:toDate, 'YYYY/MM/DD')
_

上記では、_:fromDate_および_:toDate_はstringであり、numberではありません。

例えば、

_SQL> SELECT to_timestamp('20111010', 'YYYYMMDD') FROM dual;

TO_TIMESTAMP('20111010','YYYYMMDD')
-----------------------------------------------------------
10-OCT-11 12.00.00.000000000 AM
_

または、TO_CHARを使用して最初にconvertnumber into string

_SQL> SELECT to_timestamp(TO_CHAR(20111010), 'YYYYMMDD') FROM dual;

TO_TIMESTAMP(TO_CHAR(20111010),'YYYYMMDD')
------------------------------------------------------------------
10-OCT-11 12.00.00.000000000 AM
_
8
Lalit Kumar B

このソリューションがお役に立てば幸いです。

不要な変換が多すぎます。

私は自分のシステムで同じシナリオをシミュレートしました enter image description here

ここで、_CREATED_TIME_はデータ型timestamp(6)の列です。

3
Jeethu