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 oracle 代码块

我正在使用一个函数,该函数将日期作为 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

There seems to be a contradiction in what you've said, but the flow isn't very clear. You have a procedure (P_USER_TIME?) which is called from a function (unnamed). Your procedure (and it would be helpful to at least see how that's declared) takes a string argument, but you are passing it a date, not a varchar2 value. Since we don't have your actual procedure, let's make one up:

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;
/

If I call that with the string you're passing as plsql_block I get:

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.

So the time portion is lost. You're converting a string representing the date into a date object, and when it's passed to the procedure it's being implicitly converted back to a string using your default NLS_DATE_FORMAT mask, which I've guessed is probably DD-MON-YYYY; so this is equivalent to doing:

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

Doing to_char(to_date(...)) looks redundant, but because you have an explicit data mask one way and an implicit one the other, it's probably not doing what you expect.

Assuming the P_USER_TIME procedure is expecting the date/time string in the specific format you're passing, you should just pass the string, not try to convert it yourself:

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.

You also have a function that's calling the procedure dynamically. Again, let's make one up:

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.

So the same thing happens. If the construction of plsql_block is simplified to:

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

then you get:

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

PL/SQL procedure successfully completed.

Reading the question again, it may actually be a much simpler underlying problem. You said '... string argument to which I pass the current date in string format using the to_date function'. If that's interpreted literally, it suggests you might just be using to_date when you should have to_char; if you really want the current time that would make the line in the function something like:

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

Or using the direct call to the procedure:

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.

Edited to look at the Java code posted as a comment

Your function now seems to take two arguments, one of which is the block you want to execute; and return a cursor. I'm going to guess (again) that the cursor is returning what's been inserted, so I've changed my dummy procedure to insert the date/time into a table, and my function to retrieve that. This would be a lot easier if you posted a complete set of code that demonstrates the problems you're seeing, of course.

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;
/

I can still call that from SQL*Plus with no problems. And I can have a Java program execute it:

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

Which seems to be fine; this has the output from three calls to the Java program.

You haven't said quite why you think the time is being truncated in your Java code. I'll go even further out on a limb... are you basing that on the display from your Java showing it as 00:00:00; and if so, are you using rs.getDate() instead of rs.getTimestamp? java.sql.Date doesn't have a time portion, unlike java.util.Date. (See this question for example).

于 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 驱动程序相关的日期时间相关错误。例如 - 错误 11864041 - 时间戳变量从 ODBC 传递为 VARCHAR 导致值损坏(Oracle 支持

于 2012-07-31T01:15:12.163 回答