0

DBMS_SQL.EXECUTE 関数を使用して Oracle ストアド プロシージャを呼び出そうとしています。PL/SQL ブロックを入力引数として、DBMS_SQL.EXECUTE 関数を使用して DB プロシージャを呼び出す関数に渡しています。プロシージャには、TO_DATE 関数を使用して現在の日付を文字列形式で渡す文字列引数があります。プロシージャを呼び出すために使用した構文については、以下を参照してください。プロシージャが呼び出されると、渡された日付が DATE データ型としてデータベースに保存されます。私が直面している問題は、日付の時間部分が切り捨てられ、関数に渡された時間に関係なく、時間が午前 12:00 になることです。誰かが私が何か間違ったことをしていることを教えてもらえますか?

関数の呼び出しに使用される SQL ブロック:

plsql_block =BEGIN P_USER_TIME(to_date('21-JUL-2012 03:30:30','DD-MON-YYYY HH24:MI:SS')); Return; End;

プロシージャーを呼び出す関数の SQL 構文:

ret_int := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE(ret_int,plsql_block,DBMS_SQL.NATIVE);

ret_int_execute := DBMS_SQL.EXECUTE(ln_dbms_cur);

PFB オラクル コード ブロック

日付を varchar 入力として受け取り、n がそれを別のプロシージャに渡す関数を使用しています。日付に関連付けられた過去の時間が一部のシナリオで挿入されていないことがわかりました。私の機能の下に見つけてください

iv_plsql4 :='10-08-2012 07:30:30';
ln_dbms_cur := DBMS_SQL.OPEN_CURSOR;
iv_plsql2 := BEGIN PKG_PRADEEP.P_INSERTDATE(to_date(iv_plsql4,'DD-MM-YYYY HH24:MI:SS'));

DBMS_OUTPUT.put_line(iv_plsql);
DBMS_SQL.PARSE(ln_dbms_cur,iv_plsql,DBMS_SQL.NATIVE);
ln_cur_execute := DBMS_SQL.EXECUTE(ln_dbms_cur);
This code inserts the date in to the database but the time comes as 12:00 A.M.

しかし、文字列 iv_plsql2 を以下のように変更すると、日付が TIME フィールドに挿入されます。

iv_plsql2 := BEGIN PKG_PRADEEP.P_INSERTDATE(to_date('10-AUG-2012 07:30:30','DD-MM-YYYY HH24:MI:SS'));

誰かがなぜこれが起こるのか説明できますか?

4

2 に答える 2

0

あなたの言っていることは矛盾しているように見えますが、その流れはあまり明確ではありません。関数 (名前なし) から呼び出されるプロシージャ ( P_USER_TIME?) があります。あなたの手順(そして少なくともそれがどのように宣言されているかを確認することは役に立ちます)は文字列引数を取りますがdate、値ではなくを渡していvarchar2ます。実際の手順がないので、作成してみましょう。

create or replace procedure p_user_time(p_time varchar2) is
    l_time date;
begin
    dbms_output.put_line('Parameter p_time: ' || p_time);
    l_time := to_date(p_time, 'DD-MON-YYYY HH24:MI:SS');
    dbms_output.put_line('Converted l_time: ' ||
        to_char(l_time, 'DD-MON-YYYY HH24:MI:SS'));
end;
/

私が得るようにあなたが渡している文字列でそれを呼び出すとplsql_block

alter session set nls_date_format = 'DD-MON-YYYY';
set serveroutput on

exec P_USER_TIME(to_date('21-JUL-2012 03:30:30','DD-MON-YYYY HH24:MI:SS'));

Session altered.

Parameter p_time: 21-JUL-2012
Converted l_time: 21-JUL-2012 00:00:00

PL/SQL procedure successfully completed.

したがって、時間の部分は失われます。日付を表す文字列をdateオブジェクトに変換しています。それがプロシージャに渡されると、デフォルトの NLS_DATE_FORMAT マスクを使用して暗黙的に文字列に変換されますDD-MON-YYYY。したがって、これは次のことと同じです。

exec P_USER_TIME(to_char(to_date('21-JUL-2012 03:30:30','DD-MON-YYYY HH24:MI:SS')));

これを行うto_char(to_date(...))のは冗長に見えますが、明示的なデータ マスクと暗黙的なデータ マスクがあるため、期待どおりの結果が得られない可能性があります。

P_USER_TIMEプロシージャが、渡す特定の形式の日付/時刻文字列を想定していると仮定すると、文字列を自分で変換しようとするのではなく、単に渡す必要があります。

exec P_USER_TIME('21-JUL-2012 03:30:30');

Parameter p_time: 21-JUL-2012 03:30:30
Converted l_time: 21-JUL-2012 03:30:30

PL/SQL procedure successfully completed.

プロシージャを動的に呼び出す関数もあります。もう一度、1 つを作成しましょう。

create or replace function f_foo return number is
    ln_dbms_cur number;
    ret_int number;
    plsql_block varchar2(256);
begin
     plsql_block := 'BEGIN P_USER_TIME(to_date(''21-JUL-2012 03:30:30'',''DD-MON-YYYY HH24:MI:SS'')); END;';

     ln_dbms_cur := DBMS_SQL.OPEN_CURSOR;
     DBMS_SQL.PARSE(ln_dbms_cur, plsql_block, DBMS_SQL.NATIVE);
     ret_int := DBMS_SQL.EXECUTE(ln_dbms_cur);
     DBMS_SQL.CLOSE_CURSOR(ln_dbms_cur);
     return ret_int;
end;
/

var rc number;

exec :rc := f_foo;

Parameter p_time: 21-JUL-2012
Converted l_time: 21-JUL-2012 00:00:00

PL/SQL procedure successfully completed.

だから同じことが起こります。の構築が次のplsql_blockように単純化されている場合:

    plsql_block := 'BEGIN P_USER_TIME(''21-JUL-2012 03:30:30''); END;';

次に、次のようになります。

Parameter p_time: 21-JUL-2012 03:30:30
Converted l_time: 21-JUL-2012 03:30:30

PL/SQL procedure successfully completed.

もう一度質問を読むと、実際にはもっと単純な根本的な問題かもしれません。あなたは「... to_date関数を使用して現在の日付を文字列形式で渡す文字列引数」と言いました。それが文字通り解釈されるto_date場合、必要なときにto_char;を使用している可能性があることを示唆しています。関数の行を次のようにする現在の時刻が本当に必要な場合:

 plsql_block := 'BEGIN P_USER_TIME(to_char(sysdate, ''DD-MON-YYYY HH24:MI:SS'')); END;';

または、プロシージャへの直接呼び出しを使用します。

exec P_USER_TIME(to_char(sysdate, 'DD-MON-YYYY HH24:MI:SS'));

Parameter p_time: 31-JUL-2012 09:38:43
Converted l_time: 31-JUL-2012 09:38:43

PL/SQL procedure successfully completed.

コメントとして投稿されたJavaコードを見るように編集

関数は 2 つの引数を取るようになりました。そのうちの 1 つは実行するブロックです。カーソルを返します。カーソルが挿入されたものを返すと (再び) 推測するので、日付/時刻をテーブルに挿入するようにダミー プロシージャを変更し、それを取得する関数を変更しました。もちろん、発生している問題を示す完全なコード セットを投稿すると、これはずっと簡単になります。

create or replace procedure p_user_time(p_time varchar2) is
    l_time date;
begin
    dbms_output.put_line('Parameter p_time: ' || p_time);
    l_time := to_date(p_time, 'DD-MON-YYYY HH24:MI:SS');
    dbms_output.put_line('Converted l_time: ' ||
        to_char(l_time, 'DD-MON-YYYY HH24:MI:SS'));
    insert into cooldude values(l_time);
end;
/

create or replace function f_foo(pNumber number, p_plsql_block in varchar2)
return sys_refcursor is
    ln_dbms_cur number;
    ret_int number;
    plsql_block varchar2(256);
    rc sys_refcursor;
begin    
     ln_dbms_cur := DBMS_SQL.OPEN_CURSOR;
     DBMS_SQL.PARSE(ln_dbms_cur, p_plsql_block, DBMS_SQL.NATIVE);
     ret_int := DBMS_SQL.EXECUTE(ln_dbms_cur);
     DBMS_SQL.CLOSE_CURSOR(ln_dbms_cur);

     open rc for select * from cooldude;
     return rc;
end;
/

SQL*Plus から問題なく呼び出すことができます。そして、Java プログラムにそれを実行させることができます。

import java.sql.*;
import java.text.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.OracleDataSource;

public class Cooldude
{

    public static void main(String args[]) throws SQLException 
    {
        String plSqlBlk = "BEGIN P_USER_TIME(to_char(sysdate, 'DD-MON-YYYY HH24:MI:SS')); END;";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        Connection conn;
        OracleDataSource ds = new OracleDataSource();
        ds.setURL("jdbc:oracle:thin:scott/oracle@127.0.0.1:1521:orcl");
        conn = ds.getConnection();

        CallableStatement cstmt = null;
        ResultSet rs = null;
        String output = "";
        System.out.println("******calling SP *******");
        cstmt = conn.prepareCall("{? = call f_foo(?,?)}");
        cstmt.setFetchSize(10000);
        cstmt.registerOutParameter(1, OracleTypes.CURSOR);
        cstmt.setInt(2, 204149885);
        cstmt.setString(3, plSqlBlk);
        cstmt.executeQuery();

        rs = (ResultSet) cstmt.getObject(1);
        while (rs.next())
        {
            Timestamp ts = rs.getTimestamp(1);
            System.out.println(sdf.format(ts));
        }

        if ( conn != null )
        {
            try { conn.close(); } catch ( Exception ex ) {}
            conn = null;
        }
    }
}

javac Cooldude.java && java Cooldude

******calling SP *******
2012-08-11 09:45:07
2012-08-11 09:46:04
2012-08-11 09:54:33

これは問題ないようです。これは、Java プログラムへの 3 回の呼び出しからの出力です。

Java コードで時間が切り捨てられていると考える理由については、まだ詳しく説明していません。私は手足をさらに詳しく説明します... Javaのディスプレイに基づいて、それを次のように表示していますか00:00:00?もしそうなら、rs.getDate()代わりに使用していますrs.getTimestampか?java.sql.Dateとは異なり、 には時間部分がありませんjava.util.Date。(たとえば、この質問を参照してください)。

于 2012-07-31T08:30:29.630 に答える
0

これに関する私の最初のスタンスは、STPP_USER_TIME()がタイムスタンプを切り捨てているということです。ただし、そうではない可能性があると確信している場合は、試してみてください-

DECLARE
   ret_int INTEGER;
   plsql_block  VARCHAR2(1000);
BEGIN
   plsql_block :='BEGIN P_USER_TIME(to_timestamp(''21-JUL-2012 03:30:30'',''DD-MON-YYYY HH24:MI:SS'')); END;';
   ret_int := DBMS_SQL.OPEN_CURSOR;
   DBMS_SQL.PARSE(ret_int,plsql_block,DBMS_SQL.NATIVE);
   ret_int_execute := DBMS_SQL.EXECUTE(ret_int);
   DBMS_SQL.CLOSE_CURSOR(ret_int);
EXCEPTION
WHEN OTHERS THEN
   DBMS_SQL.CLOSE_CURSOR(ret_int);
END;

注 - ODBC ドライバーに関連する日時関連のバグが多数あります。例 - Bug 11864041 - TIMESTAMP VARIABLE PASSED AS VARCHAR FROM ODBC CAUSING VALUE TO BE CORRUPT ( Oracle サポート)

于 2012-07-31T01:15:12.163 に答える