I have a procedure that takes some input variables with these names:
KEYWORD1 IN VARCHAR2,
KEYWORD1_VAL IN VARCHAR2,
KEYWORD2 IN VARCHAR2,
KEYWORD2_VAL IN VARCHAR2,
KEYWORD3 IN VARCHAR2,
KEYWORD3_VAL IN VARCHAR2,
KEYWORD4 IN VARCHAR2,
KEYWORD4_VAL IN VARCHAR2,
KEYWORD5 IN VARCHAR2,
KEYWORD5_VAL IN VARCHAR2,
KEYWORD6 IN VARCHAR2,
KEYWORD6_VAL IN VARCHAR2,
KEYWORD7 IN VARCHAR2,
KEYWORD7_VAL IN VARCHAR2,
KEYWORD8 IN VARCHAR2,
KEYWORD8_VAL IN VARCHAR2,
KEYWORD9 IN VARCHAR2,
KEYWORD9_VAL IN VARCHAR2,
KEYWORD10 IN VARCHAR2,
KEYWORD10_VAL IN VARCHAR2
I want to loop through 1-10 and do something like this:
FOR X IN 1..10
LOOP
IF KEYWORDX = 'CLI_RID' THEN
UPDATE FD_TABLE FD_CLI_RID = TO_NUMBER(KEYWORDX_VAL) WHERE FD_RID = RetVal;
END IF;
END LOOP;
Where X would be the loop variable. How could I do that in Oracle? DO I have to use Dynamic SQL? If so, how do I check the KEYWORD for 'CLI_RID'?
I don't think there's really anyway to do that in a loop. You could maybe do it with a case expression:
UPDATE FD_TABLE FD_CLI_RID = TO_NUMBER(CASE
WHEN KEYWORD1 = 'CLI_RID' THEN KEYWORD1_VAL
WHEN KEYWORD2 = 'CLI_RID' THEN KEYWORD2_VAL
WHEN KEYWORD3 = 'CLI_RID' THEN KEYWORD3_VAL
...
END)
WHERE FD_RID = RetVal
AND CASE
WHEN KEYWORD1 = 'CLI_RID' THEN KEYWORD1_VAL
WHEN KEYWORD2 = 'CLI_RID' THEN KEYWORD2_VAL
WHEN KEYWORD3 = 'CLI_RID' THEN KEYWORD3_VAL
...
END IS NOT NULL;
The case in the where clause stops it updating an existing value to null if there os no CLI_RID passed.
Related
I want to know if there exists something like Reflection API in PL/SQL or not.
I have a table like
create table my_table (
id number,
value1 number,
value2 number,
value3 number,
value4 number,
value5 number);
And I have a variable as
rec as my_table%rowtype
... fill rec
insert into my_table values rec;
is there any way I can populate rec field dynamically by its name.
I mean I know the index (in this case something between 1 and 5), so I want to set 'value'||index to something.
As in my real case the last index is much more than 5, using a set of if/elsif is not proper. By the way number of fields is increased in long term (for example value6, value7 ma be added next year and so on, so I wan to write some kind of code not to be changed on every new column).
You can access variables in a program using dynamic SQL only if they are available globally. If you declare you record in the spec you can build utility functions that will use EXECUTE IMMEDIATE to build a small PL/SQL block to set the value. Here is a simple example of what you are looking for. Notice you can overload the set procedure to keep your datatypes intact.
CREATE TABLE my_table (
value1 NUMBER,
value2 VARCHAR2(100),
value3 DATE);
CREATE OR REPLACE PACKAGE pkg_my_table IS
my_table_rec my_table%ROWTYPE;
FUNCTION build_statement(i_record IN VARCHAR2,
i_field IN VARCHAR2) RETURN VARCHAR2;
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN VARCHAR2);
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN NUMBER);
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN DATE);
PROCEDURE insert_a_row;
END pkg_my_table;
/
CREATE OR REPLACE PACKAGE BODY pkg_my_table IS
FUNCTION build_statement(i_record IN VARCHAR2,
i_field IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN 'BEGIN ' || lower($$PLSQL_UNIT) || '.' || i_record || '.' || i_field || ' := :x; END;';
END build_statement;
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN VARCHAR2) IS
BEGIN
EXECUTE IMMEDIATE build_statement(i_record => i_record,
i_field => i_field)
USING i_value;
END set_value;
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN NUMBER) IS
BEGIN
EXECUTE IMMEDIATE build_statement(i_record => i_record,
i_field => i_field)
USING i_value;
END set_value;
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN DATE) IS
BEGIN
EXECUTE IMMEDIATE build_statement(i_record => i_record,
i_field => i_field)
USING i_value;
END set_value;
PROCEDURE insert_a_row IS
BEGIN
my_table_rec := NULL;
set_value(i_record => 'my_table_rec',
i_field => 'value1',
i_value => 42);
set_value(i_record => 'my_table_rec',
i_field => 'value2',
i_value => 'forty-two');
set_value(i_record => 'my_table_rec',
i_field => 'value3',
i_value => to_date('1/1/1942',
'mm/dd/yyyy'));
INSERT INTO my_table
VALUES my_table_rec;
END insert_a_row;
END pkg_my_table;
/
BEGIN
pkg_my_table.insert_a_row;
END;
/
SELECT *
FROM my_table;
-- 42 forty-two 1/1/1942
Beware globals: you need to reset them correctly before using them again or you might get data carried over from previous invocations. Setting an entire record type variable to NULL will reset all the underlying fields (handy).
You will also be prone to ORA-04068: existing state of packages has been discarded errors should you compile PL/SQL with globals where there are active sessions referencing your code. Generally this is not a problem, but it is a behavioral difference.
I'm new in oracle pl/sql. I've created new package procedure list then I wanted to realise each procedure in seperate block. Here is list of procedures that I wanted creat for now it's only one.
create or replace package listProcedures is
procedure bss_claim12
( o_claim_id out number,
o_error_code out varchar2,
o_error_msg out varchar2,
i_card_number varchar2,
i_phone_number varchar2,
i_product_id number,
i_summ_loan number,
client_code number,
mfo varchar2
);
Then I wanted to create it's body but it's giving following errors.
Compilation errors for PACKAGE BODY IBS.LISTPROCEDURES
Error: PLS-00103: Encountered the symbol "end-of-file" when expecting
one of the following:
create or replace package body ibs.listprocedures is
procedure bss_claim12
( o_claim_id out number,
o_error_code out varchar2,
o_error_msg out varchar2,
i_card_number varchar2,
i_phone_number varchar2,
i_product_id number,
i_summ_loan number,
client_code number,
mfo varchar2
) is
begin
dbms_output.put_line(o_claim_id);
dbms_output.put_line(o_error_msg);
dbms_output.put_line(client_code);
end bss_claim12;
What should i do in body of this procedure to make it work well.
You should end both specification and body parts of the package :
SQL> create or replace package listProcedures is
procedure bss_claim12
( o_claim_id out number,
o_error_code out varchar2,
o_error_msg out varchar2,
i_card_number varchar2,
i_phone_number varchar2,
i_product_id number,
i_summ_loan number,
client_code number,
mfo varchar2
);
end listProcedures;
/
SQL> create or replace package body listProcedures is
procedure bss_claim12
( o_claim_id out number,
o_error_code out varchar2,
o_error_msg out varchar2,
i_card_number varchar2,
i_phone_number varchar2,
i_product_id number,
i_summ_loan number,
client_code number,
mfo varchar2
) is
begin
dbms_output.put_line(o_claim_id);
dbms_output.put_line(o_error_msg);
dbms_output.put_line(client_code);
end bss_claim12;
end listProcedures;
/
I have this function :
CREATE OR REPLACE FUNCTION checkLiveSoccerOdd (p_FIXID VARCHAR2,
p_TYPE VARCHAR2,
p_RES VARCHAR2)
RETURN NUMBER
IS
odd NUMBER;
BEGIN
SELECT O.Odd
INTO odd
FROM LIVE M, ODDS O
WHERE M.FIXID = O.FIXID(+)
AND M.FIXID = p_FIXID
AND O.TYPE = p_TYPE
AND O.RES = p_RES;
RETURN odd;
END;
Now i need to get more columns in query, for example:
Select M.*, O.*
I tried with cursor but I don't get results.
Can anyone help me with this?
Try this:
CREATE OR REPLACE FUNCTION checkLiveSoccerOdd (p_FIXID VARCHAR2,
p_TYPE VARCHAR2,
p_RES VARCHAR2)
RETURN SYS_REFCURSOR
IS
COL SYS_REFCURSOR;
BEGIN
OPEN COL FOR
SELECT M.*,O.*
FROM LIVE M, ODDS O
WHERE M.FIXID = O.FIXID(+)
AND M.FIXID = p_FIXID
AND O.TYPE = p_TYPE
AND O.RES = p_RES;
RETURN COL;
END;
Stored procedure is not returning the value that I am expecting. I did not know what is the problem with the procedure.
Here is the procedure:
CREATE OR REPLACE procedure PRC_CUSTOMER_WITH_LOGIN
(p_name_out out varchar2,
p_count out int,
p_all_records out SYS_REFCURSOR,
p_mode in varchar2,
p_id in varchar2,
p_name_in in varchar2,
p_contact_no in varchar2,
p_email in varchar2,
p_address in varchar2)
IS
BEGIN
IF p_mode='q'
THEN
select NAME into p_name_out from customer where id='1';
ELSIF p_mode='i'
THEN
INSERT into customer(id,name,contactNo,email,address)
Values(p_id, p_name_in, p_contact_no , p_email , p_address);
ELSIF p_mode='u'
THEN
UPDATE customer set name=p_name_in, contactNo=p_contact_no, email=p_email, address=p_address
where id=p_id;
ELSIF p_mode='d'
THEN
DELETE from customer where id=p_id;
ELSIF p_mode='a'
THEN
OPEN p_all_records FOR
select * from customer;
ELSIF p_mode='l'
THEN
SELECT COUNT(*) into p_count from customer WHERE name=p_name_in AND id=p_id;
END IF;
END;
/
This is the procedure all other conditions are working fine but the last condition is not working correctly this condition return 0 all the time whether I enter the correct id and name or wrong.
Here I am calling this procedure
cs = (OracleCallableStatement) con.prepareCall("{call TESTDB.PRC_CUSTOMER_WITH_LOGIN(?,?,?,?,?,?,null,null,null)}");
cs.registerOutParameter(1, OracleTypes.VARCHAR);
cs.registerOutParameter(2, OracleTypes.INTEGER);
cs.registerOutParameter(3, OracleTypes.CURSOR);
cs.setString(4, "l");
cs.setString(5, password);
cs.setString(6, name);
cs.executeQuery();
chk=cs.getInt(2);
System.out.println(chk);
Can someone tell me what the mistake is that I'm making here? I shall be thankful .... :)
Try to use UPPER both side so if any case sensitive names are there then it will nullify it.
SELECT COUNT(*) into p_count from customer WHERE upper(name)=upper(p_name_in) AND id=p_id;
Maybe you are wrong when you set id with the password value?
1-> p_name_out out varchar2,
2-> p_count out int,
3-> p_all_records out SYS_REFCURSOR,
4-> p_mode in varchar2,
5-> p_id in varchar2, --- 5 is id, not password ??!?
6-> p_name_in in varchar2,
p_contact_no in varchar2,
p_email in varchar2,
p_address in varchar2
cs = (OracleCallableStatement) con.prepareCall(
"{call TESTDB.PRC_CUSTOMER_WITH_LOGIN(?,?,?,?,?,?,null,null,null)}");
cs.registerOutParameter(1, OracleTypes.VARCHAR);
cs.registerOutParameter(2, OracleTypes.INTEGER);
cs.registerOutParameter(3, OracleTypes.CURSOR);
cs.setString(4, "l");
cs.setString(5, password);
cs.setString(6, name);
Another possibility is your id/password is stored as encrypted thing?
CREATE or REPLACE PROCEDURE SP_INSERT_OVERSEAS_COMPANY
(
COMPANY_CODE IN NUMBER,
COMPANY_NAME IN VARCHAR2,
STREET_ADDR IN VARCHAR2,
COMPANY_STATE IN VARCHAR2,
ZIP_CODE IN VARCHAR2,
COUNTRY IN VARCHAR2,
CONTACT_PERSON IN VARCHAR2,
CONTACT_NUMBER IN VARCHAR2
)
AS
BEGIN
IF sysdate between trunc(sysdate,'DD')+interval '9' hour and trunc(sysdate,'DD')+interval '17' hour
THEN
INSERT INTO Overseas_Company
VALUES
(COMPANY_NAME,COMPANY_NAME,STREET_ADDR,COMPANY_STATE,ZIP_CODE,COUNTRY,CONTACT_PERSON,CONTACT_NUMBER);
ELSE
dbms_output.put_line ('Process is outside of normally working hours');
END IF;
END SP_INSERT_OVERSEAS_COMPANY;
/
Should COMPANY_NAME,COMPANY_NAME,... be COMPANY_CODE,COMPANY_NAME,...? The parameter COMPANY_CODE is not used in the procedure. Are you getting numeric conversion errors?