Oracle select statement based on multiple input parameters - oracle

How I achieve the following in oracle 11g.
CREATE OR REPLACE PROCEDURE sel_tblStateMaster (
p_id IN NUMBER DEFAULT NULL,
p_code IN varchar DEFAULT NULL,
p_name IN varchar DEFAULT NULL),
p_result OUT sys_refcursor
as
begin
// Dummy code
OPEN p_result FOR SELECT * FROM TBLSTATEMASTER;
if not p_code IS NULL
OPEN p_result FOR SELECT * FROM p_result where code=p_code;
end if;
if not p_name IS NULL
OPEN p_result FOR SELECT * FROM p_result where name=p_name;
end if;
end
/
I know above specified query is not correct, I just need a corrected solution for Oracle.

It is a simple IF-ELSE construct:
IF p_code IS NOT NULL AND p_name IS NOT NULL
THEN
OPEN p_result FOR SELECT * FROM TBLSTATEMASTER WHERE code=p_code AND NAME=p_name;
ELSE
OPEN p_result FOR SELECT * FROM TBLSTATEMASTER;
END IF;

The IF statement should have a then clause
CREATE OR REPLACE PROCEDURE sel_tblStateMaster (
p_id IN NUMBER DEFAULT NULL,
p_code IN varchar DEFAULT NULL,
p_name IN varchar DEFAULT NULL),
p_result OUT sys_refcursor
as
begin
// Dummy code
OPEN p_result FOR SELECT * FROM TBLSTATEMASTER;
if not p_code IS NULL
then
OPEN p_result FOR SELECT * FROM p_result where code=p_code;
end if;
if not p_name IS NULL
then
OPEN p_result FOR SELECT * FROM p_result where name=p_name;
end if;
end;

Related

The declaration of the type of this expression is incomplete or malformed

I am working on the following stored procedure.
My_Procedure
create or replace PROCEDURE My_Procedure(
v_ID IN NUMBER DEFAULT 0 ,
v_DETAIL_ID IN NUMBER DEFAULT 0 ,
v_HEADER_ID IN NUMBER DEFAULT 0 ,
v_JOB_DETAIL_ID IN NUMBER DEFAULT 0 ,
v_TABLE_NAME IN VARCHAR2,
v_ESCALATION_TYPE IN VARCHAR2 DEFAULT NULL ,
v_COLUMN_LIST IN NVARCHAR2 DEFAULT NULL ,
cv_1 OUT SYS_REFCURSOR,
cv_2 OUT SYS_REFCURSOR ) AS BEGIN NUll; END;
Stored Procedure in which i am executing
DECLARE
v_ident VARCHAR(30000) := NULL;
v_columns
varchar(30000) := NULL;
v_job_header_id number := 0;
BEGIN
SELECT
(
SELECT
rtrim(XMLAGG(xmlelement(e, c.column_name, ',').extract('//text()')
ORDER BY
c.column_id
).getclobval(), ',')
FROM
table1 c
WHERE
c.owner = t.owner
AND c.table_name = t.table_name
)
INTO v_columns
FROM
all_tables t
WHERE
t.table_name = 'TABLE_NAME';
v_ident := 'INSERT INTO TABLE_NAME ('
|| v_columns
|| ') EXEC My_Procedure(0,0,0,''tableName'',null,v_COLUMNS)';
dbms_output.put_line(v_ident);
EXECUTE IMMEDIATE ( v_ident, 'v_JOB_HEADER_ID INT OUT,v_COLUMNS VARCHAR(30000) OUT', v_job_header_id, v_columns );
END;
In this stored procedure i am taking the table columns name and inserting the values according to the columns.
I am getting the error on the execute immediate line. as the declaration of the type of this expression is incomplete or malformed.

I want to write a procedure with input parameter as single or multiple values and return a ref cursor as per the input

I want to implement as below :
CREATE OR REPLACE PROCEDURE INPUT_XML (v_sne_id varchar2(10) -- input can be single or multiple values,
v_card_name varchar2(10) DEFAULT NULL,
v_port_no varchar2(10) DEFAULT NULL,
v_refcur OUT SYS_REFCURSOR)
AS
BEGIN
IF (card_name is null and port_no is null )
then
open v_refcur for
select * from table where sne_id in (all the input sneId(s) );
end if;
END INPUT_XML:
You may create and use a User-defined collection TYPE with TABLE function.
Type
CREATE OR REPLACE TYPE sne_id_type IS TABLE OF varchar2(10);
Procedure
CREATE OR REPLACE PROCEDURE input_xml (
v_sne_id sne_id_type, --use the parameter of the collection type
v_card_name VARCHAR2 DEFAULT NULL,
v_port_no VARCHAR2 DEFAULT NULL,
v_refcur OUT SYS_REFCURSOR
) AS
BEGIN
IF ( v_card_name IS NULL AND v_port_no IS NULL ) THEN
OPEN v_refcur FOR SELECT *
FROM tablename
WHERE sne_id IN ( SELECT column_value
FROM TABLE ( v_sne_id )
);
END IF;
END input_xml;
/
To pass multiple values while executing, you may do
BEGIN
INPUT_XML(sne_id_type('ID1','ID2','ID3'), 'CARD', null,null);
END;
/

ORA-01002: fetch out of sequence

I created a procedure in oracle database that returns data in a ref-cursor, and I want it to return the rowcount of this cursor also as an output variable. After testing, the P_count variable is filled correctly, but when I tried to open the cursor an 'ORA-01002: fetch out of sequence' error fired. I have read before about it and I found that the problem is because I am using a fetch statement in my code. But till now I did not discover how to resolve it. Any helps are appreciated, thank you. Below is my Procedure:
PROCEDURE IS_CLIENT_LOGGED_IN (
P_CLIENT_NUM Varchar2,
P_CURSOR out SYS_REFCURSOR ,
P_COUNT OUT NUMBER,
P_ERROR out Varchar2
) AS
cur_rec Varchar2(1024);
BEGIN
BEGIN
Open P_CURSOR FOR
SELECT ID
FROM tbl_registration
WHERE tbl_client_id = P_CLIENT_NUM
AND tbl_logout_date is null;
LOOP
FETCH P_CURSOR INTO cur_rec;
EXIT WHEN P_CURSOR%notfound;
P_COUNT := P_CURSOR%rowcount;--will return row number beginning with 1
END LOOP;
EXCEPTION WHEN OTHERS THEN
P_ERROR := 'Unable to select Data from tbl_registration' ||SQLERRM;
END;
END IS_CLIENT_LOGGED_IN;
Based on your comment the procedure should be like this:
PROCEDURE IS_CLIENT_LOGGED_IN (
P_CLIENT_NUM Varchar2,
P_CURSOR out SYS_REFCURSOR ,
P_COUNT OUT NUMBER,
P_ERROR out Varchar2
) AS
cur_rec Varchar2(1024);
BEGIN
Open P_CURSOR FOR
SELECT ID
FROM tbl_registration
WHERE tbl_client_id = P_CLIENT_NUM
AND tbl_logout_date is null;
LOOP
FETCH P_CURSOR INTO cur_rec;
EXIT WHEN P_CURSOR%notfound;
P_COUNT := P_CURSOR%rowcount;--will return row number beginning with 1
END LOOP;
CLOSE P_CURSOR;
Open P_CURSOR FOR
SELECT ID
FROM tbl_registration
WHERE tbl_client_id = P_CLIENT_NUM
AND tbl_logout_date is null;
EXCEPTION WHEN OTHERS THEN
P_ERROR := 'Unable to select Data from tbl_registration' ||SQLERRM;
END IS_CLIENT_LOGGED_IN;
Not very efficient, but that's what you asked for.
Anyway, I don't see any reason to increment P_COUNT one-by-one.
Make
SELECT COUNT(*) INTO P_COUNT
FROM tbl_registration
WHERE tbl_client_id = P_CLIENT_NUM
AND tbl_logout_date is null;
Open P_CURSOR FOR
SELECT ID
FROM tbl_registration
WHERE tbl_client_id = P_CLIENT_NUM
AND tbl_logout_date is null;
to get the same.

Can't retrieve data using dynamic SQL from the function that returns the table

My types:
TYPE T_rowBalanceListForClient IS RECORD
(
RowCode Asset.RowCode%TYPE,
RowName Asset.RowName%TYPE
);
TYPE T_tableBalanceListForClient IS TABLE OF T_rowBalanceListForClient;
My function:
FUNCTION F_BalanceListForClient
(
p_ClientId Client.ClientId%TYPE
)
RETURN T_tableBalanceListForClient PIPELINED
AS
CURSOR CUR_TABLE IS
SELECT
RowCode,
RowName
FROM Asset;
BEGIN
FOR CUR_REC IN CUR_TABLE LOOP
PIPE ROW(CUR_REC);
END LOOP;
END;
Part of my stored procedure:
sql_statement := ' SELECT * FROM TABLE(:1)';
OPEN c_Result FOR sql_statement USING F_BalanceListForClient(11);
While building the package I reseive the Oracle error:
PLS-00457: expressions have to be of SQL types
In the common stored procedures calls like this are built and operate well (not dynamics):
PROCEDURE GET_BALANCE_STANDARD_LIST
(
c_Result OUT SYS_REFCURSOR,
p_ClientId Client.ClientId%TYPE DEFAULT NULL
)
AS
BEGIN
OPEN c_Result FOR
SELECT RowName FROM TABLE(F_BalanceListForClient(p_ClientId));
END;
Appreciate any help.
Thanks.
CREATE OR REPLACE TYPE T_rowBalanceListForClient IS OBJECT
(
RowCode NUMBER,
RowName VARCHAR2(200)
);
CREATE OR REPLACE TYPE T_tableBalanceListForClient AS TABLE OF T_rowBalanceListForClient;
/
CREATE OR REPLACE FUNCTION F_BalanceListForClient
(
p_ClientId NUMBER
)
RETURN T_tableBalanceListForClient PIPELINED
AS
CURSOR CUR_TABLE IS
SELECT
RowCode,
RowName
FROM Assets
; --put a filter of the p_clientId
BEGIN
FOR CUR_REC IN CUR_TABLE
LOOP
pipe row (T_rowBalanceListForClient (CUR_REC.RowCode, CUR_REC.RowName));
END LOOP;
RETURN;
END;
/
CREATE OR REPLACE PROCEDURE GET_BALANCE_STANDARD_LIST
(
c_Result OUT SYS_REFCURSOR,
p_ClientId NUMBER DEFAULT NULL
)
AS
sql_statement varchar2(200);
BEGIN
sql_statement := ' SELECT * FROM TABLE(F_BalanceListForClient(:1))';
OPEN c_Result FOR sql_statement USING p_ClientId;
END;
/
BEGIN
GET_BALANCE_STANDARD_LIST(:cur ,11);
END;
/

Modify multiple oracle triggers

I have a task that involves updating many triggers which are exactly the same query but applied to several different tables. Is there a way to update all these TRIGGERS using a FOR or similar statement? Actually what I need to do is modify the WHEN clause for all this triggers.
you can use dbms_metadat for this.
for example:
declare
type arr_tab is table of varchar2(30);
v_arr arr_tab;
v_trig clob;
begin
dbms_metadata.set_transform_param( DBMS_METADATA.SESSION_TRANSFORM,
'SQLTERMINATOR', FALSE );
v_arr := arr_tab('TEST_TRIG', 'TEST2_TRIG'); -- change these triggers.
for idx in 1..v_arr.count
loop
v_trig := dbms_metadata.get_ddl('TRIGGER',v_arr(idx), user);
execute immediate regexp_replace(regexp_replace(v_trig, 'ALTER TRIGGER.*', ''), 'WHEN ([^\)]*\))', 'WHEN (1=1)', 1, 1, 'mi');
end loop;
end;
/
the 'WHEN ([^\)]*\))', 'WHEN (1=1)' part replaces the WHEN clause with (in my case) WHEN (1=1).
You can use dba_triggers to extract the text of the trigger into CREATE or replace statements. But due to some of the columns being LONG datatype you will have trouble extracting them as VARCHAR2. This can be resolved by using Tom Kytes package which is lost somewhere on the oracle site. I include my own version which you may have to modify to meet your needs.
Run the select, insert your when clause and then run the create or replace statements.
This won't work due to the trigger_body being a long datatype
select 'CREATE OR REPLACE TRIGGER '|| description
||trigger_body
from dba_triggers
where owner = 'Your schema'
but this should work if your triggers are not more than 4000 characters
select 'CREATE OR REPLACE TRIGGER '|| description
|| ADMIN.LONG_HELP.SUBSTR_OF('select trigger_body from dba_triggers where trigger_name = :0',
1,4000,'0',dt.trigger_name)
from dba_triggers dt
where owner = 'YourSchema';
CREATE OR REPLACE PACKAGE ADMIN.LONG_HELP
/******************************************************************************
NAME: LONG_HELP
PURPOSE: Read fields of type long. (commonly found in data dictionary)
REVISIONS:
Ver Date Author Description
--------- ---------- --------------- ------------------------------------
1.0 10/27/2011 1. Created this package. based on Tom Kyte's column here
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:839298816582
note that it only retrieves the first 4000 characters of any LONG column
USAGE in a WHERE
INSTR(
ADMIN.LONG_HELP.SUBSTR_OF('SELECT text from all_views where view_name =:o ',
1,4000,'o',m2.obj_name),m1.FK_ID) > 0
******************************************************************************/
--AUTHID CURRENT_USER
--removed to get around ORA-29470: Effective userid or roles are not the same as when cursor was parsed
--restrict usage to admin schema for Oracle 11g
AS
FUNCTION substr_of (p_query IN VARCHAR2,
p_from IN NUMBER,
p_for IN NUMBER,
p_name1 IN VARCHAR2 DEFAULT NULL ,
p_bind1 IN VARCHAR2 DEFAULT NULL ,
p_name2 IN VARCHAR2 DEFAULT NULL ,
p_bind2 IN VARCHAR2 DEFAULT NULL ,
p_name3 IN VARCHAR2 DEFAULT NULL ,
p_bind3 IN VARCHAR2 DEFAULT NULL ,
p_name4 IN VARCHAR2 DEFAULT NULL ,
p_bind4 IN VARCHAR2 DEFAULT NULL )
RETURN VARCHAR2;
END LONG_HELP;
/
CREATE OR REPLACE PACKAGE BODY ADMIN.LONG_HELP
AS
g_cursor NUMBER := DBMS_SQL.open_cursor;
g_query VARCHAR2 (32765);
PROCEDURE bind_variable (p_name IN VARCHAR2, p_value IN VARCHAR2)
IS
BEGIN
IF (p_name IS NOT NULL)
THEN
DBMS_SQL.bind_variable (g_cursor, p_name, p_value);
END IF;
END BIND_VARIABLE;
FUNCTION substr_of (p_query IN VARCHAR2,
p_from IN NUMBER,
p_for IN NUMBER,
p_name1 IN VARCHAR2 DEFAULT NULL ,
p_bind1 IN VARCHAR2 DEFAULT NULL ,
p_name2 IN VARCHAR2 DEFAULT NULL ,
p_bind2 IN VARCHAR2 DEFAULT NULL ,
p_name3 IN VARCHAR2 DEFAULT NULL ,
p_bind3 IN VARCHAR2 DEFAULT NULL ,
p_name4 IN VARCHAR2 DEFAULT NULL ,
p_bind4 IN VARCHAR2 DEFAULT NULL )
RETURN VARCHAR2
AS
/******************************************************************************
NAME: LONG_HELP.SUBSTR_OF
PURPOSE: CONVERT long data fields into VARCHAR2
WHOSE DATA IS CHANGED: none
WHAT USES THIS:
WHERE ARE THE RESOURCES NEEDED:
******************************************************************************/
l_buffer VARCHAR2 (4000);
l_buffer_len NUMBER;
BEGIN
IF (NVL (p_from, 0) <= 0)
THEN
raise_application_error (-20002,
'From must be >= 1 (positive numbers)');
END IF;
IF (NVL (p_for, 0) NOT BETWEEN 1 AND 4000)
THEN
raise_application_error (-20003, 'For must be between 1 and 4000');
END IF;
IF (p_query <> g_query OR g_query IS NULL)
THEN
IF (UPPER (TRIM (NVL (p_query, 'x'))) NOT LIKE 'SELECT%')
THEN
raise_application_error (-20001, 'This must be a select only');
END IF;
DBMS_SQL.parse (g_cursor, p_query, DBMS_SQL.native);
g_query := p_query;
END IF;
bind_variable (p_name1, p_bind1);
bind_variable (p_name2, p_bind2);
bind_variable (p_name3, p_bind3);
bind_variable (p_name4, p_bind4);
DBMS_SQL.define_column_long (g_cursor, 1);
IF (DBMS_SQL.execute_and_fetch (g_cursor) > 0)
THEN
DBMS_SQL.column_value_long (g_cursor,
1,
p_for,
p_from - 1,
l_buffer,
l_buffer_len);
END IF;
RETURN l_buffer;
END substr_of;
END LONG_HELP;
/

Resources