Dynamic SQL accept table column as input in a procedure - oracle

Hey I am trying to write a procedure in which the user can insert which columns he would like to get as parameter input. As of right now when I run a test script I get this error:
error -1 message error in ct_cu_act_medrecon_pg.spm_search_patientmedrecs =>ORA-00933: SQL command not properly ended
The error is refering to the order by part in the select statement, and when I remove that I get an error saying:
error -1 message error in ct_cu_act_medrecon_pg.spm_search_patientmedrecs =>ORA-00904: "D"."P_INSERTDT_IN": invalid identifier
Here is the spec:
procedure spm_search_patientmedrecs (
p_columnsort_in in varchar2, --which is sort column
p_medmed_in in varchar2, --first column
p_planid_in in varchar2, --second column
p_detmed_in in varchar2, --third column
p_insertdt_in in varchar2, --fourth column
p_ascdesc_in in varchar2, --asc or desc in order by
p_return_cur_out out sys_refcursor,
p_err_code_out out number,
p_err_mesg_out out varchar2
);
Here is the procedure body:
procedure spm_search_patientmedrecs (
p_columnsort_in in varchar2,
p_medmed_in in varchar2,
p_planid_in in varchar2,
p_detmed_in in varchar2,
p_insertdt_in in varchar2,
p_ascdesc_in in varchar2,
p_return_cur_out out sys_refcursor,
p_err_code_out out number,
p_err_mesg_out out varchar2)
is
lv_sql varchar2(32767);
begin
lv_sql := '';
lv_sql := 'select h.p_medmed_in,
h.p_planid_in,
d.p_detmed_in,
d.p_insertdt_in
from membermedicalreconcilationhdr h,
membermedicalreconcilationdet d
where h.membermedreconciliationhdrskey =
d.membermedreconciliationhdrskey
order by h.p_columnsort_in p_ascdesc_in';
p_err_code_out := 0;
OPEN p_return_cur_out FOR lv_sql;
exception
when others then
p_err_code_out := -1;
p_err_mesg_out := 'error in ct_cu_act_medrecon_pg.spm_search_patientmedrecs =>'||sqlerrm;
end spm_search_patientmedrecs;
Here is my test script:
set serveroutput on
declare
type tempcursor is ref cursor;
v_cur_result tempcursor;
errcode number;
errmesg varchar2(1000);
begin
ct_cu_act_medrecon_pg.spm_search_patientmedrecs
('primarymemberplanid',
'membermedreconciliationhdrskey',
'primarymemberplanid',
'membermedreconciliationdetskey',
'inserteddt',
'ASC',
v_cur_result,
errcode,
errmesg
);
-- dbms_output.put_line(v_cur_result);
dbms_output.put_line('error '||errcode||' message '||errmesg);
end;
First off, I know how I'm handeling the error isnt the best way to do it but thats how the person asking me to do this wanted it.
Now I dont know if this is a possible thing to do in Oracle PL/SQL, but if it is I would greatly appreciate some help in pointing me in the right direction. If you guys need any more information feel free to ask and I will assist as best I can (Ive only been working with SQL and PL/SQL for 2 months). Thanks in advance.

Dynamic SQL means assembling strings which are executed as SQL statements. Your string hardcodes the parameter names, whereas what you actually need is the contents of the parameters.
Something like this:
lv_sql := 'select h.'||p_medmed_in||',
h.'||p_planid_in||',
d.'||p_detmed_in||',
d.'||p_insertdt_in||'
from membermedicalreconcilationhdr h,
membermedicalreconcilationdet d
where h.membermedreconciliationhdrskey =
d.membermedreconciliationhdrskey
order by h.'||p_columnsort_in||' '|| p_ascdesc_in;

Related

Error(12,5): PLS-00103: Encountered the symbol "LC_SQLERRM" when expecting one of the following: language

CREATE OR REPLACE PACKAGE APPS.XX_PROC_ADI_test AS
PROCEDURE XX_INS_DATA_ADI (
p_primary_uom_flag VARCHAR2,
p_list_line_type_code VARCHAR2,
p_price_break_type_code VARCHAR2,
p_arithmetic_operator VARCHAR2,
p_operand NUMBER,
p_start_date_active DATE,
p_end_date_active DATE,
p_product_precedence NUMBER
);
END;
SET VERIFY OFF
WHENEVER SQLERROR EXIT FAILURE ROLLBACK;
CREATE OR REPLACE PACKAGE APPS.XX_PROC_ADI_test AS
PROCEDURE XX_INS_DATA_ADI (
p_primary_uom_flag VARCHAR2,
p_list_line_type_code VARCHAR2,
p_price_break_type_code VARCHAR2,
p_arithmetic_operator VARCHAR2,
p_operand NUMBER,
p_start_date_active DATE,
p_end_date_active DATE,
p_product_precedence NUMBER
)IS
lc_sqlerrm VARCHAR2(2000);
lc_error_msg VARCHAR2 (2000);
l_responsibility_id NUMBER := apps.fnd_global.resp_id;
l_resp_application_id NUMBER := apps.fnd_global.resp_appl_id;
l_org_id NUMBER := apps.fnd_global.org_id;
l_user_id NUMBER := apps.fnd_global.user_id;
BEGIN
INSERT INTO QP_LIST_LINES(
primary_uom_flag,
list_line_type_code,
price_break_type_code,
arithmetic_operator,
operand,
start_date_active,
end_date_active,
product_precedence
)
VALUES (
p_primary_uom_flag,
p_list_line_type_code,
p_price_break_type_code,
p_arithmetic_operator,
p_operand,
p_start_date_active,
p_end_date_active,
p_product_precedence
);
COMMIT;
EXCEPTION WHEN OTHERS THEN
lc_sqlerrm := SUBSTR(SQLERRM,1,1999);
raise_application_error (-20001, 'OTHER_EXCEPTION - MSG | ' || lc_sqlerrm);
END;
END XX_INS_DATA_ADI;
END;
If you're going to use this (and your tool supports it), use it at the beginning:
SET VERIFY OFF
WHENEVER SQLERROR EXIT FAILURE ROLLBACK;
Then create
package specification first
package body next
create or replace package xx_proc_adi_test as
procedure xx_ins_data_adi(...);
end xx_proc_adi_test;
/
create or replace package BODY xx_proc_adi_Test as
procedure xx_ins_data_adi(...) is
...
begin
...
exception
...
end xx_ins_data_adi;
end xx_proc_adi_test;
/

Add exception in stored procedure

I want to handle exception using oracle as I haven't done it before. below is my stored procedure.
create or replace
PROCEDURE GET_VALID_LATLONG
(
P_XYCORDINATE IN VARCHAR2,
P_SAPID IN VARCHAR2,
OUTR4GSTATENAME OUT SYS_REFCURSOR
)
AS
v_counter number:=0;
BEGIN
DBMS_OUTPUT.ENABLE;
OPEN OUTR4GSTATENAME FOR
SELECT DISTINCT(R4GSTATECODE),R4GSTATENAME
FROM R4G_LB.R4GSTATEBOUNDARY_EVW
WHERE SDE.ST_INTERSECTS(SDE.ST_GEOMETRY('POINT
('||P_XYCORDINATE||')', 3),SHAPE) = 1;
END GET_VALID_LATLONG;
how to handle the exception?
UPDATE
I added like this, is it fine when error occurs ??
create or replace
PROCEDURE GET_VALID_LATLONG
(
P_XYCORDINATE IN VARCHAR2,
P_SAPID IN VARCHAR2,
OUTR4GSTATENAME OUT SYS_REFCURSOR
)
AS
v_counter number:=0;
BEGIN
DBMS_OUTPUT.ENABLE;
OPEN OUTR4GSTATENAME FOR
SELECT DISTINCT(R4GSTATECODE),R4GSTATENAME
FROM R4G_LB.R4GSTATEBOUNDARY_EVW
WHERE SDE.ST_INTERSECTS(SDE.ST_GEOMETRY('POINT
('||P_XYCORDINATE||')', 3),SHAPE) = 1;
EXCEPTION
WHEN OTHERS THEN
NULL;
END GET_VALID_LATLONG;
A list of pre-defined exceptions can be found in the Oracle docs, for example here.
https://docs.oracle.com/cd/A97630_01/appdev.920/a96624/07_errs.htm
You can use this list of exception names in your exception clause, for example
WHEN TOO_MANY_ROWS THEN
NULL; -- whatever you wish to do here.

Error PLS-00103 when create package with Oracle

I'm trying create package with oracle, although I have read many examples in docs oracle and built code same this tutorial but I still error this.
The following code:
create table manage_emplyee
(
f_name varchar(20),
l_name varchar(20)
);
// Specification
create or replace package fn2
as
procedure manage_emplyee(v_fname in VARCHAR2, v_lname in VARCHAR2);
procedure manage_emplyee_delete(v_fname in VARCHAR2);
end;
/
create or replace package body fn2
as
--Procedure Implementation
procedure manage_emplyee(v_fname in VARCHAR2, v_lname in VARCHAR2)
is
begin
insert into manage_emplyee VALUES (v_lname, v_lname);
end manage_emplyee;
// body
procedure manage_emplyee_delete (v_fname in VARCHAR2)
is
begin
delete manage_emplyee where v_fname = v_fname;
end manage_emplyee_delete;
end fn2;
/
Error
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
begin end function pragma procedure
Please help me fix it, thanks so much !
There are many things incorrect, so here is a correct version.
Run the table script first -
create table manage_emplyee
(
f_name varchar(20),
l_name varchar(20)
);
Run the Spec script after that
create or replace package fn2
as
procedure manage_emplyee(v_fname VARCHAR2,
v_lname VARCHAR2);
procedure manage_emplyee_delete(v_fname VARCHAR2);
end;
/
Run the body script after that
create or replace package body fn2
as
procedure manage_emplyee(v_fname VARCHAR2, v_lname VARCHAR2)
is
begin
insert into manage_emplyee VALUES (v_lname, v_lname);
end ;
procedure manage_emplyee_delete (v_fname VARCHAR2)
is
begin
delete from manage_emplyee where f_name = v_fname;
end ;
end;
/
The syntax for delete from table_name was incorrect.
I am sure, you want to match f_name from table with v_fname from the input variable to delete the data. Earlier you were matching v_fname with v_fname in your code, which will always be true (except for when its passed NULL) and you would end up loosing all your test data
*NOTE -
Adding IN explicitly is not required, the default type is IN for parameters in PLSQL procedures

Stored Procedure Related

I am creating a stored procedure in oracle that is selecting records from login table -
create or replace procedure login_info
(username IN varchar2, password IN varchar2, result OUT number)
as
begin
select * from login;
end;
Whenever I am going to compile this it shows an error:
PLS-00428: an INTO clause is expected in this SELECT statement
What does this mean? I do not understand this.
You have to store the result of your SELECT statement into a variable, you can use sys_refcursor to display the result.
create or replace procedure login_info
(username IN varchar2, password IN varchar2, result OUT number, result_out OUT SYS_REFCURSOR)
as
l_query varchar2(1000) := Null;
begin
l_query := 'select * from login';
open result_out
for l_query;
end;
above code will give you the output
PLS-00428: an INTO clause is expected in this SELECT statement
That means you need an INTO close when you issue bare SELECT from PL/SQL.
:D
More constructively: where do you think the result of your select would go in that code fragment?
create or replace procedure login_info
(username IN varchar2, password IN varchar2, result OUT number)
as
begin
select * from login;
end;
You have to retrieve it somehow in order to be processed by your PL/SQL code. Assuming you have several rows to collect, you should use BULK COLLECT INTO:
create or replace procedure login_info
(username IN varchar2, password IN varchar2, result OUT number)
as
type my_tbl_type IS TABLE OF login%ROWTYPE;
my_tbl my_tbl_type;
begin
select * BULK COLLECT INTO my_tbl from login;
-- do whatever you
-- need here
-- on `my_tbl`.
end;
As a final note, maybe are you looking for an explicit CURSOR instead? You should definitively take a look at PL/SQL 101: Working with Cursors. This is an interesting discussion both about SELECT ... INTO ... and CURSOR manipulation.

Pagination in Oracle/PLSQL error

Hey I am trying to add paging to my dynamic sql block in PLSQL but for some reason when I run the test script it errors out:
ORA-00932: inconsistent datatypes: expected - got -
Here is my procedure:
create or replace
procedure spm_search_patientmedrecs (
p_columnsort_in in varchar2,
p_column1_in in varchar2,
p_column2_in in varchar2,
p_column3_in in varchar2,
p_column4_in in varchar2,
p_ascdesc_in in varchar2,
p_return_cur_out out sys_refcursor
is
lv_sql varchar2(32767);
lv_startnum number:= 1;
lv_incrementby number:= 20;
begin
lv_sql := '';
lv_sql := 'select * from (
select /*+ first_rows(20) */
'||p_column1_in||',
'||p_column2_in||',
'||p_column3_in||',
'||p_column4_in||',
row_number() over
(order by '||p_columnsort_in||' '||p_ascdesc_in||') rn
from membermedicalreconcilationhdr h,
membermedicalreconcilationdet d
where h.membermedreconciliationhdrskey =
d.membermedreconciliationhdrskey)
where rn between :lv_startnum and :lv_incrementby
order by rn';
open p_return_cur_out for lv_sql;
end spm_search_patientmedrecs;
Here is my test script:
set serveroutput on
declare
type tempcursor is ref cursor;
v_cur_result tempcursor;
p_columnsort_in varchar2(50);
p_column1_in varchar2(50);
p_column2_in varchar2(50);
p_column3_in varchar2(50);
p_column4_in varchar2(50);
p_ascdesc_in varchar2(50);
begin
spm_search_patientmedrecs
('h.PRIMARYMEMBERPLANID',
'h.PRIMARYMEMBERPLANID',
'h.ASSIGNEDUSERID',
'd.MEMBERMEDRECONCILIATIONDETSKEY',
'd.GENERICNM',
'ASC',
v_cur_result
);
loop
fetch v_cur_result into
p_column1_in,p_column2_in,p_column3_in,p_column4_in;
dbms_output.put_line('column 1: '||p_column1_in||' column 2: '||p_column2_in||
' column 3: '||p_column3_in||' column 4: '||p_column4_in);
exit when v_cur_result%notfound;
end loop;
end;
The error I posted above doesnt make sense to me, but I've been looking for the cause for awhile. If anyone can point me in the right direction it would be much appreciated, thanks in advance.
A couple of issues jump out at me.
The query that you are using to return the cursor returns 5 columns (the 4 you pass in plus the computed rn) while your fetch fetches the data into only 4 variables. You would either need to modify your query to return only 4 columns or modify your test script to fetch the data into 5 variables.
In your procedure, you have bind variables in your SQL statement but you don't pass in any bind variables when you open the cursor. My guess is that you want something like this
Passing the bind variables with the USING clause
open p_return_cur_out
for lv_sql
using lv_startnum, lv_incrementby;
There may well be more errors-- if there are, it would be helpful to post the full stack trace including the line number of the error.
A couple of other things to be aware of.
Unless p_columnsort_in happens to specify a column that is unique, your paging code may well miss rows and/or show rows in multiple pages because the sort order isn't fully specified. If rows 20 and 21 have the same p_columnsort_in value, it would be perfectly legal to sort them one way on the first query and another way on the second query so row 20 might show up on the first and second page and row 21 might not show up anywhere.
If efficiency is a concern, using rownum will probably end up being more efficient than using the analytic function like this because the optimizer can generally do a better job of optimizing a rownum predicate.
create or replace
procedure spm_search_patientmedrecs (
p_columnsort_in in varchar2,
p_column1_in in varchar2,
p_column2_in in varchar2,
p_column3_in in varchar2,
p_column4_in in varchar2,
p_ascdesc_in in varchar2,
p_return_cur_out out sys_refcursor
is
lv_sql varchar2(32767);
lv_startnum number:= 1;
lv_incrementby number:= 20;
begin
lv_sql := 'select * from (
select /*+ first_rows(20) */
'||p_column1_in||',
'||p_column2_in||',
'||p_column3_in||',
'||p_column4_in||',
row_number() over
(order by '||p_columnsort_in||' '||p_ascdesc_in||') rn
from membermedicalreconcilationhdr h,
membermedicalreconcilationdet d
where h.membermedreconciliationhdrskey =
d.membermedreconciliationhdrskey)
where rn between :1 and :2
order by rn';
open p_return_cur_out for lv_sql using lv_startnum, lv_incrementby;
end spm_search_patientmedrecs;

Resources