web-dev-qa-db-ja.com

PreparedStatementでsetDateを使用する

コードをより標準にするために、SQL変数をハードコーディングしたすべての場所を準備済みステートメントに変更し、代わりに変数をバインドするように求められました。

しかし、setDate()で問題に直面しています。

コードは次のとおりです。

        DateFormat dateFormatYMD = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        DateFormat dateFormatMDY = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
        Date now = new Date();
        String vDateYMD = dateFormatYMD.format(now);
        String vDateMDY = dateFormatMDY.format(now);
        String vDateMDYSQL =  vDateMDY ;
        Java.sql.Date date = new Java.sql.Date(0000-00-00);

   requestSQL = "INSERT INTO CREDIT_REQ_TITLE_ORDER (REQUEST_ID," + 
                " ORDER_DT, FOLLOWUP_DT) " +  "values(?,?,?,)";


                prs = conn.prepareStatement(requestSQL);

                prs.setInt(1,new Integer(requestID));

                prs.setDate(2,date.valueOf(vDateMDYSQL));
                prs.setDate(3,date.valueOf(sqlFollowupDT));

SQLが実行されると、次のエラーが表示されます。

    Java.lang.IllegalArgumentException
    at Java.sql.Date.valueOf(Date.Java:138)
    at com.cmsi.eValuate.TAF.TAFModuleMain.CallTAF(TAFModuleMain.Java:1211)

setString()の代わりにto_date()を使用する必要がありますか?

43
roymustang86

__ Java.sql.Dateの使用

テーブルにDATE型の列がある場合:

  • Java.lang.String

    メソッド Java.sql.Date.valueOf(Java.lang.String) は、yyyy-[m]m-[d]d形式の日付を表す文字列を受け取りました。例えば。:

    ps.setDate(2, Java.sql.Date.valueOf("2013-09-04"));
    
  • Java.util.Date

    タイプJava.util.Dateの変数endDateがあるとします。こうして変換を行います。

    ps.setDate(2, new Java.sql.Date(endDate.getTime());
    
  • 現在

    現在の日付を挿入する場合:

    ps.setDate(2, new Java.sql.Date(System.currentTimeMillis()));
    
    // Since Java 8
    ps.setDate(2, Java.sql.Date.valueOf(Java.time.LocalDate.now()));
    

__ Java.sql.Timestampの使用

テーブルにTIMESTAMPまたはDATETIMEタイプの列がある場合:

  • Java.lang.String

    メソッド Java.sql.Timestamp.valueOf(Java.lang.String) は、yyyy-[m]m-[d]d hh:mm:ss[.f...]形式の日付を表す文字列を受け取りました。例えば。:

    ps.setTimestamp(2, Java.sql.Timestamp.valueOf("2013-09-04 13:30:00");
    
  • Java.util.Date

    タイプJava.util.Dateの変数endDateがあるとします。こうして変換を行います。

    ps.setTimestamp(2, new Java.sql.Timestamp(endDate.getTime()));
    
  • 現在

    現在のタイムスタンプが必要な場合:

    ps.setTimestamp(2, new Java.sql.Timestamp(System.currentTimeMillis()));
    
    // Since Java 8
    ps.setTimestamp(2, Java.sql.Timestamp.from(Java.time.Instant.now()));
    ps.setTimestamp(2, Java.sql.Timestamp.valueOf(Java.time.LocalDateTime.now()));
    
130
Paul Vargas

tl; dr

JDBC 4.2以降およびJava 8以降の場合:

myPreparedStatement.setObject( … , myLocalDate  )

…そして…

myResultSet.getObject( … , LocalDate.class )

詳細

VargasのAnswerは、Java.time型について言及するのに適していますが、Java.sql.Dateへの変換のみを参照しています。ドライバーが更新された場合、変換する必要はありません。

Java.time

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、Java.util.Date.CalendarJava.text.SimpleDateFormatなどの古い面倒な日時クラスに取って代わります。 Joda-Time チームは、Java.timeへの移行も推奨しています。

詳細については、 Oracleチュートリアル を参照してください。また、多くの例と説明についてはStack Overflowを検索してください。

Java.time機能の多くは、 ThreeTen-Backport でJava 6および7にバックポートされ、さらに ThreeTenABP でAndroidに適合します。

LocalDate

Java.timeでは、 Java.time.LocalDate クラスは、時刻およびタイムゾーンのない日付のみの値を表します。

JDBC 4.2 以降の仕様に準拠する JDBCドライバー を使用する場合、古い Java.sql.Date クラスを使用する必要はありません。 PreparedStatement::setObject および ResultSet::getObject を使用して、LocalDateオブジェクトをデータベースと直接やり取りできます。

LocalDate localDate = LocalDate.now( ZoneId.of( "America/Montreal" ) );
myPreparedStatement.setObject( 1 , localDate  );

…そして…

LocalDate localDate = myResultSet.getObject( 1 , LocalDate.class );

JDBC 4.2より前の変換

ドライバーがJava.time型を直接処理できない場合は、Java.sql型への変換にフォールバックします。ただし、Java.time型のみを使用するビジネスロジックで、それらの使用を最小限に抑えてください。

Java.time型との間の変換のために、新しいメソッドが古いクラスに追加されました。 Java.sql.Date については、 valueOf および toLocalDate メソッドを参照してください。

Java.sql.Date sqlDate = Java.sql.Date.valueOf( localDate );

…そして…

LocalDate localDate = sqlDate.toLocalDate();

プレースホルダー値

質問のコードに示されているように、0000-00-00をプレースホルダー値として使用する場合は注意してください。すべてのデータベースや他のソフトウェアが、その時点までさかのぼることができるわけではありません。よく使用される nix/Posix Epochの基準日 1970年の1970-01-01のようなものを使用することをお勧めします。

LocalDate Epoch_DATE = LocalDate.ofEpochDay( 0 ); // 1970-01-01 is day 0 in Epoch counting.

Java.timeについて

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、 Java.util.DateCalendar 、および SimpleDateFormat などの厄介な古い レガシー 日時クラスに取って代わります。

メンテナンスモード になった Joda-Time プロジェクトは、 Java.time クラスへの移行を推奨しています。

詳細については、 Oracle Tutorial を参照してください。また、多くの例と説明についてはStack Overflowを検索してください。仕様は JSR 31 です。

Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠する JDBCドライバー を使用します。文字列やJava.sql.*クラスは必要ありません。

Java.timeクラスはどこで入手できますか?

ThreeTen-Extra プロジェクトは、クラスを追加してJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。ここでは、 IntervalYearWeekYearQuarter 、および more

15
Basil Bourque

あなたが持っている問題は、フォーマットされたJava.util.Dateから互換性のないフォーマットを渡してJava.sql.Dateのインスタンスを構築していることです。これはvalueOf()を使用するときと同じようには動作しません異なる形式を使用します。

また、時間と分を維持することを目指していることもわかります。データ型をJava.sql.Timestampに変更することをお勧めします。これは、データベースフィールドをDATETIMEなどに変更するとともに、時間と分をサポートします。 (データベースベンダーによって異なります)。

とにかく、Java.util.Date to Java.sql.Dateから変更する場合は、使用することをお勧めします

Java.util.Date date = Calendar.getInstance().getTime();
Java.sql.Date sqlDate = new Java.sql.Date(date.getTime()); 
// ... more code here
prs.setDate(sqlDate);
3

docs は、Java.sql.Dateがスローすることを明示的に示しています。

  • IllegalArgumentException-指定された日付がJDBC日付エスケープ形式でない場合(yyyy-[m]m-[d]d

また、日付をStringに変換してからsql.dateに変換する必要はないはずです。これは不要なようです(バグが発生しやすい!)。代わりに次のことができます。

Java.sql.Date sqlDate := new Java.sql.Date(now.getTime());
prs.setDate(2, sqlDate);
prs.setDate(3, sqlDate);
2
Vincent Malgrat

現在の日付をデータベースに追加する場合は、Javaで日付を計算することを避けます。 Java(クライアント)側で「今」を決定すると、クライアント側の設定が間違っていたり、時刻やタイムゾーンが間違っていたりすると、データベースで矛盾が発生する可能性があります。代わりに、日付を設定できますサーバー側で次のような方法で:

requestSQL = "INSERT INTO CREDIT_REQ_TITLE_ORDER ("   +
                "REQUEST_ID, ORDER_DT, FOLLOWUP_DT) " +
                "VALUES(?, SYSDATE, SYSDATE + 30)";

...

prs.setInt(1, new Integer(requestID));

この方法では、1つのバインドパラメーターのみが必要であり、サーバー側で日付が計算されるのは一貫しています。さらに良いのは、CREDIT_REQ_TITLE_ORDERに挿入トリガーを追加し、トリガーに日付を挿入させることです。これにより、さまざまなクライアントアプリ(たとえば、sqlplusを介して修正を試みる人)間の一貫性を強化できます。

1
Glenn