ORA-01722: invalid number in execute immediate - sql

I am running the following script in SQL Developer but getting the below error -
ORA-01722: invalid number
ORA-06512: at line 85
The data passed to this query is coming from a different table.
DATA BEING PASSED -
BAN - 945170744, ACTV_BILL_SEQ_NO- 12 , SUBSCRIBER_NO - 1234567891, DISCOUNT_CD - NULL, PRIOD_CVRG_ND_DATE - 04-JAN-20,
Note - Ban is defined as NUMBER(9) in both the tables.
SCRIPT -
SET SERVEROUTPUT ON
DECLARE
V_HIERARCHY_ID NUMBER(10);
V_NODE_CYCLE NUMBER(2);
V_BILL_CYCLE NUMBER(2);
V_DISCOUNT_CD CHAR(9);
V_EXP_DATE DATE;
V_COUNT NUMBER(3);
v_val_Done_by varchar2(25) ;
v_ban NUMBER(9);
v_comments varchar2(20);
v_success varchar2(10) :='SUCCESS';
v_yesnoind varchar2(1) :='Y';
v_comments_1 varchar2(30) :='DISCOUNT EXPIRED';
v_comments_2 varchar2(30) :='DISCOUNT NOT FOUND';
v_issue_Desc varchar2(50) :='NEW RECORD MISSING';
BEGIN
DBMS_OUTPUT.put_line ('BAN: '|| :1 || ' ACTV_BILL_SEQ_NO : ' || :2 || ' SUBSCRIBER: '|| :3 ||
'COLUMN_NAME : ' || :4|| ' COLUMN_DATA: '|| :5|| 'DIFF_DATA : ' || :6 || ' SOC: ' ||:7|| '
FEATURE_CODE: ' ||:8|| ' FTR_REVENUE_CODE: ' ||:9|| ' PRIOD_CVRG_ST_DATE: ' ||:10|| '
PRIOD_CVRG_ND_DATE: ' ||:11|| ' ACTV_REASON_CODE: ' ||:12|| 'BALANCE_IMPACT_CODE: '|| :13 || '
SOURCE_APPL_CODE : ' || :14 || ' DISCOUNT_CD: '|| :15 || ' BILL_MEDIA : ' || :16|| 'BILL_FORMAT : '
|| :17 || ' PRODUCT_TYPE: ' ||:18|| ' FTR_TYPE ' ||:19 || ' VAL_ID ' ||:20 );
v_ban :=:1;
V_DISCOUNT_CD :=:15;
V_EXP_DATE :=:11;
dbms_output.put_line(V_DISCOUNT_CD);
dbms_output.put_line(V_EXP_DATE);
select 'comments_'|| :20 into v_comments from dual;
select 'val_done_by_'|| :20 into v_val_Done_by from dual;
DBMS_OUTPUT.Put_line(v_val_Done_by);
DBMS_OUTPUT.Put_line(v_comments);
SELECT HIERARCHY_ID INTO V_HIERARCHY_ID FROM BILLING_ACCOUNT WHERE BAN =:1;
IF V_HIERARCHY_ID IS NULL
THEN
SELECT COUNT(*) INTO V_COUNT FROM BAN_DISCOUNT WHERE BAN =:1 AND TRIM(DISCOUNT_CODE) =
V_DISCOUNT_CD AND EXPIRATION_DATE < V_EXP_DATE;
IF V_COUNT >= 1
THEN
EXECUTE IMMEDIATE 'UPDATE BL_DIFF_CATEGORY SET VALIDATION_STS=:2,' || v_val_Done_by || ' = :3, '
|| v_comments || ' = :4 WHERE BAN = :1 AND DIFF_TYPE = :5'
using v_issue_Desc,v_comments_1,v_yesnoind,v_success,v_ban;
COMMIT;
ELSE
EXECUTE IMMEDIATE 'UPDATE BL_DIFF_CATEGORY SET VALIDATION_STS=:2,' || v_val_Done_by || ' = :3, '
|| v_comments || ' = :4 WHERE BAN = :1 AND DIFF_TYPE = :5'
using v_issue_Desc,v_comments_2,v_yesnoind,v_success,v_ban;
COMMIT;
END IF;
ELSE
-- NODE LEVEL DISCOUNT CHECK
SELECT COUNT(*) INTO V_COUNT FROM CH_OBJECT_ATTRIBUTES
WHERE
OBJ_ID IN ( SELECT ARC_FATHER_ID FROM CH_ARCS WHERE ARC_CHILD_ID = V_HIERARCHY_ID)
AND ATTR_NAME = 'Discount Plans'
AND ATTR_VALUE = V_DISCOUNT_CD
AND VALID_TO < V_EXP_DATE;
-- BAN LEVEL DISCOUNT CHECK
SELECT COUNT(*) INTO V_COUNT FROM CH_OBJECT_ATTRIBUTES
WHERE
OBJ_ID = V_HIERARCHY_ID
AND ATTR_NAME = 'Discount Plans'
AND ATTR_VALUE = V_DISCOUNT_CD
AND VALID_TO < V_EXP_DATE;
-- SUBSCRIBER LEVEL DISCOUNT CHECK
SELECT COUNT(*) INTO V_COUNT FROM CH_OBJECT_ATTRIBUTES
WHERE
OBJ_ID IN ( SELECT ARC_CHILD_ID FROM CH_ARCS WHERE ARC_FATHER_ID = V_HIERARCHY_ID)
AND ATTR_NAME = 'Discount Plans'
AND ATTR_VALUE = V_DISCOUNT_CD
AND VALID_TO < V_EXP_DATE;
IF V_COUNT >= 1
THEN
EXECUTE IMMEDIATE 'UPDATE BL_DIFF_CATEGORY SET VALIDATION_STS=:2,' || v_val_Done_by || ' = :3, '
|| v_comments || ' = :4 WHERE BAN = :1 AND DIFF_TYPE = :5'
using v_issue_Desc,v_comments_1,v_yesnoind,v_success,v_ban;
COMMIT;
ELSE
(I am facing the above error in this ELSE part in below line as it is going in this line 85)
EXECUTE IMMEDIATE ''UPDATE BL_DIFF_CATEGORY SET VALIDATION_STS=:2,'' || v_VAL_DONE_BY || '' =
:3, '' || v_comments || '' = :4 WHERE BAN = :1 AND DIFF_TYPE = :5''
using v_issue_Desc,v_comments_2,v_yesnoind,v_success,v_ban;
COMMIT;
END IF;
END IF;
END;

(I am facing the above error in this ELSE part in below line as it is going in this line 85)
EXECUTE IMMEDIATE ''UPDATE BL_DIFF_CATEGORY SET VALIDATION_STS=:2,'' || v_VAL_DONE_BY || '' = :3, '' || v_comments || '' = :4 WHERE BAN = :1 AND DIFF_TYPE = :5''
using v_issue_Desc,v_comments_2,v_yesnoind,v_success,v_ban;
There seems to be some discrepancy between orders of the placeholders in the string and the parameters in the USING clause. For instance BAN = :1 is the fourth placeholder but v_ban is the fifth variable passed to the EXECUTE IMMEDIATE statement, whilst the value actually assigned to BAN is v_success.
Perhaps you simply need to review the placeholders and re-order the parameters? If so, remember to do the same for the statement in the IF branch.
Incidentally, the names of the placeholders in the string don't matter, but if you're going to use numbers you might as well put them in numeric order.

DISCOUNT_CD - NULL <== Null is not a valid number -- you need a coalesce here
eg
SELECT COUNT(*) INTO V_COUNT FROM CH_OBJECT_ATTRIBUTES
WHERE
OBJ_ID IN ( SELECT ARC_CHILD_ID FROM CH_ARCS WHERE ARC_FATHER_ID = V_HIERARCHY_ID)
AND ATTR_NAME = 'Discount Plans'
AND ATTR_VALUE = COALESCE(V_DISCOUNT_CD,0)
AND VALID_TO < V_EXP_DATE;

Related

How can i turn this pl/sql into a procedure

I had to write this query for an assignement. So we have a database and we are pulling information from it, this is going to work with some back end c# eventually. Is there anything i can do , knowing im going to reuse this, in order to make it better and more adaptable when the day comes when i have to connect it all.
set serveroutput on
DECLARE
LV_DATE HVK_RESERVATION.RESERVATION_START_DATE%TYPE;
LV_SERV VARCHAR(100);
CURSOR LCUR_RES IS
SELECT *
FROM HVK_RESERVATION R
INNER JOIN HVK_PET_RESERVATION PR
ON R.RESERVATION_NUMBER = PR.RES_RESERVATION_NUMBER
INNER JOIN HVK_PET P
ON P.PET_NUMBER = PR.PET_PET_NUMBER
INNER JOIN HVK_OWNER OW
ON OW.OWNER_NUMBER = P.OWN_OWNER_NUMBER
WHERE R.RESERVATION_START_DATE < LV_DATE
AND R.RESERVATION_END_DATE > LV_DATE;
CURSOR LCUR_SERVICE(PET_RES_NUM NUMBER) IS
SELECT *
FROM HVK_SERVICE S
INNER JOIN HVK_PET_RESERVATION_SERVICE PRS
ON PRS.SERV_SERVICE_NUMBER = S.SERVICE_NUMBER
AND PRS.PR_PET_RES_NUMBER = PET_RES_NUM;
BEGIN
LV_DATE := TO_DATE('&logdate', 'yy-mm-dd');
DBMS_OUTPUT.PUT_LINE('Kennel log for ' || '' || LV_DATE);
DBMS_OUTPUT.PUT_LINE('-------------------------------');
FOR I IN LCUR_RES LOOP
DBMS_OUTPUT.PUT_LINE('Run:' || '' || I.RUN_RUN_NUMBER || ' ' ||
'Pet: ' || '' || I.PET_NAME || ' ' ||
I.OWNER_LAST_NAME || ' Pet Reservation: ' || '' ||
I.PET_RES_NUMBER);
DBMS_OUTPUT.PUT_LINE('Reservation start/end ' || ' ' ||
I.RESERVATION_START_DATE || ' ' ||
I.RESERVATION_END_DATE);
DBMS_OUTPUT.PUT('Services : ');
FOR X IN LCUR_SERVICE(I.PET_RES_NUMBER) LOOP
DBMS_OUTPUT.PUT(X.SERVICE_DESCRIPTION || ' ');
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
FOR LREC_LOG IN (SELECT *
FROM HVK_KENNEL_LOG KL
WHERE KL.PR_PET_RES_NUMBER = I.PET_RES_NUMBER
) LOOP
DBMS_OUTPUT.PUT_LINE('Notes: ' || '' ||
LREC_LOG.KENNEL_LOG_SEQUENCE_NUMBER || ' ' ||
'Log Note: ' || '' || LREC_LOG.KENNEL_LOG_NOTES);
END LOOP;
DBMS_OUTPUT.PUT_LINE(' ');
END LOOP;
END;
It it supposed to output the run number , reservation number , pet name , and any relate notes.
you can replace DECLARE with CREATE OR REPLACE PROCEDURE my_proc(in_logdate in date) IS.
in that case my_proc will be the name of your procedure.
you should also use a parameter instead of &logdate
so e.g. parameter name in_logdate of type date
...
LV_DATE := in_logdate;
...

continuing loops a thing in oracle

I am carrying out another exercise to learn various things about Oracle SQL's syntax today's lesson I've chosen are loops. Please see below code where I am trying to have two fields (temp variables) having values being decreased until it's less than zero depending on which of the variables hit's zero depends on what text I would like to output into the script output. Hopefully it makes sense. If I have made any faux pas's please do shout at me.
DECLARE
"Character" VARCHAR2(255);
"Enemy" VARCHAR2(255);
"Character_Health" NUMBER;
"Enemy_Health" NUMBER;
"Character_Attack" NUMBER;
"Enemy_Attack" NUMBER;
BEGIN -- Generates Base Stats
SELECT 'Hero' INTO "Character" FROM dual;
SELECT 'Villain' INTO "Enemy" FROM dual;
SELECT 100 INTO "Character_Health" FROM dual;
SELECT 25 INTO "Enemy_Health" FROM dual;
SELECT 10 INTO "Character_Attack" FROM dual;
SELECT 5 INTO "Enemy_Attack" FROM dual;
dbms_output.put_line ("Character" || ' (' || "Character_Health" || ') VS ' ||' '|| "Enemy" || ' (' || "Enemy_Health" || ')') ;
dbms_output.put_line ('');
dbms_output.put_line ('FIGHT!');
BEGIN -- Round 1
LOOP
dbms_output.put_line ('');
SELECT "Enemy_Health" - "Character_Attack" INTO "Enemy_Health" FROM dual; -- Hero hits Villain
dbms_output.put_line ("Character" || ' Hits ' || "Enemy" || ' for ' || "Character_Attack" ||' Damage' );
dbms_output.put_line ("Enemy" || ' Has ' || "Enemy_Health" || ' Health Remaining ');
CASE WHEN "Enemy_Health" < 0 THEN dbms_output.put_line ("Enemy" || 'Has Fainted' || "Character" || 'Wins!');
ELSE CONTINUE;
EXIT WHEN "Enemy_Health" < 0;
SELECT "Character_Health" - "Enemy_Attack" INTO "Character_Health" FROM dual; -- Villain hits Hero
dbms_output.put_line ('');
dbms_output.put_line ("Enemy" || ' Hits ' || "Character" || ' for ' || "Enemy_Attack" ||' Damage' );
dbms_output.put_line ("Character" || ' Has ' || "Character_Health" || ' Health Remaining ');
CASE WHEN "Character_Health" < 0 THEN dbms_output.put_line ("Character" || 'Has Fainted' || "Enemy" || 'Wins!');
ELSE CONTINUE;
EXIT WHEN "Character_Health" < 0;
END LOOP;
END;
END;
I found some errors
1. Syntax for case is:
CASE [ expression ]
WHEN condition_1 THEN result_1
WHEN condition_2 THEN result_2
...
WHEN condition_n THEN result_n
[ELSE result]
END CASE
Learn more:
- simple case statement
- searched case statement
CONTINUE stops processing loop and starts it from the begining, so your logic is corrupt - only Hero is attacking.
You need space after "Fainted"
It's better to use IF in this case:
IF "Character_Health" < 0
THEN
dbms_output.put_line ("Character" || 'Has Fainted. ' || "Enemy" || 'Wins!');
EXIT;
END IF;
It's not mistake, but you don't need select into from dual if you want to change value of variable.
Last but not least- i don't like how you use variables. "Character_Health" is similar to 'Character_Health' or '''Character_Health'''. Better use names like characterHealth or character_health.
My version would be something like that:
DECLARE
v_Character VARCHAR2(255) := 'Hero' ;
v_Enemy VARCHAR2(255) := 'Villain';
v_Character_Health NUMBER := 100;
v_Enemy_Health NUMBER := 25;
v_Character_Attack NUMBER := 10;
v_Enemy_Attack NUMBER := 5;
v_nl VARCHAR2(1) := chr(10);
BEGIN
dbms_output.put_line (v_Character || ' (' || v_Character_Health || ') VS ' ||' '|| v_Enemy || ' (' || v_Enemy_Health || ')' || v_nl) ;
dbms_output.put_line ('FIGHT!' || v_nl);
LOOP
v_Enemy_Health := v_Enemy_Health - v_Character_Attack;
dbms_output.put_line (v_Character || ' Hits ' || v_Enemy || ' for ' || v_Character_Attack ||' Damage' );
dbms_output.put_line (v_Enemy || ' Has ' || v_Enemy_Health || ' Health Remaining' || v_nl);
IF v_Enemy_Health < 0 THEN dbms_output.put_line (v_Enemy || 'Has Fainted. ' || v_Character || 'Wins!'); EXIT;
END IF;
v_Character_Health := v_Character_Health - v_Enemy_Attack;
dbms_output.put_line (v_Enemy || ' Hits ' || v_Character || ' for ' || v_Enemy_Attack || ' Damage' );
dbms_output.put_line (v_Character || ' Has ' || v_Character_Health || ' Health Remaining' || v_nl);
IF v_Character_Health < 0 THEN dbms_output.put_line (v_Character || 'Has Fainted. ' || v_Enemy || 'Wins!'); EXIT;
END IF;
END LOOP;
END;
/

Getting 'ORA00904: invalid identifier' on dynamic tables

I have a script that works with dynamic tables. When executing the below code segment, it gives me error ORA00904: invalid identifier.
IF Database_SYS.Column_Exist (service_tab_, ''KEY_VALUE'') THEN
UPDATE '|| service_tab_ || '
SET key_ref = new_key_ref_,
key_value = ''Test'',
rowversion = SYSDATE
WHERE ROWID = rec_.ROWID;
ELSE
UPDATE '|| service_tab_ || '
SET key_ref = new_key_ref_,
rowversion = SYSDATE
WHERE ROWID = rec_.ROWID;
END IF;
Would be better this one:
BEGIN
IF Database_SYS.Column_Exist (service_tab_, '''' || KEY_VALUE || '''') THEN
EXECUTE IMMEDIATE
'UPDATE ' || service_tab_ || '
SET key_ref = new_key_ref_,
key_value = :val,
rowversion = SYSDATE
WHERE ROWID = :rid'
USING 'TEST', rec_.ROWID;
ELSE
EXECUTE IMMEDIATE
'UPDATE ' || service_tab_ || '
SET key_ref = new_key_ref_,
rowversion = SYSDATE
WHERE ROWID = :rid'
USING rec_.ROWID;
END IF;
END;
I don't think you need '''' || KEY_VALUE || '''', using just Database_SYS.Column_Exist(service_tab_, KEY_VALUE) should be fine if you have properly coded the function.
Try something like this:
EXECUTE IMMEDIATE 'update' || service_tab_ || 'SET key_ref = ' ||new_key_ref_|| ' rowversion = SYSDATE WHERE ROWID = '|| rec_.ROWID;
LEt me know if you get further errors, we can resolve them together in comments.
BEGIN
IF Database_SYS.Column_Exist (service_tab_, '''' || KEY_VALUE || '''') -- 4x': StartString + Quote + ' + EndString doublepipe to concat Strings
THEN
EXECUTE IMMEDIATE -- If you want to Build dynamic SQL you have to throw it into "EXECUTE IMMEDIATE 'myQuery'"
'UPDATE ' || service_tab_ || '
SET key_ref = new_key_ref_,
key_value = ''TEST'',
rowversion = SYSDATE
WHERE ROWID = rec_.ROWID';
ELSE
EXECUTE IMMEDIATE
'UPDATE ' || service_tab_ || '
SET key_ref = new_key_ref_,
rowversion = SYSDATE
WHERE ROWID = rec_.ROWID';
END IF;
END;
Next time you should Build up your script step-by-step. A single Error can be handled better than having a bunch of invalid code..
If the only difference is in updating a column it would be more correct to apply the condition only to a part of the query
DECLARE
V_QUERY VARCHAR2(200);
BEGIN
--
V_QUERY := 'UPDATE '||service_tab_||
' SET key_ref = new_key_ref_,
rowversion = SYSDATE';
--
IF Database_SYS.Column_Exist (service_tab_, 'KEY_VALUE') THEN
V_QUERY := V_QUERY||', key_value = ''Test''';
END IF;
--
V_QUERY := V_QUERY||' WHERE ROWID = rec_.ROWID';
--
EXECUTE IMMEDIATE V_QUERY;
--
END;

PL/SQL - Create tables based on cursor using execute immediate?

I've written the following code that selects some student test data and using a cursor, inserts it into a table.
What id like to be able to do is create one table for each student and insert their relative data. This could be one row or multiple rows.
SET SERVEROUTPUT ON
CREATE OR REPLACE PROCEDURE run_student_scores
IS
CURSOR c_pass_fail_cursor
IS
SELECT students.firstname,
test_history.score,
test_id.test_name,
test_id.passing_grade
FROM students
INNER JOIN test_history
ON students.student_id = test_history.student_id
INNER JOIN test_id
ON test_id.test_id = test_history.test_id
WHERE test_history.start_time BETWEEN to_timestamp(sysdate) + INTERVAL '8' HOUR
AND to_timestamp(sysdate) + INTERVAL '21' HOUR;
v_name students.firstname%TYPE;
v_score test_history.score%TYPE;
v_test varchar2(40);
v_passing test_id.passing_grade%TYPE;
v_result varchar2(4);
BEGIN
EXECUTE IMMEDIATE ('create table student_tests_' || (to_char(sysdate, 'yyyymmdd')) || '(student_name VARCHAR2(20), test_name varchar2(40), test_score NUMBER(3), pass_rate NUMBER(3), pass_fail VARCHAR2(4))');
OPEN c_pass_fail_cursor;
LOOP
FETCH c_pass_fail_cursor INTO v_name, v_score, v_test, v_passing;
EXIT WHEN c_pass_fail_cursor%NOTFOUND;
If v_score < v_passing
THEN v_result := 'Fail';
DBMS_OUTPUT.PUT_LINE(v_name || ' ' || v_score || ' ' || v_test || ' ' || V_passing || ' ' || 'Result =' || v_result);
ELSE
v_result := 'Pass';
DBMS_OUTPUT.PUT_LINE(v_name || ' ' || v_score || ' ' || v_test || ' ' || V_passing || ' ' || 'Result =' || v_result);
END IF;
EXECUTE IMMEDIATE 'INSERT INTO student_tests_' || (to_char(sysdate, 'yyyymmdd')) || ' ' || ' values(:1, :2, :3, :4, :5)' using v_name, v_test, v_score, v_passing, v_result;
END LOOP;
CLOSE c_pass_fail_cursor;
END;
/
I've played around with it for the last couple of days and cant get it to work. The closest i can get is to create the tables and insert the first row only, generating an error when the loop tries to create a table that already exists.
Any help would be awesome
Thanks folks
Ben
Outcome: 1 table for each student (unique by name).
The create table ... is now inside the loop surrounded by an exception block. If the table already exists, the exception (ORA-00955) is handled.
SET SERVEROUTPUT ON
CREATE OR REPLACE PROCEDURE run_student_scores
IS
CURSOR c_pass_fail_cursor
IS
SELECT students.firstname,
test_history.score,
test_id.test_name,
test_id.passing_grade
FROM students
INNER JOIN test_history
ON students.student_id = test_history.student_id
INNER JOIN test_id
ON test_id.test_id = test_history.test_id
WHERE test_history.start_time BETWEEN to_timestamp(sysdate) + INTERVAL '8' HOUR
AND to_timestamp(sysdate) + INTERVAL '21' HOUR;
v_name students.firstname%TYPE;
v_score test_history.score%TYPE;
v_test varchar2(40);
v_passing test_id.passing_grade%TYPE;
v_result varchar2(4);
--New variables
table_already_exists EXCEPTION;
PRAGMA EXCEPTION_INIT(table_already_exists, -955);
BEGIN
OPEN c_pass_fail_cursor;
LOOP
FETCH c_pass_fail_cursor INTO v_name, v_score, v_test, v_passing;
EXIT WHEN c_pass_fail_cursor%NOTFOUND;
begin
EXECUTE IMMEDIATE ('create table student_tests_' || v_name || ' (student_name VARCHAR2(20), test_name varchar2(40), test_score NUMBER(3), pass_rate NUMBER(3), pass_fail VARCHAR2(4))');
exception when table_already_exists then
null;
end;
If v_score < v_passing
THEN v_result := 'Fail';
DBMS_OUTPUT.PUT_LINE(v_name || ' ' || v_score || ' ' || v_test || ' ' || V_passing || ' ' || 'Result =' || v_result);
ELSE
v_result := 'Pass';
DBMS_OUTPUT.PUT_LINE(v_name || ' ' || v_score || ' ' || v_test || ' ' || V_passing || ' ' || 'Result =' || v_result);
END IF;
EXECUTE IMMEDIATE 'INSERT INTO student_tests_' || v_name || ' ' || ' values(:1, :2, :3, :4, :5)' using v_name, v_test, v_score, v_passing, v_result;
END LOOP;
CLOSE c_pass_fail_cursor;
END;
/
Grafros answer looks good, but i strongly recommend to take a look at DBMS_ASSERT with DBMS_ASSERT.ENQUOTE_NAME or DBMS_ASSERT.ENQUOTE_LITERAL whenever you have take abitrary strings and use them in execute immidiate.

pl sql and dynamic sql

I am trying to create some dynamic sql using the following code block
firstSqlStatement := true;
updateText := 'UPDATE T_EMPLOYEES SET ';
if FIRSTNAME IS NOT NULL and FIRSTNAME > 0 THEN
updateText:=updateText || ' firstName=' || FIRSTNAME || ' ';
firstSqlStatement := false;
end if;
if MIDDLENAME IS NOT NULL and length(MIDDLENAME) > 0 THEN
if firstSqlStatement = false THEN
updateText:=updateText || ',';
end if;
updateText:=updateText || ' middleName=' || MIDDLENAME || ' ';
firstSqlStatement := false;
end if;
updateText:=updateText
|| ' where upper(id)=upper(' || ID ||');';
DBMS_OUTPUT.put_line(updateText);
EXECUTE IMMEDIATE updateText;
The statement never executes properly as there are missing single quotes around values.
Any ideas what i can do to make this small example work or is there any better way of doing this?
firstSqlStatement := true;
updateText := 'UPDATE T_EMPLOYEES SET ';
if FIRSTNAME IS NOT NULL and FIRSTNAME > 0 THEN
updateText:=updateText || ' firstName=''' || FIRSTNAME || ''' ';
firstSqlStatement := false;
end if;
if MIDDLENAME IS NOT NULL and length(MIDDLENAME) > 0 THEN
if firstSqlStatement = false THEN
updateText:=updateText || ',';
end if;
updateText:=updateText || ' middleName=''' || MIDDLENAME || ''' ';
firstSqlStatement := false;
end if;
updateText:=updateText || ' where upper(id)=upper(' || ID || ');';
DBMS_OUTPUT.put_line(updateText);
EXECUTE IMMEDIATE updateText;
use '''
Maybe you can do it this way.
declare
ll_employee_id number := 10;
lv_firstname varchar2(30) := 'Thomas';
lv_middlename varchar2(30) := null;
begin
update t_employees
set firstname = decode(lv_firstname, null, firstname, lv_firstname),
middlename = decode(lv_middlename, null, middlename, lv_middlename)
where employee_id = ll_employee_id;
end;
DECLARE
my_error exception;
sql_stmt VARCHAR2 (500);
v_char_field VARCHAR2 (500);
v_number_field NUMBER;
v_stmt_number NUMBER;
BEGIN
sql_stmt := 'UPDATE TABLE';
IF 1 = 1 -- REPLACE WITH CONDITION FOR SELECTION FIELD
THEN
sql_stmt := sql_stmt || 'field_1 = :1';
v_stmt_number := 1;
ELSIF 1 = 1 -- REPLACE WITH CONDITION FOR SELECTION FIELD
THEN
sql_stmt := sql_stmt || 'field_2 = :1';
v_stmt_number := 2;
ELSE
DBMS_OUTPUT.put_line ('Field unmanaged');
RAISE my_error;
END IF;
IF 1 = 1 -- REPLACE WITH CONDITION FOR SELECTION TYPE FIELD
THEN
EXECUTE IMMEDIATE sql_stmt USING v_char_field;
ELSIF 1 = 1 -- REPLACE WITH CONDITION FOR SELECTION TYPE FIELD
THEN
EXECUTE IMMEDIATE sql_stmt USING v_number_field;
ELSE
DBMS_OUTPUT.put_line ('Type Field unmanaged');
RAISE my_error;
END IF;
DBMS_OUTPUT.PUT_LINE ('STATEMENT NUMBER : ' || v_stmt_number);
DBMS_OUTPUT.PUT_LINE ('TOTAL RECORD UPDATE : ' || SQL%ROWCOUNT);
EXCEPTION
WHEN my_error
THEN
NULL;
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE ('ERROR :' || SQLERRM);
END;
You can use multiple selections to compose your statement for selection fields to be updated and for the type.