Calling a stored procedure with CLOB output - plsql

I am trying to use the CLOB datatype as the output parameter in my stored procedure because its resultset exceeds the storage capacity of a var datatype.
How do I execute the procedure? Below are the commands I had run to execute.
I tried assigning the resultset to the the CLOB variable using the INTO query as shown in the query.
var cl CLOB;
EXECUTE procedure_name(:cl);
print cl;
How do i declare the binding variable because if you look at the first command, I am first initializing cl as var I am not able to initialize it as CLOB as it is giving out an error.
This is a sample of my procedure. The actual query in the procedure is 700 lines long.
CREATE OR REPLACE PROCEDURE procedure_name (cl OUT CLOB)
IS
BEGIN OPEN cl FOR
SELECT * FROM .....
statement 1
.
.
.
.
.
statement n
INTO cl
FROM
statement 1
.
.
.
statement n
EXCEPTION
WHEN
OTHERS THEN
DECLARE
err_num NUMBER := SQLCODE;
err_msg VARCHAR2(512) := SQLERRM;
error_id_pk NUMBER;
error_dt DATE;
BEGIN
SELECT (REGEXP_REPLACE(CURRENT_TIMESTAMP, '[^0-9]+', ''))INTO error_id_pk FROM DUAL;
SELECT SYSDATE INTO error_dt FROM DUAL;
INSERT INTO ODS_CONTROL.ERROR_DETAILS(ERROR_ID, ERROR_CODE, ERROR_DATE, PROCEDURE_NAME, ERROR_MSG)
VALUES ( error_id_pk,
err_num,
error_dt,
'PRC_FLEXI_CARD',
err_msg
);
END;
END;
Error message:
Error starting at line : 2 in command -
EXECUTE procedure_name( :clb )
Error report -
ORA-06550: line 1, column 7:
PLS-00905: object procedure_name is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:

[TL;DR] VAR is a keyword for declaring a variable and is not a data type; your actual error is due to using invalid syntax when you tried to define your procedure and it has not compiled.
VAR is short for VARIABLE and defines a PL/SQL bind variable.
This declaration has the syntax:
VAR[IABLE] [variable [type] ]
where type represents one of the following:
NUMBER
CHAR
CHAR (n [CHAR | BYTE])
NCHAR
NCHAR (n)
VARCHAR2 (n [CHAR | BYTE])
NVARCHAR2 (n)
BLOB
BFILE
CLOB
NCLOB
REFCURSOR
BINARY_FLOAT
BINARY_DOUBLE
So with:
var cl CLOB;
you are declaring a variable using the VAR keyword and the variable is named cl and has the type CLOB.
Also, your CREATE PROCEDURE statement has a syntax error as you cannot have the single quotes around the procedure name. For example:
CREATE PROCEDURE procedure_name (clb OUT CLOB)
IS
BEGIN
clb := 'test';
END;
/
Then:
VAR cl CLOB;
EXECUTE procedure_name( :cl );
PRINT cl;
Outputs:
test
Updated:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE ERROR_DETAILS(
ERROR_ID NUMBER,
ERROR_CODE NUMBER,
ERROR_DATE DATE,
PROCEDURE_NAME VARCHAR2(30),
ERROR_MSG VARCHAR2(512)
)
/
CREATE PROCEDURE procedure_name (cl OUT CLOB)
IS
BEGIN
SELECT DUMMY
INTO cl
FROM dual
WHERE ROWNUM = 1;
EXCEPTION
WHEN
OTHERS THEN
DECLARE
err_num NUMBER := SQLCODE;
err_msg VARCHAR2(512) := SQLERRM;
BEGIN
INSERT INTO /* ODS_CONTROL. */ ERROR_DETAILS(
ERROR_ID,
ERROR_CODE,
ERROR_DATE,
PROCEDURE_NAME,
ERROR_MSG
) VALUES (
TO_NUMBER( TO_CHAR( CURRENT_TIMESTAMP, 'YYYYMMDDHH24MISSFF9' ) ),
err_num,
SYSDATE,
'PRC_FLEXI_CARD',
err_msg
);
END;
END;
/
Query 1:
SELECT * FROM USER_ERRORS
Results:
No rows selected

Related

Oracle - store large string in CLOB

I need to save a procedure body into a Clob column with a use of variable. String is longer than 4000 characters, so I can't use VarChar2, but with CLOB variable I receive error "ORA-01422: exact fetch returns more than requested number of rows". Same error appears with Varchar2. My PL/SQL block:
DECLARE
txt_procedure CLOB;
BEGIN
SELECT text INTO txt_procedure
FROM all_source
WHERE name = 'My_procedure'
ORDER BY line;
INSERT INTO TABLE1(ID,DATE,CLOB_COLUMN)
VALUES (my_seq.NEXTVAL,'11.10.2018',txt_procedure);
END;
/
How could I insert procedure body into clob column ?
As you will get multiple rows from your query for every line of your source, the following might help:
DECLARE
txt_procedure CLOB;
BEGIN
FOR source_r IN ( SELECT text
FROM all_source
WHERE name = 'My_procedure'
ORDER BY line
)
LOOP
txt_procedure := txt_procedure || chr(10) || source_r.text;
END LOOP;
INSERT INTO TABLE1(ID,DATE,CLOB_COLUMN)
VALUES (my_seq.NEXTVAL,'11.10.2018',txt_procedure);
END;
/
UPDATE
As an alternative, you might also use the DBMS_METADATA package for this:
DECLARE
txt_procedure CLOB;
BEGIN
txt_procedure := DBMS_METADATA.get_ddl(
object_type => 'PROCEDURE',
name => 'My_procedure',
owner => 'YOUR_SCHEMA'
);
INSERT INTO TABLE1(ID,DATE,CLOB_COLUMN)
VALUES (my_seq.NEXTVAL,'11.10.2018',txt_procedure);
END;
/

PLSQL script not working with passing multiple values into IN() caluse

I am very new in PLSQL, i want to pass an array of number into IN() clause value, But Sqldeveloper throw following error messages:
Error report -
ORA-06550: line 11, column 60:
PLS-00382: expression is of wrong type
ORA-06550: line 11, column 53:
PL/SQL: ORA-22905: cannot access rows from a non-nested table item
ORA-06550: line 10, column 4:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
This is my code :
DECLARE
TYPE sc IS TABLE OF transactionhistory.NBSUBCOMPANY%TYPE INDEX BY PLS_INTEGER;
arr sc;
BEGIN
arr(0) := 000;
arr(1) := 111;
arr(2) := 222;
arr(3) := 333;
select count(th.CHCARDNUMBER) as transactions from transactionhistory th INNER JOIN cards ch on ch.NBATTMID=th.NBATTMID where th.dtdate>=to_date('01-oct-2016','dd-mon-yyyy') and th.dtdate<to_date('01-nov-2016','dd-mon-yyyy')
and ch.NBSUBCOMPANY IN (select column_value from table (arr))
and ((th.CHTRANSTYPE in ('2940', '2916', '2941', '2942', '2943', '2944', '2945', '2902', '2917', '2925') and th.NBBASEAMT < 0) or (th.CHTRANSTYPE in ('2922', '2923', '2926', '2950', '2951', '2952', '2953', '2954', '2955') and th.NBBASEAMT > 0) or (th.CHTRANSTYPE in ('1101', '1102', '1104', '1105', '1106', '1107', '1109') and th.BASEII_STATUS = 'C') or th.CHTRANSTYPE not in ('2940', '2916', '2941', '2942', '2943', '2944', '2945', '2902', '2917', '2925', '2922', '2923', '2926', '2950', '2951', '2952', '2953', '2954', '2955', '1101', '1102', '1104', '1105', '1106', '1107', '1109'));
END;
Please suggest me how can i pass this.
You will need to have a workaround.
SQL doesn't support local collection types to be used in the way you want.
Sample Procedure below which will help in resolving
CREATE OR REPLACE type TEST_TYPE
IS
TABLE OF NUMBER;
You will need to create a type in the database for this to work. Can be created inside a package, if you have one.
DECLARE
TEST_VAR TEST_TYPE := TEST_TYPE();
BEGIN
TEST_VAR.extend(1);
TEST_VAR(TEST_VAR.last) := 222;
TEST_VAR.extend(1);
TEST_VAR(TEST_VAR.last) := 333;
FOR rec IN
(SELECT column_value
FROM TABLE(TEST_VAR)
)
LOOP
dbms_output.put_line(rec.column_value);
END LOOP;
END;
Output
222
333
This way, you can use select column_value from table(test_var) for your IN() clause.
Also, you don't necessarily need to follow the extend(i) part. you can simply do the below as well
TEST_VAR TEST_TYPE := TEST_TYPE(222,333);
Have a read - local collection types not allowed in SQL statements
You can use MEMBER OF clause. See below:
As #Sudipta mentioned you cannot use a collection decalred in PLSQL block as you are doing, you need to declare it outside of the PLSQL block.
CREATE OR REPLACE TYPE sc IS TABLE OF NUMBER;
and then
DECLARE
-- TYPE sc IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
arr sc:=sc();
num number;
BEGIN
arr.extend(4);
arr(1) := 0;
arr(2) := 1;
arr(3) := 2;
arr(4) := 3;
Select count(1)
into num
from employee
-- You can use either commented one or uncommented one. your choice.
--where employee_id in (select column_value from table(arr));
where employee_id member of arr;
END;

PLS-00103: Encountered the symbol "IF" when expecting one of the following

Below is my function in Oracle:
create or replace
FUNCTION CALCULATEINT
( DebtNo IN VARCHAR2
, JFlag IN VARCHAR2
, FloatingInterestRate IN NUMBER
) RETURN NUMBER IS
AccInt NUMERIC(17,8):=0;
BEGIN
DECLARE
PrincipalDue NUMERIC(11,2);
InterestDue NUMERIC(17,8);
IF (JFlag IN ('B', 'C', 'Y')) THEN
BEGIN
SELECT
DEF_JUDG_PRINC_DUE ,
DEF_JUDG_PRINC_RATE
bulk collect into PrincipalDue ,InterestDue
FROM
DANT
WHERE
AND DE_NO = DebtNo ;
END;
END IF;
RETURN AccInt;
END;
I am getting errors below:
1.PLS-00103: Encountered the symbol "IF" when expecting one of the following: begin function pragma procedure subtype type current cursor delete exists prior The symbol "begin" was substituted for "IF" to continue.
2.PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
create or replace
FUNCTION CALCULATEINT
( DebtNo IN VARCHAR2
, JFlag IN VARCHAR2
, FloatingInterestRate IN NUMBER
) RETURN NUMBER IS
AccInt NUMERIC(17,8):=0;
BEGIN
DECLARE
PrincipalDue NUMERIC(11,2);
InterestDue NUMERIC(17,8);
BEGIN
IF (JFlag IN ('B', 'C', 'Y')) THEN
SELECT
DEF_JUDG_PRINC_DUE ,
DEF_JUDG_PRINC_RATE
bulk collect into PrincipalDue ,InterestDue
FROM
DANT
WHERE
AND DE_NO = DebtNo ;
END IF;
END;
RETURN AccInt;
END;
Move the if statement from before the anonymous begin to after the begin.
I am certain that is the error.
Correspondingly you also need to move the end statement after the end if block.
Hope this helps.

retrieve recordset with more than one column value using refcursor in oracle

am creating a package in pl/sql . with in this i declared the ref cursor . With in procedure am using select statement with multiple column name . but am not able to get the result.
here i attached my code. Help me to correct the error. Am new to pl/sql
code
CREATE OR REPLACE PACKAGE types AS
TYPE cursor_type IS REF CURSOR;
END Types;
/
CREATE OR REPLACE
PROCEDURE get_CDR_rs (p_no IN zkv.FLD_callingPartyNumber%TYPE,
CDR_recordset OUT SYS_REFCURSOR) AS
BEGIN
OPEN CDR_recordset FOR
SELECT FLD_callingPartyNumber,
FLD_dateTimeConnect
FROM CISCOCUIC_TBL
WHERE FLD_callingPartyNumber= p_no
ORDER BY FLD_callingPartyNumber,;
END get_CDR_rs;
/
SET SERVEROUTPUT ON SIZE 1000000
DECLARE
l_cursor SYS_REFCURSOR;
l_callingPartyNumber zkv.FLD_callingPartyNumber%TYPE;
l_dateTimeConnect zkv.FLD_dateTimeConnect%TYPE;
BEGIN
LOOP
FETCH l_cursor
INTO l_callingPartyNumber, l_dateTimeConnect;
EXIT WHEN l_cursor%NOTFOUND;
END LOOP;
CLOSE l_cursor;
END;
/
Error
9/41 PL/SQL: ORA-00936: missing expression
5/5 PL/SQL: SQL Statement ignored
First thing is there is a syntax error in the procedure. It should be
CREATE OR REPLACE
PROCEDURE get_CDR_rs (p_no IN zkv.FLD_callingPartyNumber%TYPE,
CDR_recordset OUT SYS_REFCURSOR) AS
BEGIN
OPEN CDR_recordset FOR
SELECT FLD_callingPartyNumber,
FLD_dateTimeConnect
FROM CISCOCUIC_TBL
WHERE FLD_callingPartyNumber= p_no
ORDER BY FLD_callingPartyNumber; -- there was a comma which is not required or you
-- missed a column
END get_CDR_rs;
/
Secondly where is get_CDR_rs being called to retrieve the results?
Thirdly why do you need the following? because you are using sys_refcursor
CREATE OR REPLACE PACKAGE types AS
TYPE cursor_type IS REF CURSOR;
END Types;
/
If you would like to see the results of your procedure which returns sys_refcursor, do as follows
variable rset refcursor;
DECLARE
p_no zkv.FLD_callingPartyNumber%TYPE;
BEGIN
p_no := '123';
get_CDR_rs (p_no, :rset);
END;
/
print rset

Dynamic column name to record type variable

DECLARE
TYPE t IS RECORD (
col_name VARCHAR2 (100)
);
t_row t;
cname VARCHAR (100) := 'col_name';
BEGIN
t_row.col_name := 'col';
DBMS_OUTPUT.put_line ('out');
IF t_row.cname IS NULL THEN
DBMS_OUTPUT.put_line ('in');
END IF;
END;
Error at line 1
ORA-06550: line 12, column 12:
PLS-00302: component 'CNAME' must be declared
ORA-06550: line 12, column 3:
PL/SQL: Statement ignored
How can I assign dynamic column name to type variable of record?
You can do that with dynamic sql:
To make the example simpler I'll make your type t a schema object (but basically you don't have to - you can put it in the dynamic part as well)
create or replace type t is object(col_name varchar2(100));
/
Then you can look at this script:
declare
t_row t;
cname varchar2(100) := 'col_name';
begin
t_row := new t('col');
execute immediate 'declare t_in t := :0; begin if t_in.' || cname ||
' is null then dbms_output.put_line(''in''); end if; end;'
using t_row;
end;
Though, I must say, that this is a strange requirement ...
The error is because record t doesn't have a field cname, but col_name:
type t is record (
col_name varchar2(100)
);
One have to know record fields during compile time.
Could tell us what is the real problem you're going to solve ?

Resources