非暙準のSQL構文機胜のいく぀かの䟋。 パヌト2日付圢匏

はじめに



この蚘事では、Oracleの日付圢匏ずその凊理のいく぀かの機胜に぀いお説明したす。 この蚘事では、いく぀かの暙準的な日付曞匏マスク、文字列から日付ぞの明瀺的および暗黙的な倉換、およびこのプロセスに圱響する远加のパラメヌタヌの抂芁を説明したす。 蚘事の最初の郚分ず同様に、この資料の説明は、非暙準のフォヌマット機胜を瀺す䟋に基づいおいたす。 暗黙的な倉換プロセスに関係するOracleメカニズムに぀いお詳しく調べたす。 ほずんどの機胜は、ドキュメントの関連セクションぞのリンクで説明されおいたす。



最初は、日付に関する蚘事を曞く぀もりはありたせんでしたが、このトピックに関する1぀の問題だけを怜蚎するこずに専念する぀もりでした。 ただし、䜜業䞭にOracleのさたざたな远加機胜をカバヌする必芁があり、新しい䟋が登堎し始めたした。 そのため、1぀の問題の怜蚎が小さな蚘事になりたした。 最も興味深いトピックではないにもかかわらず、退屈なものになったこずを願っおいたす。



挔算子による順序の機胜、not inの操䜜、および暗黙的な型倉換の䟋に関する蚘事の最初の郚分はこちらです。





To_date関数ず日付圢匏



トピックの曞匏蚭定が奜きなプログラマヌはほずんどいたせん。 たずえば、䞀郚のコヌスでは、日付の曞匏蚭定ず地域暙準のトピックは、特にトレヌニングの最終日の最埌の時間に配眮されたす。 リスナヌは退屈です。 その理由は、暙準タスクで比范的たれに䜿甚される倚数の既存のフォヌマットです。 ほずんどの堎合、マスクはto_number 、 to_char 、およびto_dateの 3぀の関数で䜿甚されたす。 3぀の堎合すべおで、マスクは2番目のオプションのパラメヌタヌです。 そしお、 数倀をフォヌマットするための正気のマスクが倚かれ少なかれある堎合 、 日付をわいせ぀にフォヌマットするためのマスクに加えお、 サフィックスず修食子がありたす。



もちろん、倚数のマスクを䜿甚できるこずは肯定的なこずです。たずえば、プログラマヌの日が2011幎9月13日であるかどうかを確認するために、幎の日数を返すマスク「DDD」を䜿甚できたす。

-- №1 select to_char(to_date('13.09.2011'),'DDD') "Programmers day" from dual;
      
      





曞匏蚭定の明らかな利点にもかかわらず、この蚘事の2番目のパヌトでは、日付曞匏の抂芁ず゚キゟチックなマスクの䜿甚䟋を含める぀もりはありたせんでした。 第䞀に、誰もが興味を持぀こずはたずありたせん。第二に、著者は耇雑なフォヌマットの倧ファンではありたせん。 このセクションが衚瀺される唯䞀の理由は、RR圢匏の䜿甚に関する読者からの質問です。



セクションのメむントピックに盎接移動する前に、日付の操䜜の非暙準的な䟋をいく぀か芋おみたしょう。



䟋1 切り捚おられたパタヌンを䜿甚する

暙準のフォヌマットから始めたしょう。 今日の日付は2011幎9月16日ですが、次のリク゚ストは満たされたすか

 -- №2 select to_char(sysdate, 'YYYY') from dual; -- №3 select to_date('03', 'DD') from dual;
      
      





リク゚スト番号2は、日付を文字列に倉換し、垌望する圢匏に倉換する兞型的な䟋です。 唯䞀の違いは、「DD.MM.YY」たたは「DD-MON-YYYY」タむプのより䞀般的なマスクの代わりに、幎のみを蚭定するマスクを䜿甚したこずです。 リク゚スト番号2は正垞に実行され、珟圚の幎が4桁の圢匏で返されたす。 「2011」。



ク゚リ3はもう少しおもしろいです。これは、文字列を切り捚おられた曞匏マスクを䜿甚した日付ぞの明瀺的な倉換の兞型的な䟋です。したがっお、構文の芳点から、ク゚リは正しく、正垞に実行されたす。 より重芁な問題は、その実装の結果です。 1日しか䞎えられない堎合、圌は䜕日目を返したすか この質問に答える前に、明瀺的に蚭定されおいない堎合にOracleがどのように時間を蚭定するか思い出しおみたしょう。

 -- №4 select to_char(to_date('03.02.2011','DD.MM.YYYY'),'DD.MM.YYYY HH24:MI:SS') from dual; -- №5 select to_char(to_date('03.02.2011 30', 'DD.MM.YYYY MI'),'DD.MM.YYYY HH24:MI:SS') from dual;
      
      





リク゚ストNo. 4では時間は瀺されず、リク゚ストNo. 5では分数のみが瀺され、時間ず秒は省略されたす。 Oracleにはルヌルがあり、日付に時間コンポヌネントがない堎合、時間芁玠の䞀郚のみが指定されおいる堎合ク゚リNo.5のように、時間は自動的に00:00:00぀たり真倜䞭に蚭定され、芁玠は00に蚭定されたす。したがっお、リク゚スト番号4は文字列「03 .02.2011 00:00:00」を返し、リク゚スト番号5は「03.03.02.2011 00:30:00」を返したす。



ク゚リ3に戻りたしょう。このルヌルは日付に圓おはたりたすか。 倉換䞭に欠萜した日付芁玠は00たたは01に眮き換えられたすか はい、それらは眮き換えられたすが、sysdate珟圚の幎の珟圚の月の最初の日からの倀がすべお欠萜しおいる日付芁玠に䜿甚されるわけではありたせん。 したがっお、リク゚ストNo. 3は月を09、2011を幎ずしお䜿甚するため、リク゚ストの結果は2011幎3月9日ずなりたす。



䟋2 フォヌマット順

次のク゚リが実行されたすか実行された堎合、䜕日目が返されたすか

 -- №6 select to_date('20092011', 'YYYYDDMM') from dual;
      
      





䞀芋、日付文字列に区切り文字がないこずは、ク゚リの実行ず互換性のない重芁な芁玠のように芋えたすが、日付マスクも区切り文字なしで指定され、倉換する文字列は指定されたパタヌンに察応したす。 したがっお、リク゚ストNo. 6は正垞に実行され、2009幎11月20日に返送されたす結果の圢匏は、セッション蚭定によっおわずかに異なる堎合がありたす。 次の䟋で、セパレヌタに関連する問題をより詳现に怜蚎したす。



䟋3 暗黙的な倉換

デフォルトの日付圢匏をDD.MON.RR、日付蚀語をロシア語ずするず、次のク゚リが機胜したす。

 -- №7 select months_between('1\-9','01$/08') from dual;
      
      





このク゚リは、暗黙的な倉換を䜿甚しお日付に倉換する必芁がある2぀の文字列パラメヌタヌを指定したす。 ドキュメントによるず、既定の圢匏を䜿甚する堎合、日付ぞの暗黙的な倉換の文字列は、パタヌン[D | DD] separator1 [MM | MON | MONTH] separator2 [R | RR | YY | YYYY]を満たす必芁がありたす。 separator1およびseparator2ずしお、スペヌス、タブ、および「二重匕甚笊」を含むほずんどの区切り文字ず特殊文字を䜿甚できたす。さらに、行に少なくずも2桁の日、月、幎を指定する堎合、次に、セパレヌタを完党に省略するこずができたす。䟋

 -- №8 select to_date('0109') from dual; -- №9 select to_date('0109') from dual; -- №10          DD.MM.RR select to_date('010909') from dual;
      
      





ク゚リNo. 7で指定された䞡方の行が指定されたパタヌンに察応するため、ク゚リは正垞に実行され、番号11が返されたす。



䟋番号4。 To_date関数のパラメヌタヌ

デフォルトの日付圢匏をDD.MON.RR、日付蚀語をロシア語ずするず、次のク゚リが機胜したす。

 -- №11 select to_date(sysdate,'mm/dd/yyyy hh24:mi:ss') from dual;
      
      





同様のク゚リが、Ask Tomペヌゞの議論の1぀に登堎したした。 芁求トラップは、日付sysdateを日付に倉換しようずしおいるこずです。 リク゚ストが次のようになる堎合

 -- №12 select to_char(sysdate,'mm/dd/yyyy hh24:mi:ss') from dual;
      
      





その実行は成功し、文字列'09 / 15/2011 23:00:11 'を返したした。 ただし、to_date関数は最初のパラメヌタヌずしお文字列を想定しおいるため、最初は日付が文字列に暗黙的に倉換されたすデフォルトのマスクでto_charsysdateを呌び出すのず同じです。 この倉換の結果はストリング'15 .09.11 'であり、to_date呌び出しが行われたす。 したがっお、ク゚リ11は次のク゚リず同等です。

 -- №13 select to_date('15.09.11','mm/dd/yyyy hh24:mi:ss') from dual;
      
      





行'15 .09.11 'はむンストヌルされおいるマスクに察応しおいないため、リク゚ストNo. 13を実行できないこずを確認するこずは難しくありたせん。したがっお、リク゚ストNo. 11も実行できたせん。



デフォルトの日付圢匏を蚭定する

デフォルトの日付圢匏は、NLS_DATE_FORMAT圢匏自䜓に責任ずNLS_DATE_LANGUAGE日、月などの名前を蚘述するずきに䜿甚される蚀語に責任の2぀のパラメヌタヌによっお蚭定されたす。 これらのパラメヌタヌが明瀺的に指定されおいない堎合、それらの倀はNLS_LANGパラメヌタヌに基づいお蚭定されたす 。



日付圢匏を蚭定できるレベルは3぀ありたす。
  1. DBレベル
     select * from nls_database_parameters where parameter in ('NLS_DATE_FORMAT','NLS_DATE_LANGUAGE');
          
          



    このレベルのパラメヌタヌは、デヌタベヌスの䜜成時に蚭定され、init.oraファむルに曞き蟌たれたす。
  2. むンスタンスレベル
     select * from nls_instance_parameters where parameter in ('NLS_DATE_FORMAT','NLS_DATE_LANGUAGE');
          
          



    このレベルのパラメヌタヌは、むンスタンスの開始時に蚭定され 、ALTER SYSTEMコマンドを䜿甚しお倉曎できたす。
  3. セッションレベル
     select * from nls_session_parameters where parameter in ('NLS_DATE_FORMAT','NLS_DATE_LANGUAGE');
          
          



    このレベルのパラメヌタヌは、ALTER SESSIONコマンドで倉曎できたす 。 たた、これらのパラメヌタヌの倀は、ク゚リを䜿甚しお確認できたす。
      select SYS_CONTEXT ('USERENV', 'NLS_DATE_FORMAT'), SYS_CONTEXT ('USERENV', 'NLS_DATE_LANGUAGE') from dual;
          
          



次の各レベルのパラメヌタヌは、前のレベルのパラメヌタヌを「䞊曞き」したす。 セッションレベルのパラメヌタヌを蚭定しおいる堎合、他のレベルのパラメヌタヌはセッションに圱響したせん。 すべおのセッションに単䞀の日付圢匏を蚭定するには、Tomは自分の列で ON-LOGONトリガヌを䜿甚するこずをお勧めしたす 。
 create or replace trigger data_logon_trigger after logon ON DATABASE begin execute immediate 'alter session set nls_date_format = ''dd/mm/yyyy'''; end;
      
      





䟋5 DD.MM.RRずDD-MON-RRの圢匏

デフォルトで日付のフォヌマットに泚意を払うために、文字列を日付に暗黙的に倉換する際のある奇劙なこずに觊発されたした。 次の䟋を芋おみたしょう。

 -- №14 --     alter session set NLS_DATE_FORMAT='DD.MM.RR'; --     alter session set NLS_DATE_LANGUAGE='AMERICAN'; --    select * from nls_session_parameters where parameter in ('NLS_DATE_FORMAT','NLS_DATE_LANGUAGE'); --    select to_date('11.09.11') from dual; select to_date('11.SEP.11') from dual;
      
      





文字列'11 .09.11 'の日付ぞの倉換は成功するが、文字列'11 .SEP.11'は成功しないず仮定するのは論理的です。 ただし、そうではないため、䞡方の倉換が正垞に完了したす。 最初に、文字列をセッションマスクに倉換できない堎合、Oracleは他のレベルのマスクを䜿甚しようずするず仮定したしたDBレベルマスクは「DD-MON-RR」に蚭定されたす。 ドキュメントを読むず、そうではないこずがわかりたした。Oracleは、前の段萜で説明した原則に埓っおいたす。



別の䟋を詊しおみたしょう。

 -- №15 --     alter session set NLS_DATE_FORMAT='DD.MON.RR'; --     alter session set NLS_DATE_LANGUAGE='AMERICAN'; --    select * from nls_session_parameters where parameter in ('NLS_DATE_FORMAT','NLS_DATE_LANGUAGE'); --    select to_date('11.09.11') from dual; select to_date('11.SEP.11') from dual;
      
      





結果が前のク゚リず同じだず思う堎合、あなたは間違っおいたす。 倉換の1぀が倱敗したす。 この堎合、文字列'11 .09.11 'はパタヌンず䞀臎したせん。 おそらくこれは神秘䞻矩でしょうか



ああ、いや。 ドキュメントを読むず、日付曞匏芁玠の自動眮換のルヌルがあるこずがわかりたした 。 以䞋は亀換衚です。

元のフォヌマット芁玠 オリゞナルの代わりに詊す远加のフォヌマット芁玠
「MM」 「月」ず「月」
「月 「月」
「月」 「月」
「Yy」 「YYYY」
「RR」 「RRRR」
この衚の内容を芋るず、圢匏「DD.MM.RR」には圢匏「DD.MON.RR」および「DD.MONTH.RR」などが暗黙的に含たれおいるが、圢匏は「DD」であるこずが明らかになりたす。 .MON.RR 'format' DD.MM.RR 'は存圚せず、リク゚ストNo. 14およびNo. 15の動䜜を説明しおいたす。



䟋6 フォヌマットRR vs YY

ほずんどのナヌザヌにずっお、RRマスクずYYマスクの違いはよく知られおいたすが、この情報が圹立぀ず感じる人もいたす。 䟋の怜蚎にすぐに進みたす。 次のク゚リを返すデヌタ

 -- №16 select to_date('11','RR') "RR", to_date('11','YY') "YY" from dual; -- №17 select to_date('99','RR') "RR", to_date('99','YY') "YY" from dual;
      
      





䞊蚘の䞡方のリク゚ストは成功し、リク゚ストNo. 3の䟋No. 1に蚘茉されおいるルヌルに埓っお日付を返したす。 したがっお、受信したすべおの日付の日の倀は01になり、月の倀は09になりたす9月にリク゚ストを実行する堎合。 䞻な質問は、今幎の重芁性は䜕ですか



ク゚リNo. 16 by '11'では2011幎を意味し、䞡方のマスクがそれを私に返したず掚枬するのは簡単です。 ク゚リ16の結果は、2011幎9月1日ず2011幎9月1日です。



リク゚ストNo. 17では、'99 'で1999を意味したしたが、ここではマスクの意芋が分かれおいたした。RRマスクは予想される1999を返し、YYマスクは2099を返したした。 ク゚リ17の結果は1999幎9月1日ず2099幎9月1日です。



これらのフォヌマット芁玠がどのように機胜するかを詳しく芋おみたしょう。

 -- №18 select to_date('00','RR') "00", to_date('49','RR') "49", to_date('50','RR') "50", to_date('99','RR') "99" from dual union all select to_date('00','YY') "00", to_date('49','YY') "49", to_date('50','YY') "50", to_date('99','YY') "99" from dual;
      
      





ク゚リ番号18からわかるように、マスクの動䜜の違いは50幎代から始たりたす。 YY圢匏は垞に珟圚の䞖玀の幎を返し、RRは、珟圚の䞖玀の幎ずしお50幎未満、および前䞖玀の幎ずしお50幎以䞊の幎を認識したす。 実際、倀to_date'99 '、' RR '= 1999およびto_date' 00 '、' RR '= 2000は、珟圚の日付が2051未満で、その埌にto_date'99'、 'RR' = 2099およびto_date'00 '、' RR '=2100。実隓する堎合、サヌバヌ時間を2051に倉曎し、ク゚リ18の結果がどのように倉化するかを確認できたす。実行䞭のシステムでは実行しないでください。 サヌバヌ時間が倉曎されるず、sysdateが倉曎されるため、すべおのレポヌト、ログテヌブルなどで発生する頭痛の皮に぀いおも考えない方がよいでしょう。 RR圢匏を䜿甚しお2桁の幎を4桁の幎に倉換するための䞀般的な芏則は次のようになりたす 。

指定された2桁の幎が00〜49の堎合、 指定された2桁の幎が50〜99の堎合、

幎を2桁で蚭定する堎合に぀いおのみ説明しおいるこずに泚意しおください。幎を4桁で蚭定するず、YYマスクは自動的にYYYYマスクに眮き換えられ、RRマスクはRRRRになりたす。

 -- №19 select to_date('1950','RR') "50RR", to_date('1950','YY') "50YY" from dual;
      
      





したがっお、リク゚スト19は、どちらの堎合も1950を返したす。



䟋7 他のいく぀かの䟋

レビュヌを終了するには、少し異囜情緒を考慮しおください。 次のク゚リの結果ずしお゚ラヌが発生したすか

 -- №20 select DATE '1928-12-25' from dual;
      
      





これが無意味なレコヌドであるず刀断した堎合は、間違えられたす。これはANSI暙準に準拠した完党に正しい日付蚭定であり、ク゚リNo. 20は成功し、1928幎12月25日に返されたす。



どのリク゚ストが倱敗したすか

 -- №21 select to_date('1998--25 17:30','YYYY-MON-DD HH24:MI','NLS_DATE_LANGUAGE=AMERICAN') from dual; -- №21 select to_date('1998--25 17:30','YYYY-MON-DD HH24:MI','NLS_DATE_LANGUAGE=RUSSIAN') from dual;
      
      





この䟋は、to_date関数の3番目のパラメヌタヌの存圚を瀺すこずを目的ずしおいたす。 このパラメヌタヌを䜿甚するず、このto_date関数呌び出しに察しおのみ、NLSNational Language Supportパラメヌタヌのいずれかの倀を蚭定できたす。 䟋5で怜蚎したセッションのNLSパラメヌタヌを蚭定したす。 リク゚ストNo. 20ずNo. 21の䞻な違いは、月の名前ではなく䟋5で説明されおいるように、MONマスクは自動的にMONTHマスクに眮き換えられたす、異なる日付蚀語を瀺しおいたす。 リク゚スト番号21は月の名前を英語で期埅しおいるため、実行されたせん;リク゚スト番号22は月の名前をロシア語で期埅し、正垞に実行されたす。



次のテヌブル宣蚀は、どのような堎合にデヌタを挿入するずきに゚ラヌに぀ながる可胜性がありたすか

 -- №23 create table for_test (a number, b date default to_date('11.09.2011'));
      
      





デフォルトの日付圢匏「DD.MON.RR」のセッションでは、最初の列の倀のみが挿入されるたびに
 insert into for_test(a) values(1);
      
      



゚ラヌが発生したす。





さたざたなアプリケヌションで日付を衚瀺する機胜



日付衚瀺に圱響するもの

このセクションは、コメントに瀺された掚奚事項により、蚘事の発行埌に远加されたした。 以䞋は、日付の衚瀺ず数倀の衚瀺の䞡方に圓おはたりたす。 おそらく、䞊蚘の蚘事に蚘茉されおいるいく぀かの䟋を実行するず、結果に瀺されおいる圢匏以倖の圢匏で日付を受け取りたした。 セッションの蚭定が䟋に瀺されおいるずおりであれば、これは少なくずも奇劙に思えたす。



真実は、リク゚ストを実行するずき

 -- №24 select sysdate from dual;
      
      



日付を取埗したすが、画面に結果を衚瀺するには、デヌタベヌスにアクセスする特定のナヌティリティが日付を文字列に倉換する必芁がありたす。 したがっお、日付および数倀を衚瀺するには、to_charが暗黙的に呌び出されたす。 暗黙的な倉換の叀兞的なケヌスがありたすこの倉換は画面に衚瀺するためだけであり、その結果は蚈算に関䞎せず、デヌタの衚瀺以倖には圱響したせん。 暗黙的な倉換がある堎合、それを実行するマスクもありたす。 叀兞的なケヌスでは、セッションに蚭定されたマスク、぀たり nls_session_parametersテヌブルのNLS_DATE_FORMATパラメヌタヌで指定されたマスク。これは蚘事党䜓で積極的に䜜業したした。



いく぀かのアプリケヌションの動䜜を確認したしょう。 次のスクリプトを䜿甚しお確認したす。

 -- №25 --     select * from nls_session_parameters where parameter in ('NLS_DATE_FORMAT','NLS_DATE_LANGUAGE'); --  select sysdate from dual; --     alter session set NLS_DATE_FORMAT='DD.MON.RR hh24:mi:ss'; --  select sysdate from dual;
      
      





sqlplusが日付の衚瀺に䜿甚するパラメヌタヌを確認したしょう。

画像

図 1. sqlplusのク゚リ25の結果。



図1からわかるように、日付衚瀺圢匏はセッション蚭定、぀たり sqlplusはセッション蚭定を䜿甚したす。 これにより、倉換ず衚瀺の䞡方に同じマスクが䜿甚されるため、日付を文字列に、たたはその逆に倉換するプロセスを理解しやすくなりたす。



䞀郚の高床な開発ツヌルは、Oracle蚭定に関連しない独自のNLS蚭定を䜿甚したす。 䟋ずしお、日付を衚瀺するためにPL / SQL Developerが䜿甚するオプションを確認したしょう。 これを行うには、リク゚スト番号25を実行したす。

画像

図 2. PL / SQL Developerのク゚リ25の結果。



図2からわかるように、セッション蚭定を倉曎しおも日付衚瀺圢匏は倉わりたせん。 さらに、泚意深く芋るず、画面に日付を衚​​瀺した最初ず2番目の結果がセッションパラメヌタヌず䞀臎しなかったこずがわかりたす最初の堎合、衚瀺された日付は4桁圢匏の幎で、マスクは2桁圢匏の幎を瀺しおいたした。 これは、ナヌティリティが独自のNLS蚭定を䜿甚するこずを意味したす。PL/ SQL Developerの堎合、その堎所は図に瀺されおいたす。 3。

画像

図 3. PL / SQL DeveloperでNLS日付衚瀺オプションを蚭定したす。



NLSナヌティリティの蚭定が悪いこずがある方法

セッション圢匏ずは異なる圢匏で日付を衚瀺するず、1぀の理由で有害です-ナヌザヌを誀解させ、゚ラヌを匕き起こす可胜性がありたす。 sqlplusおよびPL / SQL Developerで次のク゚リを実行したす。

 -- №26 --     alter session set NLS_DATE_FORMAT='DD.MON.RR hh24:mi:ss'; --  select sysdate from dual; --         select to_date() from dual;
      
      



の代わりに、前の行から受信したデヌタをク゚リの最埌の行に挿入したす。



ク゚リの結果は、以䞋の図に瀺されおいたす。

画像

図 4. sqlplusのク゚リ26の結果。





図 5. PL / SQL Developerのク゚リ26の結果。



sqlplusで衚瀺されたデヌタが正垞に日付に倉換され、PL / SQL Developerによっお衚瀺されたデヌタを倉換できなかったのはなぜですか Oracleはセッションで指定されたデヌタ圢匏を倉換に䜿甚し、PL / SQL Developerによるデヌタ出力はセッション圢匏ずは異なる独自の圢匏で衚瀺されるためです。





おわりに



結論ずしお、日付の操䜜に専念するほがすべおの投皿で、Tom Kiteは明瀺的な倉換を䜿甚する必芁性ずマスクの必須䜿甚に぀いお話しおいるこずを思い出しおください。 「文字列を日付に倉換するずきは、デフォルトの日付圢匏に䟝存せず、垞に明瀺的にマスクを蚭定しおください」-これが圌の蚀葉の発音です。 ask Tomペヌゞを䜿甚しお、日付倉換を操䜜するずきに、远加の䟋ず考えられる゚ラヌを芋぀けるこずができたす。



日付を扱うこずは蚘事党䜓を取り䞊げたので、倚くの興味深い質問が「オヌバヌボヌド」のたたであり、それを怜蚎したいず思いたす。 ほずんどの堎合、蚘事の3番目の郚分は、空き時間があるずすぐに衚瀺されたす。



All Articles