Drop and Create table if exist if not then Create in oracle Procedure - stored-procedures

I have a query that takes start and end year for data also it takes a name of a table as procedure parameters..
the query then will create a table with that name if it doesn't exist or if exist it will drop and recreate it
CREATE OR REPLACE Procedure USE_RAWDATA
( START_RP IN NUMBER, END_RP IN NUMBER,TABLE_NAME varchar)
IS
v_listStr CLOB;
DAT VARCHAR(500):=to_char(to_date(SYSDATE), 'yyyymmdd');
cnt NUMBER;
BEGIN
BEGIN
SELECT COUNT(*) INTO cnt FROM user_tables WHERE table_name = TABLE_NAME||'_'||DAT;
dbms_output.put_line(TABLE_NAME||'_'||DAT);
dbms_output.put_line(cnt);
IF (cnt) = 1 THEN
EXECUTE IMMEDIATE 'DROP TABLE '||TABLE_NAME||'_'||DAT;
dbms_output.put_line('DROP TABLE '||TABLE_NAME||'_'||DAT);
END IF;
END;
select rtrim(xmlagg(xmlelement(e,column_name,', ').extract('//text()') order by column_id).getclobval(),', ') x INTO v_listStr from RAW_DATA_METADATA WHERE (START_ROUND<= END_RP and END_ROUND is NULL) or (START_ROUND >= START_RP and END_ROUND <= END_RP );
EXECUTE IMMEDIATE 'CREATE TABLE '||TABLE_NAME||'_'||DAT||' AS SELECT '||v_listStr ||' FROM RAW_DATA WHERE ROUND_ID BETWEEN '||START_RP ||' AND '||END_RP;
END;
/
my problem is that cnt is always giving me 0 even the table exists then the procedure will end with an error table already exist...
I don't know why .. since when I try it as PL\SQL query it gives me a correct result cnt =1 if exist
declare
v_listStr CLOB;
DAT VARCHAR(500):=to_char(to_date(SYSDATE), 'yyyymmdd');
cnt NUMBER;
BEGIN
BEGIN
SELECT COUNT(*) INTO cnt FROM user_tables WHERE :TABLE_NAME = :TABLE_NAME||'_'||DAT;
dbms_output.put_line(:TABLE_NAME||'_'||DAT);
dbms_output.put_line(cnt);
IF (cnt) = 1 THEN
EXECUTE IMMEDIATE 'DROP TABLE '||:TABLE_NAME||'_'||DAT;
dbms_output.put_line('DROP TABLE '||:TABLE_NAME||'_'||DAT);
END IF;
END;
select rtrim(xmlagg(xmlelement(e,column_name,', ').extract('//text()') order by column_id).getclobval(),', ') x INTO v_listStr from RAW_DATA_METADATA WHERE (START_ROUND<= :END_RP and END_ROUND is NULL) or (START_ROUND >= :START_RP and END_ROUND <= :END_RP );
EXECUTE IMMEDIATE 'CREATE TABLE '||:TABLE_NAME||'_'||DAT||' AS SELECT '||v_listStr ||' FROM RAW_DATA WHERE ROUND_ID BETWEEN '||:START_RP ||' AND '||:END_RP;
END;
/
can you help me figure out why it always cnt gives 0 even the table is exist

This query can only ever return 0:
select count(*) into cnt
from user_tables
where table_name = table_name || '_' || dat;
You need to either prefix table_name with the procedure name
select count(*) into cnt
from user_tables
where table_name = use_rawdata.table_name || '_' || dat;
or else name your parameters differently (tableName, p_table_name etc).
I'd also suggest removing the first begin and end as they aren't doing anything, and adjusting your indentation to reflect the code structure more accurately.
I make it something like this:
create or replace procedure use_rawdata
( start_rp in number
, end_rp in number
, table_name varchar2 )
is
v_liststr clob;
dat varchar2(8) := to_char(sysdate, 'yyyymmdd');
cnt number;
begin
select count(*) into cnt
from user_tables
where table_name = upper(use_rawdata.table_name) || '_' || dat;
dbms_output.put_line(table_name || '_' || dat);
dbms_output.put_line(cnt);
if cnt = 1 then
execute immediate 'DROP TABLE ' || table_name || '_' || dat;
dbms_output.put_line('DROP TABLE ' || table_name || '_' || dat);
end if;
select rtrim(xmlagg(xmlelement(e, column_name, ', ').extract('//text()') order by column_id).getclobval(), ', ') x
into v_liststr
from raw_data_metadata
where (start_round <= end_rp and end_round is null)
or (start_round >= start_rp and end_round <= end_rp);
execute immediate 'create table ' || table_name || '_' || dat || ' as select ' || v_liststr || ' from raw_data where round_id between ' || start_rp || ' and ' || end_rp;
end;

Related

How to execute a multi row cursor as a table report

Dear friends i have done this:
FUNCTION ALL_CLIENTS_DATA
( client_in IN varchar2)
RETURN sys_refcursor
IS c1 sys_refcursor;
BEGIN
OPEN c1 FOR
Select TO_CHAR('SELECT '''||ATR_NOMBRE_ATRIBUTO||''','||ATR_VALOR_ATRIBUTO||' FROM '||ATR_VALOR_TABLA||' WHERE NRO_CLIENTE='''||client_in||''';')FROM GNT_ATRIBUTO WHERE ATR_TAB_IDENTIFICADOR = 7;
RETURN c1;
END;
And receiving this as cursor/function value:
SELECT 'Estado',TO_CHAR(DECODE(estado,0,'ACTIVO',1,'ELIMINADO',2,'RETIRADO',3,'NUEVO',4,'PROCESO DE RETIRO','No Disponible')) FROM cliente WHERE NRO_CLIENTE='253417';
SELECT 'SED-Cuadro-Llave',cadena FROM cliente WHERE NRO_CLIENTE='253417';
SELECT 'Sector',to_char(sector) FROM cliente WHERE NRO_CLIENTE='253417';
SELECT 'Zona',to_char(zona) FROM cliente WHERE NRO_CLIENTE='253417';
.
.
.
And this if I execute line for line (alone for testing):
Estado ACTIVO
SED-Cuadro-Llave 00100S / 21 / 3SP
Sector 89
Zona 291
.
.
.
I just don't know how to display my final result in a single execution. Please help.
If you want all the attributes in one row you need to assemble a query from the result set of GNT_ATRIBUTO then open the cursor for that.
FUNCTION ALL_CLIENTS_DATA
( client_in IN varchar2)
RETURN sys_refcursor
IS
stmt varchar2(32767);
c1 sys_refcursor;
l_tgt_table varchar2 (32767);
BEGIN
stmt := 'select ';
for lrec in (
Select ATR_NOMBRE_ATRIBUTO
, ATR_VALOR_ATRIBUTO
, ATR_VALOR_TABLA
, rownum as rn
from GNT_ATRIBUTO
where ATR_TAB_IDENTIFICADOR = 7
)
loop
if lrec.rn > 1 then
stmt := stmt || ',';
end if;
stmt := stmt || lrec.ATR_VALOR_ATRIBUTO
|| ' as "' || lrec.ATR_NOMBRE_ATRIBUTO || '"';
l_tgt_table := lrec.ATR_VALOR_TABLA;
end loop;
stmt := stmt || ' from ' || l_tgt_table
|| ' WHERE NRO_CLIENTE= :p1 ';
OPEN c1 FOR stmt using client_in;
RETURN c1;
END;

Dynamic order by multiple columns in SQL Server

I use SQL Server 2012. I have a sample table named 'Table1' with seven columns.
CREATE TABLE TABLE1
(
Field1 INT ,
Field2 INT ,
Field3 INT ,
Field4 INT ,
Field5 INT ,
Field6 INT ,
Field7 INT
)
GO
INSERT INTO TABLE1 VALUES (1,2,9,5,1,5,85)
INSERT INTO TABLE1 VALUES (2,6,8,4,1,4,45)
INSERT INTO TABLE1 VALUES (3,5,7,3,5,6,1)
INSERT INTO TABLE1 VALUES (4,4,6,1,51,4,1)
INSERT INTO TABLE1 VALUES (5,5,5,4,7,2,7)
INSERT INTO TABLE1 VALUES (6,5,4,6,4,7,8)
INSERT INTO TABLE1 VALUES (7,12,5,3,2,5,3)
INSERT INTO TABLE1 VALUES (8,1,6,5,9,5,1)
INSERT INTO TABLE1 VALUES (9,1,13,2,1,7,3)
INSERT INTO TABLE1 VALUES (10,6,9,3,6,2,6)
INSERT INTO TABLE1 VALUES (11,2,1,2,8,7,7)
INSERT INTO TABLE1 VALUES (12,7,6,1,3,3,2)
INSERT INTO TABLE1 VALUES (13,7,2,6,4,7,1)
GO
I have created the below Stored Procedure, This SP is able to query data considering the asked order by column.
I can query my table with each possibility of single column and kind of order by (ASC or Desc).
CREATE Procedure ProceName
(
#OrderByField INT = 1,
#OrderDirection INT = 0 -- 0 = Asc , 1 = Desc
)
As
Begin
SELECT
*
FROM Table1
ORDER BY
CASE WHEN #OrderDirection=0 AND #OrderByField=1 THEN Field1 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=2 THEN Field2 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=3 THEN Field3 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=4 THEN Field4 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=5 THEN Field5 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=6 THEN Field6 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=7 THEN Field7 END ASC,
CASE WHEN #OrderDirection=1 AND #OrderByField=1 THEN Field1 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=2 THEN Field2 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=3 THEN Field3 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=4 THEN Field4 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=5 THEN Field5 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=6 THEN Field6 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=7 THEN Field7 END DESC End
GO
EXECUTE ProceName #OrderByField=1, #OrderDirection=0
EXECUTE ProceName #OrderByField=6, #OrderDirection=1
Now I need to change this sp for accepting multi columns as order by series columns. They can be pass by name or by order of columns.
In this case i should be able to execute my SP like below command:
EXECUTE ProceName #OrderByField='6,7,2', #OrderDirection='0,1,1'
How can I achive this gool with out using the sp_executesql (Dynamic Query)?
Well, your ascending and descending wouldn't matter in your case unless you were trying to choose asc and desc for each column. Here is using the last column.
DECLARE #OrderByField VARCHAR(64) = '1,3,7'
DECLARE #DynamicColumns VARCHAR(256) = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#OrderByField,1,'FIELD1'),2,'FIELD2'),3,'FIELD3'),4,'FIELD4'),5,'FIELD5'),6,'FIELD6'),7,'FIELD7')
DECLARE #OrderDirection INT = 1
DECLARE #order varchar(4)
SET #order = CASE WHEN #OrderDirection = 1 THEN 'DESC' ELSE 'ASC' END
--uncomment this line of code to add the sort to every column which only matters for DESC since ASC is default
--SET #DynamicColumns = REPLACE(#DynamicColumns,',', ' ' + #order + ',')
DECLARE #sql VARCHAR(MAX) = (
'SELECT
*
FROM Table1
ORDER BY ' + #DynamicColumns + ' ' + #order)
SELECT #sql
EXEC(#sql)
CREATE Procedure ProceName
(
#OrderByField VARCHAR(100),
#OrderDirection VARCHAR(100),
)
As
Begin
Declare #SQL VARCHAR(MAX)
if OBJECT_ID('Example1') is not null
begin
drop table Example
end
if OBJECT_ID('Example2') is not null
begin
drop table Example2
end
Create table Example1
(
id int identity(1,1),
Field varchar(20)
)
Create table Example2
(
id int identity(1,1),
OrderNumber varchar(10)
)
--iterate each element for both #OrderByField and #OrderDirection
Declare #separator char(1)=','
Declare #position int = 0
Declare #name varchar(20)
Set #OrderByField = #OrderByField + #separator
---------------------------------------------------------------------------
/*iterate each for #OrderByField */
---------------------------------------------------------------------------
While CHARINDEX (#separator,#OrderByField,#position) != 0
BEGIN
SET #name = SUBSTRING (#OrderByField,#position,CHARINDEX (#separator,#OrderByField,#position)-#position)
SET #SQL = 'Insert into Example1([Field]) Values(' + char(39) + #name + char(39) + ')'
EXEC(#SQL)
SET #position = CHARINDEX(#separator,#OrderByField,#position)+1
END
---------------------------------------------------------------------------
/*iterate each for #OrderDirection */
---------------------------------------------------------------------------
SET #position = 0 --do not forget to reset the position number
Set #OrderDirection = #OrderDirection + #separator
While CHARINDEX (#separator,#OrderDirection,#position) != 0
BEGIN
SET #name = SUBSTRING (#OrderDirection,#position,CHARINDEX (#separator,#OrderDirection,#position)-#position)
SET #SQL = 'Insert into Example2([OrderNumber]) Values(' + char(39) + #name + char(39)+ ')'
EXEC(#SQL)
SET #position = CHARINDEX(#separator,#OrderDirection,#position)+1
END
Set #name = '' --reset the #name for the use of Cursor
declare #NewName varchar(500) =''
Declare row_cursor CURSOR
FOR
select 'Field'+a.Field + ' '+ case when b.OrderNumber = 0 then 'ASC' else 'DESC' end +',' as command
from Example1 as a
inner join Example2 as b
on b.id = a.id
OPEN row_cursor
FETCH NEXT FROM row_cursor into #name
WHILE (##FETCH_STATUS =0)
begin
Set #NewName = #NewName + #name
FETCH NEXT FROM row_cursor into #name
end
close row_cursor
deallocate row_cursor
SET #NewName = REVERSE(STUFF(REVERSE(#NewName),1,1,''))
SET #SQL = 'Select * From Table1 Order by ' + #NewName
--Print(#SQL)
EXEC (#SQL)
END

IBM DB2 Equivalent syntax for SQL Server Stored Procedure - error while deploying

I am newbie to IBM db2.Need to convert the below mentioned SP to db2 syntax. But i am stuck with many equivalents used or available in Db2. Even google research doesn't show how exactly we can compare object id of tables in db2 as I am doing in SQL Server stored procedure. Could anyone suggest me with right way to proceed?
EDIT: I have updated with equivalent DB2 syntax, but facing below error while deploying at the particular line, Can anyone identify and help me understand what is wrong with this syntax or the problem lies anywhere else in the procedure.
line no 25 : DECLARE v_sqlstate CHAR(5);
BACKUPTABLE: 25: An unexpected token "<variable declaration> was found following "". Expected tokens may include: "".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.18.60
An unexpected token variable declaration was found following "". Expected tokens may include: "".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.18.60
SQL Server Stored procedure syntax:
CREATE PROCEDURE [dbo].[BackUpTable]
#TableName sysname
AS
BEGIN
SET nocount ON
DECLARE #sql VARCHAR(500)
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = Object_id(N'[dbo].[' + #TableName+'_EST' + ']')
AND TYPE IN ( N'U' ))
BEGIN
SET #sql = 'declare #Done bit
set #Done = 0
while #Done = 0
begin
delete top (100000)
from ' + #TableName + '_Bak' +
' if ##rowcount = 0
set #Done = 1
end;'
SET #sql = #sql + 'insert into ' + #TableName + '_Bak select * from ' +
#TableName +'_EST'
EXEC(#sql)
END
ELSE
BEGIN
DECLARE #err_message VARCHAR(300)
SELECT #err_message = 'The table "' + Isnull(#TableName, 'null') +
'" does not exist'
RAISERROR (#err_message, 16, 1)
END
END
DB2 SYNTAX CREATED SO FAR:
CREATE OR REPLACE PROCEDURE BackUpTable (IN TableName VARCHAR(128))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE dynamicSql VARCHAR(500);
IF(EXISTS(
SELECT * FROM SYSIBM.SYSTABLES
WHERE NAME = TableName||'_EST'
)
)
THEN
SET dynamicSql = 'DELETE FROM '||TableName ||'_BAK';
SET dynamicSql = dynamicSql ||'insert into ' || TableName || '_BAK select * from ' ||
TableName || '_EST';
EXECUTE IMMEDIATE dynamicSql;
ELSE
DECLARE v_sqlstate CHAR(5);
DECLARE v_sqlcode INT;
DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
DECLARE SQLCODE INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT SQLSTATE, SQLCODE
INTO v_sqlstate, v_sqlcode
FROM sysibm.sysdummy1;
SET O_Error_Msg = 'TABLE IS NOT AVAILABLE:: SQLState : '||v_sqlstate||' SQLCode : '||v_sqlcode ;
END;
END IF;
END
on z/os you can do it:
IF( EXISTS( SELECT 1 FROM QSYS2.SYSTABLES WHERE TABLE_SCHEMA = 'YOURLIB' AND TABLE_NAME = 'YOURTABLENAME')) THEN
DROP TABLE YOURLIB.YOURTABLENAME;
END IF;

Intermittent errors when performing export to file in Oracle 11g

System info
Oracle database 11g/11.2 Enterprise edition
Summary
When the procedure is called (via Hibernate's CallableStatements), it gets all the partitions to be exported based on the days to keep (an input parameter). After those partitions are evaluated, the function which accepts partitions lists as input parameters (the first one in the wall of code) uses the DBMS_DATAPUMP API to export the content into a flat file.
Sometimes (I don't have a 100% reproducible scenario) it fails with the error below. It has to be noted that 99.9% of the time these procedures run smootly. The database user has write access to the exports directory.
The procedure:
TYPE PARTITION_NAME_TYPE IS RECORD (
PARTITION_NAME VARCHAR2(32)
);
TYPE PARTITION_LIST IS REF CURSOR RETURN PARTITION_NAME_TYPE;
PROCEDURE EXPORT_PARTITIONS (
P_TABLE_NAME IN VARCHAR2,
P_PARTITION_LIST IN PARTITION_LIST,
P_EXPORT_DIR IN VARCHAR2,
P_PARALLELISM_DEGREE IN NUMBER DEFAULT 1,
P_FILE_PATH OUT VARCHAR2,
P_RESULT OUT VARCHAR2,
P_RESULT_MSG OUT VARCHAR2)
IS
V_PUMP_HANDLE NUMBER; -- Data Pump job handle
V_PUMP_STATE VARCHAR2(255);
V_PUMP_FILE VARCHAR2(255);
V_PUMP_DIR VARCHAR2(255);
V_JOB_STATE VARCHAR2(4000);
V_STATUS KU$_STATUS1010;
V_LOGS KU$_LOGENTRY1010;
V_ROW PLS_INTEGER;
V_ERRORDETAILS VARCHAR2(4000);
V_PARTITION_LIST VARCHAR2(32767);
V_PARTITION_LIST_TEMP PARTITION_NAME_TYPE;
BEGIN
FETCH P_PARTITION_LIST INTO V_PARTITION_LIST_TEMP;
IF P_PARTITION_LIST%NOTFOUND THEN
P_RESULT := 'FAILED';
P_RESULT_MSG := 'No partitions to export';
RETURN;
END IF;
V_PARTITION_LIST := V_PARTITION_LIST_TEMP.PARTITION_NAME;
V_PUMP_FILE := V_PARTITION_LIST_TEMP.PARTITION_NAME;
LOOP
FETCH P_PARTITION_LIST INTO V_PARTITION_LIST_TEMP;
IF P_PARTITION_LIST%NOTFOUND THEN
V_PUMP_FILE := V_PUMP_FILE || '_TO_' || V_PARTITION_LIST_TEMP.PARTITION_NAME;
EXIT;
END IF;
V_PARTITION_LIST := V_PARTITION_LIST || ',' || V_PARTITION_LIST_TEMP.PARTITION_NAME;
END LOOP;
V_PUMP_HANDLE := DBMS_DATAPUMP.OPEN('EXPORT', 'TABLE');
DBMS_DATAPUMP.ADD_FILE(HANDLE => V_PUMP_HANDLE, FILENAME => V_PUMP_FILE || '.dbf' , DIRECTORY => P_EXPORT_DIR, FILETYPE => DBMS_DATAPUMP.KU$_FILE_TYPE_DUMP_FILE);
DBMS_DATAPUMP.ADD_FILE(V_PUMP_HANDLE, V_PUMP_FILE || '.log',P_EXPORT_DIR, NULL, DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE);
DBMS_DATAPUMP.DATA_FILTER (V_PUMP_HANDLE, 'PARTITION_LIST', V_PARTITION_LIST);
DBMS_DATAPUMP.SET_PARALLEL(V_PUMP_HANDLE, P_PARALLELISM_DEGREE);
DBMS_DATAPUMP.START_JOB (V_PUMP_HANDLE);
DBMS_DATAPUMP.WAIT_FOR_JOB(V_PUMP_HANDLE, V_PUMP_STATE);
DBMS_DATAPUMP.DETACH(V_PUMP_HANDLE);
P_RESULT := 'SUCCESS';
-- get actual path to Export Directory
SELECT directory_path INTO V_PUMP_DIR FROM ALL_DIRECTORIES WHERE directory_name = P_EXPORT_DIR;
P_FILE_PATH := V_PUMP_DIR || '/' || V_PUMP_FILE || '.dbf';
P_RESULT_MSG := 'Successfully exported ' || P_TABLE_NAME || '(' || V_PARTITION_LIST || ') as ' || V_PUMP_FILE || '.dbf';
EXCEPTION
WHEN OTHERS THEN
DBMS_DATAPUMP.GET_STATUS(V_PUMP_HANDLE, 8, 0, V_JOB_STATE, V_STATUS);
V_LOGS := V_STATUS.ERROR;
V_ROW := V_LOGS.FIRST;
LOOP
EXIT WHEN V_ROW IS NULL;
V_ERRORDETAILS := 'LOGLINENUMBER='||V_LOGS(V_ROW).LOGLINENUMBER || ' ERRORNUMBER='||V_LOGS(V_ROW).ERRORNUMBER || ' LOGTEXT='||V_LOGS(V_ROW).LOGTEXT;
V_ROW := V_LOGS.NEXT (V_ROW);
END LOOP;
P_RESULT_MSG := 'Failed to export partitions on ' || P_TABLE_NAME || '(' || V_PARTITION_LIST || ') : ' || SQLERRM || ' Details: (' || V_ERRORDETAILS || ')';
P_RESULT := 'FAILED';
DBMS_DATAPUMP.STOP_JOB(V_PUMP_HANDLE);
END EXPORT_PARTITIONS;
PROCEDURE EXPORT_PARTITIONS (
P_TABLE_NAME IN VARCHAR2,
P_NUM_DAYS_TO_KEEP IN NUMBER,
P_EXPORT_DIR IN VARCHAR2,
P_PARALLELISM_DEGREE IN NUMBER DEFAULT 1,
P_FILE_PATH OUT VARCHAR2,
P_RESULT OUT VARCHAR2,
P_RESULT_MSG OUT VARCHAR2)
IS
V_MIN_DAYS_TO_KEEP NUMBER := 1;
V_CNT NUMBER;
V_PARTITIONS PARTITION_LIST;
V_EXPORT_PARTITIONS_RESULT VARCHAR2(2000);
V_EXPORT_PARTITIONS_RESULT_MSG VARCHAR2(2000);
BEGIN
IF P_NUM_DAYS_TO_KEEP < V_MIN_DAYS_TO_KEEP THEN
RAISE_APPLICATION_ERROR(-20000, 'Cannot drop partitions less than ' || V_MIN_DAYS_TO_KEEP || ' days old.');
END IF;
SELECT COUNT(*)
INTO V_CNT
FROM USER_TABLES
WHERE TABLE_NAME = P_TABLE_NAME;
IF V_CNT = 0 THEN
RAISE_APPLICATION_ERROR(-20000, 'Table Does Not Exist');
END IF;
OPEN V_PARTITIONS FOR SELECT partition_name
FROM USER_TAB_PARTITIONS
WHERE table_name = UPPER(P_TABLE_NAME)
AND
CASE
WHEN INSTR(PARTITION_NAME, 'MAXVALUE') = 0
THEN TO_DATE(SUBSTR(PARTITION_NAME, -8), 'YYYYMMDD')
END < TRUNC(SYSDATE) - P_NUM_DAYS_TO_KEEP
ORDER BY partition_name ASC;
EXPORT_PARTITIONS(P_TABLE_NAME, V_PARTITIONS, P_EXPORT_DIR, P_PARALLELISM_DEGREE, P_FILE_PATH, V_EXPORT_PARTITIONS_RESULT, V_EXPORT_PARTITIONS_RESULT_MSG);
CLOSE V_PARTITIONS;
IF INSTR(V_EXPORT_PARTITIONS_RESULT, 'SUCCESS') = 0 THEN
RAISE_APPLICATION_ERROR(-20000, 'Cannot export partitions. Logs purging will not proceede. ' || V_EXPORT_PARTITIONS_RESULT_MSG);
END IF;
P_RESULT := 'SUCCESS';
P_RESULT_MSG := V_EXPORT_PARTITIONS_RESULT_MSG;
EXCEPTION
WHEN OTHERS THEN
P_RESULT_MSG := 'Failed To Export Partition on ' || P_TABLE_NAME || ': ' || SQLERRM;
P_RESULT := 'FAILED';
END EXPORT_PARTITIONS;
The error:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at * . *, line 208
ORA-39001: invalid argument value
What's on line 208 can be found below:
SQL> select text from all_source where type = 'PACKAGE BODY' and owner = '***' and name = '***' and line = '208';
TEXT
--------------------------------------------------------------------------------
P_RESULT_MSG := 'Failed to export partitions on ' || P_TABLE_NAME || '(' || V_
PARTITION_LIST || ') : ' || SQLERRM || ' Details: (' || V_ERRORDETAILS || ')';
After busting my head around for several days, I still haven't managed to find the problematic piece of code.
Edit #1
The caller of the procedure is a Hibernate CallableStatement. The declaration of the resultMsg on the java side is as follows:
call.registerOutParameter("resultMsg", Types.VARCHAR);
This calls the EXPORT_PARTITIONS(tableName, daysToKeep, exportDir, paralelismDegree) procedure, which then calls the second EXPORT_PARTITIONS procedure.

How to send the result of a select query to a message body of a mail in oracle 10G

CREATE OR REPLACE PROCEDURE STATUS_MAIL(FROM_MAIL IN VARCHAR2, TO_MAIL IN VARCHAR2)
is
v_From VARCHAR2(80) := FROM_MAIL;
v_Recipient VARCHAR2(80) := TO_MAIL;
v_Subject VARCHAR2(80) := 'EMPLOYEE STATUS';
v_Mail_Host VARCHAR2(30) := 'xx.xx.xxx.xxx';
v_Mail_Conn utl_smtp.Connection;
v_msg_body VARCHAR2(5000);
v_output VARCHAR2(5000);
BEGIN
/*Result always returns 42 rows*/
v_output := 'select empid,ename,mobile,dept from employee';
EXECUTE IMMEDIATE v_output into v_msg_body;
v_Mail_Conn := utl_smtp.Open_Connection(v_Mail_Host, xx);
utl_smtp.Helo(v_Mail_Conn, v_Mail_Host);
utl_smtp.Mail(v_Mail_Conn, v_From);
utl_smtp.Rcpt(v_Mail_Conn, v_Recipient);
utl_smtp.Data(v_Mail_Conn,
'Date: ' || to_char(sysdate, 'Dy, DD Mon YYYY hh24:mi:ss') || UTL_TCP.crlf ||
'From: ' || v_From || UTL_TCP.crlf ||
'Subject: '|| v_Subject || UTL_TCP.crlf ||
'To: ' || v_Recipient || UTL_TCP.crlf ||
UTL_TCP.crlf || v_msg_body );
utl_smtp.Quit(v_mail_conn);
EXCEPTION
WHEN utl_smtp.Transient_Error OR utl_smtp.Permanent_Error then
raise_application_error(-20000, 'Unable to send mail: '||sqlerrm);
END;
Getting an error inconsistent datatypes
# EXECUTE IMMEDIATE v_output into v_msg_body
while executing the above procedure, please help me....
So in fact your real question is: "how do I aggregate multiple rows into a single string ?"
The answer is to use aggregate functions. Oracle has introduced listagg-function in 11gR2 that solves this problem nicely but in earlier releases one has to do a bit more work.
When you know the right keywords Google finds a plenty of great resources, e.g.
String Aggregation Techniques
listagg function in 11g release 2
the collect function in 10g
I have collected the following examples from the above mentioned resources. Hope this gives you a good starting point:
The table that will be queried:
create table foo (d1 number, d2 varchar2(10));
insert all
into foo values(1, 'a')
into foo values(2, 'b')
into foo values(3, 'c')
select 1 from dual;
commit;
Oracle 11gR2:
declare
v_str varchar2(32767);
begin
select listagg('key = ' || d1 || ' value = ' || d2, chr(10))
within group (order by d1)
into v_str
from foo;
dbms_output.put_line(v_str);
exception
when value_error then
dbms_output.put_line('Exception: trying to insert too many characters to a varchar2 variable.');
end;
/
Oracle 10g:
create or replace type str_list_t as table of varchar2(32676);
/
create function to_string (
nt_in in str_list_t,
delimiter_in in varchar2 default ','
) return varchar2 is
v_idx pls_integer;
v_str varchar2(32767);
v_dlm varchar2(10);
begin
v_idx := nt_in.first;
while v_idx is not null loop
v_str := v_str || v_dlm || nt_in(v_idx);
v_dlm := delimiter_in;
v_idx := nt_in.next(v_idx);
end loop;
return v_str;
end;
/
declare
v_str varchar2(32676);
begin
select to_string(cast(collect('key = ' || d1 || ' value = ' || d2) as str_list_t), chr(10))
into v_str
from foo;
dbms_output.put_line(v_str);
exception
when value_error then
dbms_output.put_line('Exception: trying to insert too many characters to a varchar2 variable.');
end;
/
Note how I'll catch value_error exception that will be raised if the aggregated string won't fit into the reserved varchar2 capacity.
Output of both examples:
key = 1 value = a
key = 2 value = b
key = 3 value = c

Resources