2015-04-17 35 views
0

中执行sql_statement时,我需要立即创建我的sql语句,因为对于此计划的过程,我的表分区将每天都会更改。我已经尝试了几种不同的方法,并且我无法弄清楚如何在'in'in()中运行我的sqlstmt变量。'我试图在运行时创建我的sql_stmt时运行SQL过程。当我试图在()

如果sqlstmt需要是它自己的函数或过程,那很好。

感谢,

所以这是什么,我试图做一个非常简单化的版本:

CREATE OR REPLACE PROCEDURE P1 AS 
BEGIN 
DECLARE 
    L_BODY VARCHAR2 (32767); 
    V_SECONDS VARCHAR2 (6); 
    V_SQLSTMT VARCHAR2 (4000); 

V_SQLSTMT := 'SELECT TO_CHAR(MAX(TIME), ''SSSSS'') TSTAMP FROM TABLENAME PARTITION(P' || TO_CHAR(SYSDATE-1,'YYYYMMDD') || ')'; 

BEGIN 
    V_SECONDS := '0'; 
    L_BODY := L_BODY || '<h3>CHECK LAST RECORD </h3>'; 
    L_BODY := L_BODY || '<TABLE BORDER=1 BGCOLOR="#EEEEEE">'; 
    L_BODY := L_BODY || '<TR BGCOLOR="BLACK">'; 
    L_BODY := L_BODY || '<TH><FONT COLOR="WHITE">TABLE</FONT></TH>'; 
    L_BODY := L_BODY || '<TH><FONT COLOR="WHITE">TIME STAMP</FONT></TH>'; 
    L_BODY := L_BODY || '</TR>'; 

FOR OUTPUT IN (
EXECUTE IMMEDIATE V_SQLSTMT 
) 

LOOP 
L_BODY := L_BODY || '<TR>'; 
L_BODY := L_BODY || '<TD> OUTPUT FROM NAME </TD>'; 
L_BODY := L_BODY || '<TD>' || to_char(trunc(OUTPUT.tstamp/3600),'FM9900')||':'||to_char(trunc(mod(OUTPUT.tstamp,3600)/60),'FM00')||':'||to_char(mod(OUTPUT.tstamp,60),'FM00') || '</TD>'; 
V_SECONDS := V_SECONDS + OUTPUT.TSTAMP; 
END LOOP; 

EXECUTE IMMEDIATE 'alter session SET NLS_DATE_FORMAT=''DD-MON-YYYY:HH24:MI'''; 
EXECUTE IMMEDIATE 'alter session set smtp_out_server=''IP.IP.IP.IP:25'''; 

IF V_SECONDS < 86370 
THEN 
UTL_MAIL.SEND (  
    I'M NOT TYPING ALL THIS OUT 
); 
END IF; 
END; 
END P1; 

回答

0

您不能使用与游标循环动态查询;你需要打开,读取和关闭游标:

DECLARE 
    ... 
    L_TSTAMP VARCHAR2(5); 
    OUTPUT SYS_REFCURSOR; 

BEGIN 
    V_SQLSTMT := 'SELECT TO_CHAR(MAX(TIME), ''SSSSS'') TSTAMP FROM TABLENAME PARTITION(P' || TO_CHAR(SYSDATE-1,'YYYYMMDD') || ')'; 
    V_SECONDS := '0'; 
    ... 
    L_BODY := L_BODY || '</TR>'; 

OPEN OUTPUT FOR V_SQLSTMT; 
LOOP 
FETCH OUTPUT INTO L_TSTAMP; 
EXIT WHEN OUTPUT%NOTFOUND; 
L_BODY := L_BODY || '<TR>'; 
L_BODY := L_BODY || '<TD> OUTPUT FROM NAME </TD>'; 
L_BODY := L_BODY || '<TD>' || to_char(trunc(L_TSTAMP/3600),'FM9900')||':'||to_char(trunc(mod(L_TSTAMP,3600)/60),'FM00')||':'||to_char(mod(L_TSTAMP,60),'FM00') || '</TD>'; 
V_SECONDS := V_SECONDS + L_TSTAMP; 
END LOOP; 
CLOSE OUTPUT; 
... 

不知道为什么你有V_SECONDS作为一个字符串,或为什么你在查询使用TO_CHAR。您可以将秒计数器保留为数字,并将显示值格式化为第二个选择列表项。我不完全确定你想要展示的是什么,而且正如你所说的,这是一个虚拟的版本,你的真实代码中的东西可能会有所不同。

因为,正如你指出,你的查询只能返回一行,则不需要游标循环可言,只是一个动态select ... into

DECLARE 
    L_BODY VARCHAR2 (32767); 
    V_SECONDS NUMBER; 
    V_SQLSTMT VARCHAR2 (200); 
    L_SECONDS NUMBER; BEGIN 
    V_SQLSTMT := 'SELECT TO_NUMBER(TO_CHAR(MAX(TIME), ''SSSSS'')) FROM TABLENAME PARTITION(P' || TO_CHAR(SYSDATE-1,'YYYYMMDD') || ')'; 
    V_SECONDS := 0; 
    L_BODY := L_BODY || '<h3>CHECK LAST RECORD </h3>'; 
    L_BODY := L_BODY || '<TABLE BORDER=1 BGCOLOR="#EEEEEE">'; 
    L_BODY := L_BODY || '<TR BGCOLOR="BLACK">'; 
    L_BODY := L_BODY || '<TH><FONT COLOR="WHITE">TABLE</FONT></TH>'; 
    L_BODY := L_BODY || '<TH><FONT COLOR="WHITE">TIME STAMP</FONT></TH>'; 
    L_BODY := L_BODY || '</TR>'; 

    EXECUTE IMMEDIATE V_SQLSTMT INTO L_SECONDS; 
    L_BODY := L_BODY || '<TR>'; 
    L_BODY := L_BODY || '<TD> OUTPUT FROM NAME </TD>'; 
    L_BODY := L_BODY || '<TD>' || to_char(trunc(L_SECONDS/3600),'FM9900')||':'||to_char(trunc(mod(L_SECONDS,3600)/60),'FM00')||':'||to_char(mod(L_SECONDS,60),'FM00') || '</TD>'; 
    V_SECONDS := V_SECONDS + L_SECONDS; 

    EXECUTE IMMEDIATE 'alter session SET NLS_DATE_FORMAT=''DD-MON-YYYY:HH24:MI'''; 
    EXECUTE IMMEDIATE 'alter session set smtp_out_server=''IP.IP.IP.IP:25'''; 

    IF V_SECONDS < 86370 
    THEN ... 

(我改变了数据类型为数字因为它们是* 8)

缠着我你也可以得到格式化的时间从您的查询字符串,而不必从秒值重新创建它:

DECLARE 
... 
    L_SECONDS NUMBER; 
    L_TIME VARCHAR2(8); 
BEGIN 
    V_SQLSTMT := 'SELECT TO_NUMBER(TO_CHAR(MAX(TIME), ''SSSSS'')), TO_CHAR(MAX(TIME), ''HH24:MI:SS'') FROM TABLENAME PARTITION(P' || TO_CHAR(SYSDATE-1,'YYYYMMDD') || ')'; 
    V_SECONDS := 0; 
... 
    EXECUTE IMMEDIATE V_SQLSTMT INTO L_SECONDS, L_TIME; 
    L_BODY := L_BODY || '<TR>'; 
    L_BODY := L_BODY || '<TD> OUTPUT FROM NAME </TD>'; 
    L_BODY := L_BODY || '<TD>' || L_TIME || '</TD>'; 
    V_SECONDS := V_SECONDS + L_SECONDS; 
... 
+0

这效果很好。谢谢! – magicJerk

+0

Alex - V_SQLSTMT是否总是进入SYS_REFCURSOR?或者我可以将V_SQLSTMT结果直接放到一个变量中,因为这个特定的查询只返回1行?我在问,因为oracle文档说SYS_REFCURSOR用于多行查询。我试着直接进入var,但是oracle说我必须对游标进行读取。谢谢 – magicJerk

+0

@magicJerk - 对,我没有注意到你有单行查询。所以不,你根本不需要光标。用演示更新。 “时间”里有什么数据类型和值?您也可以在查询中执行输出格式。 –

相关问题