lazyなOracleユーザーのためのヒント – タイプ数を削減するANSI DATEおよびTIMESTAMP SQL構文


http://blog.tanelpoder.com/2012/12/29/a-tip-for-lazy-oracle-users-type-less-with-ansi-date-and-timestamp-sql-syntax/
の翻訳です。基本的に意訳です。意味をとりやすくするために追加した箇所については、《…》で囲っています。

本文書に関する指摘については、原文著者のTanel Poderさんではなく、渡部まで御連絡お願いいたします。


日本語訳:渡部 亮太 (WR at Csus4 dot net)

履歴


  • 2013-01-26: 初稿up


私はlazyです。従って私はタイプ数を減らすことができるなら、タイプ数を減らそうとします。

しばしば、OracleがSQLコードでANSI DATEおよびTIMESTAMP構文をサポートしていることを知って驚いている人がいます。これは、長ったらしいTO_DATE(…、 ‘YYYY-MM-DD HH24:MI:SS’)を短く《タイプ》できるちょっとした構文《的な工夫》です。もし、あるフィールドとある(日精度の)日付を比較したい場合、このようにタイプできます。

SQL> SELECT COUNT(*) FROM dba_objects WHERE created > DATE’2012-12-01′;

COUNT(*)
———-
0

SQL> SELECT COUNT(*) FROM dba_objects WHERE created > DATE’2012-01-01′;

COUNT(*)
———-
804

このように、どんなNLS設定であるかに関係なく、常に標準の日付フォーマットを使用できます。

上記の例では、date 2012-01-01は、本当に 2012-01-01 00:00:00を意味しており、その日の00:00:01以降に作成されたすべてのオブジェクトが結果に含まれることになることことに注意してください。あなたがTIMESTAMPの精度を希望する場合は、TIMESTAMPのキーワードを使用できます。

SQL> SELECT COUNT(*) FROM dba_objects WHERE created > TIMESTAMP’2012-01-01 08:12:34′;

COUNT(*)
———-
805

SQL> SELECT COUNT(*) FROM dba_objects WHERE created > TIMESTAMP’2012-01-01 08:12:34.000000000′;

COUNT(*)
———-
805

SQL> SELECT COUNT(*) FROM dba_objects WHERE created > TIMESTAMP’2012-01-01 08:12:34.000000000 -08:00′;

COUNT(*)
———-
805

ANSI SQL構文がOracle 9iで導入されたということから、この構文はOracle 9i以降で動作すると思う。

いくつかの他の状況でも、この構文を使用できます。FLASHBACK TO TIMESTAMP and SELECT … AS OF TIMESTAMP句のような:

SQL> SELECT COUNT(*) FROM t AS OF TIMESTAMP TIMESTAMP’2012-12-29 20:00:10 +03:00′;

COUNT(*)
———-
25237

SQL> SELECT COUNT(*) FROM t AS OF TIMESTAMP TIMESTAMP’2012-12-29 20:01:00 +03:00′;

COUNT(*)
———-
1

SQL> ALTER TABLE t ENABLE ROW MOVEMENT;

Table altered.

SQL> FLASHBACK TABLE t TO TIMESTAMP TIMESTAMP’2012-12-29 20:00:00 +03:00′;

Flashback complete.

SQL> SELECT COUNT(*) FROM t;

COUNT(*)
———-
25237

上記の"TIMESTAMP TIMESTAMP …"という2つ連続している箇所に注意してください。これはタイプミスではありません、最初のTIMESTAMPは、("SCN"キーワードを使用するような状況である)Oracleのトランザクション管理用のタイムスタンプではなくて、実時間のタイムスタンプで、フラッシュバックすることを指示するものです。そして2つ目のタイムスタンプは、ANSIタイムスタンプ指定子です。(古き良きTO_DATE()構文もここでは使用することができるのですが)

日付と時刻のロジックをつかうSQLコマンドを入力するときはいつでも、この時間の節約をお楽しみください。
(この機能を知らなかった君は、私《=Tanel》に会ったとき、私《=Tanel》にビールを奢ることができるよ)

新年あけましておめでとうございます! :)

update: : Sayan Malakshinovは、コメント欄に面白い情報を追加してくれました- undocumentedなTIMEキーワードも使用可能であること。簡単なテストを行いましょう:

SQL> SELECT TIME’12:34:56.000000′ a FROM dual;

A
—————————————————————————
12.34.56.000000000 PM

日、月、年の情報がない、時刻コンポーネントのみを明らかに返します。

結局どんなデータ型なのかを確認するため、テーブルを作成してみましょう:

SQL> CREATE TABLE t AS SELECT TIME’12:34:56.000000′ a FROM dual;
CREATE TABLE t AS SELECT TIME’12:34:56.000000′ a FROM dual
*
ERROR at line 1:
ORA-00902: invalid datatype

エラー
Sayanは、コメントで、テーブルの作成を許可するevent 10407について触れている。oraus.msgファイルを確認して、それが何なのか見てみましょう:

10407, 00000, "enable datetime TIME datatype creation"
// *Cause:
// *Action: set this event to enable datetime datatype creation
// *Comment: This event is set when the user wants to create
// a datetime datatype column. The compatible=8.1.0.0.0 parameter
// must also be set.

このイベントを使用してみましょう:

SQL> ALTER SESSION SET EVENTS ‘10407 trace name context forever, level 1′;

Session altered.

SQL> CREATE TABLE t AS SELECT TIME’12:34:56.000000’ a FROM dual;

Table created.

OK、できるようになりました。(文書化されていない+サポートされていないけれども)

それで、このeventを無効にしてテーブルを削除した後、TIMEデータ型を他のなにかにキャストするいくつかのバリエーションについて試してみました:

SQL> CREATE TABLE t AS SELECT CAST(TIME’12:34:56.000000′ AS DATE) a FROM dual;
CREATE TABLE t AS SELECT CAST(TIME’12:34:56.000000′ AS DATE) a FROM dual
*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected NUMBER got TIME

OK、DATE型に変換することはできません。 では、TIMESTAMP型を試してみましょう:

SQL> CREATE TABLE t AS SELECT CAST(TIME’12:34:56.000000′ AS TIMESTAMP) a FROM dual;

Table created.

SQL> @desc t
Name Null? Type
——————————- ——– —————————-
1 A TIMESTAMP(6)

SQL> SELECT * FROM t;

A
—————————————————————————
29-DEC-12 12.34.56.000000 PM

TIMESTAMPへの変換は動作しました- 結果から 現在の日付が日付コンポーネントとして選択されるようにみえます。

うーん、何らかの方法で日付コンポーネントと時刻コンポーネントを連結することができるのだろうか?

SQL> SELECT TRUNC(sysdate – 100) + TIME’15:00:00′ FROM dual;
SELECT TRUNC(sysdate – 100) + TIME’15:00:00′ FROM dual
*
ERROR at line 1:
ORA-30087: Adding two datetime values is not allowed

明らかにできないね。

とにかく、私のフライトは40分で出発するので、移動しないとね。Sayan、TIMEに関する補足ありがとう – 新しいものを学ぶっていうのは良いことだよね(毎日;-)

関連記事