Oracle dynamic PL/SQL. I cant get it to work - oracle

So here is my code:
CREATE OR REPLACE PROCEDURE UPDATE_USER
(
updateColumn IN USERS.column_name%type,
changeStr IN VARCHAR2,
unID IN VARCHAR2
)
IS
BEGIN
EXECUTE IMMEDIATE
'UPDATE
users
SET :1 = :2
WHERE
uniqueID = :3'
USING updateColumn, changeStr, unID;
END;
/
I've searched for other answers on this and as far as I can tell this should work. However I get the error:
'Error(3,25): PLS-00302: component 'COLUMN_NAME' must be declared'
Thanks.

The error message specifies line 3, character 25, which points to column_name in the declaration of the updateColumn parameter. It appears that you are trying to pass the column name to update as a parameter, but that means that at compile time the column isn't known, so its type can't be known. This also doesn't really make sense - if it's a number column then you'd be trying to pass the column name into a numeric parameter, which wouldn't work anyway. If you don't want to declare it as a simple varchar2, you could instead use user_tab_columns.column_name%type.
But you can't dynamically set the column name in the update statement using a bind variable. It would compile, but would get an ORA-01747 on execution from the apparent name starting with a colon. You'd need to concatenate it, something like:
CREATE OR REPLACE PROCEDURE UPDATE_USER
(
updateColumn IN user_tab_columns.column_name%type,
changeStr IN VARCHAR2,
unID IN VARCHAR2
)
IS
BEGIN
EXECUTE IMMEDIATE
'UPDATE
users
SET ' || updateColumn || ' = :1
WHERE
uniqueID = :2'
USING changeStr, unID;
END;
/
But you'd need to sanitise the column name to avoid SQL injection. APC's answer to the question you linked to mentions using the DBMS_ASSERT package, for example.

Related

ORA-00904 Invalid Identifier -- Dynamic Oracle function

create or replace
FUNCTION JDT_UDC_Desc
(
V_SY IN VARCHAR2,
V_RT IN VARCHAR2,
V_KY IN VARCHAR2
)
RETURN VARCHAR2
AS
V_DL01 VARCHAR2(30);
BEGIN
EXECUTE IMMEDIATE 'select drdl01
from PRODCTL.F0005
WHERE DRSY = V_SY
AND DRRT = V_RT
AND ltrim(rtrim(drky)) =ltrim(rtrim(V_KY))'
INTO V_DL01
using V_SY,V_RT,V_KY;
END;
Compiled. I click on run and enter below values:
V_SY ='00',
V_RT = '01',
V_KY='04';
And I get below error
ORA-00904 V_KY Invalid Identifier
Can anyone help me understand the reason for this error?
You are passing the literal values 'V_SY', 'V_RT' and 'V_KY' in your statement and it's interpreting them as column names, hence the invalid identifier error. You need to use the variable placeholders like:
EXECUTE IMMEDIATE 'select drdl01
from PRODCTL.F0005
WHERE DRSY = :1
AND DRRT = :2
AND ltrim(rtrim(drky)) =ltrim(rtrim(:3))'
INTO V_DL01
using V_SY,V_RT,V_KY;
First, there does not appear to be any reason to use dynamic SQL here. It should be rare that you need to resort to dynamic SQL-- your code is going to be more efficient and more maintainable.
create or replace
FUNCTION JDT_UDC_Desc
(
V_SY IN VARCHAR2,
V_RT IN VARCHAR2,
V_KY IN VARCHAR2
)
RETURN VARCHAR2
AS
V_DL01 VARCHAR2(30);
BEGIN
select drdl01
into V_DL01
from PRODCTL.F0005
WHERE DRSY = V_SY
AND DRRT = V_RT
AND trim(drky) =trim(V_KY);
return v_dl01;
END;
Second, it would be really helpful if you picked meaningful variable names and meaningful names for your columns and tables. F0005 tells you nothing about what the table contains. v_sy and drsy tell you nothing about what the variable or column is supposed to contain. That is going to make maintaining this code far more difficult that it needs to be.

Update statement inside oracle stored procedure is not working

I have one simple update statement inside oracle stored procedure. Its executing successfully but its not updating the table.
CREATE OR REPLACE PROCEDURE UpdateSourceLog
( SourceLogId IN NUMBER, TotalRowCount IN INT,Status IN VARCHAR)
AS
BEGIN
UPDATE SourceLog
SET Status = Status,
TotalRowCount = TotalRowCount,
EndTime = SYSDATE
WHERE SourceLogId = SourceLogId;
COMMIT;
END;
I have tried with changing the perameter name different from column name. Then also Its not working.
And I have tried with anonymous block. I'm not able to find out the isue. Please help me in this regard.
Thanks!
It is a bad practice to give parameters the same name as table columns.
So you should change it:
CREATE OR REPLACE PROCEDURE UpdateSourceLog
( p_SourceLogId IN NUMBER, p_TotalRowCount IN INT,p_status IN VARCHAR)
AS
BEGIN
UPDATE SourceLog
SET Status = p_status,
TotalRowCount = p_TotalRowCount,
EndTime = SYSDATE
WHERE SourceLogId = p_SourceLogId;
COMMIT;
END;
Because for now, most likely, Oracle understands it as column names and just update column to value from this column (no sense at all)

Use execute immediate in procedure for DML and passing character value in parameter

I have a delete procedure which is taking table name and some values to delete record from that table, hence I have created a procedure with execute immediate which is forming the delete query by taking the parameter and delete.
But when ever I am passing the char value in the parameter it is getting error :
invalid identifier
as query formed with out single quote for the character value. Please let me know how can I pass char value in the procedure to form a string correctly.
Below is the procedure:
CREATE OR replace PROCEDURE Prd_delete(p_tbl_name IN VARCHAR2,
p_sys VARCHAR2,
p_b_id VARCHAR2,
p_c_date NUMBER)
IS
dlt_query VARCHAR2(200);
BEGIN
dlt_query := 'delete from '
||p_tbl_name
||' where system='
||p_sys
|| ' And batch_id='
||p_b_id
|| ' And cobdate='
||p_c_date;
--dbms_output.put_line(dlt_query);
EXECUTE IMMEDIATE dlt_query;
END;
/
Below is the running command :
exec prd_delete ('TBL_HIST_DATA','M','N1',20141205);
Below is the error :
ORA-00904:"N1" invalid identifier.
How to pass this value correctly ? please suggest.
At first place, why do you need PL/SQL for the DELETE. You could do it in plain SQL.
Why is P_C_DATE a NUMBER, What data type is cobdate COLUMN. A date should always be a DATE. If the column data type is DATE, then you will run into more errors. Always pay attention to declaring correct data types.
With dynamic SQL, before directly executing, it is always a good practice to see whether the query is formed correctly using DBMS_OUTPUT. I would also suggest to use quoting string literal technique to make it even easier.
DBMS_OUTPUT.PUT_LINE(dlt_query);
The issue with the query is that you are missing the single-quotation marks around the VARCHAR2 type.
Modify the query to -
dlt_query := 'delete from '||P_TBL_NAME||' where system='||P_SYS||
' And batch_id='||''''||P_B_ID|| '''' ||
' And cobdate='||P_C_DATE;
you are losing the quotes around N1 during concatination
you can fix by adding quotes before and after , eg.
dlt_query := 'delete from '||P_TBL_NAME||' where system='||P_SYS||
' And batch_id='||''''||P_B_ID|| '''' ||
' And cobdate='||P_C_DATE;
If you have to use the EXECUTE IMMEDIATE statement, you should use bind variables:
CREATE OR REPLACE PROCEDURE prd_delete (P_TBL_NAME IN VARCHAR2,
P_SYS VARCHAR2,
P_B_ID VARCHAR2,
P_C_DATE NUMBER) IS
dlt_query VARCHAR2 (200);
BEGIN
dlt_query := 'delete from ' || P_TBL_NAME || ' where system=:1 and batch_id=:2 and cobdate=:3';
BEGIN
EXECUTE IMMEDIATE dlt_query USING P_SYS, P_B_ID, P_C_DATE;
EXCEPTION
WHEN OTHERS THEN
-- catch exception !!
END;
END;
/

SQLPLUS object system. is invalid

I'm stuck with some simple procedure and I can't figure out why.
This is my code, which I'm running in sqlplus:
CREATE OR REPLACE PROCEDURE NormalizeName(fullname IN NVARCHAR2)
IS
BEGIN
SELECT TRIM(fullname) INTO fullname FROM DUAL;
DBMS_OUTPUT.PUT_LINE(fullname);
END NormalizeName;
/
BEGIN
NormalizeName('Alice Wonderland ');
END;
/
When I run it, I get the error:
Warning: Procedure created with compilation errors.
NormalizeName('Alice Wonderland ');
*
ERROR at line 2:
ORA-06550: line 2, column 2:
PLS-00905: object SYSTEM.NORMALIZENAME is invalid
ORA-06550: line 2, column 2:
PL/SQL: Statement ignored
What's wrong?
1) Never create objects in the SYS or SYSTEM schema. Those are reserved for Oracle. If you want to create objects, create a new schema first.
2) When you see that a procedure has been created with compilation errors in SQL*Plus, type show errors to see the errors.
3) The error appears to be that your SELECT statement is trying to write to the fullname parameter. But that parameter is defined as an IN parameter, not IN OUT, so it is read-only. If you define the parameter as IN OUT, though, you could not pass a string constant to the procedure, you'd need to define a local variable in your calling block. It doesn't make a lot of sense to have a procedure that doesn't do anything other than call dbms_output since there is no guarantee that anyone will see the data written to that buffer. My guess is that you really want a function that returns a normalized name. Something like
CREATE OR REPLACE FUNCTION NormalizeName( p_full_name IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
RETURN TRIM( p_full_name );
END;
which you can then call
DECLARE
l_normalized_name VARCHAR2(100);
BEGIN
l_normalized_name := NormalizeName( 'Alice Wonderland ' );
dbms_output.put_line( l_normalized_name );
END;
If you really need a procedure because this is a homework assignment
CREATE OR REPLACE PROCEDURE NormalizeName( p_fullname IN VARCHAR2 )
AS
BEGIN
dbms_output.put_line( TRIM( p_fullname ));
END;
In the real world, you should only be using procedures when you want to manipulate the state of the database (i.e. you're doing INSERT, UPDATE, DELETE, MERGE, etc.). You use functions when you want to perform calculations without changing the state of the database or when you want to manipulate data passed in parameters.

ORA-12714: invalid national character set specified

I got a problem with oracle database ,i created a stored procedure and i wanted to pass an array of items' ids to this procedure to select the data according to array of items using "in" clause,the available solution to this as i found was to create a function and pass a string value with all item's ids seperated by a comma ,and this function will return a datatble with a row for each item id.this approach works fine when i try it in toad in a select statement,,but when i use it in the stored procedure i get a strange error
"ORA-12714: invalid national character set specified"
after searching about the reason of that error i found that it is a bug in that version of oracle according to this page and it was fixed in a 10.2.0.4 oracle patch and the exact reason is to declare a cursor for the function that returns a data table
As it is impossible to me to let the users who work on a live production environment to stop the servers to apply the update patch ,I was wondering if any Oracle expert can help me to declare a cursor and return that cursor instead of returning the table.
my Oracle function,Thanks in Advance
create or replace
FUNCTION SplitIDs(
v_List IN VARCHAR2)
RETURN RtnValue_Set PIPELINED
AS
SWV_List VARCHAR2(2000);
v_RtnValue Dt_RtnValue := Dt_RtnValue(NULL);
BEGIN
SWV_List := v_List;
WHILE (instr(SWV_List,',') > 0)
LOOP
FOR RetRow IN
(SELECT ltrim(rtrim(SUBSTR(SWV_List,1,instr(SWV_List,',') -1))) SelectedValue
FROM dual
)
LOOP
v_RtnValue.SelectedValue := RetRow.SelectedValue;
PIPE ROW(v_RtnValue);
END LOOP;
SWV_List := SUBSTR(SWV_List,instr(SWV_List,',')+LENGTH(','),LENGTH(SWV_List));
END LOOP;
FOR RetRow IN
(SELECT ltrim(rtrim(SWV_List)) SelectedValue FROM dual
)
LOOP
v_RtnValue.SelectedValue := RetRow.SelectedValue;
PIPE ROW(v_RtnValue);
END LOOP;
RETURN;
END;
Oracle says this about the error:
Error: ORA-12714 (ORA-12714)
Text: invalid national character set specified
Cause: Only UTF8 and AL16UTF16 are allowed to be used as the national character set
Action: Ensure that the specified national character set is valid
Check your NLS_NCHAR_CHARACTERSET which is set using:
select value from NLS_DATABASE_PARAMETERS where parameter = 'NLS_NCHAR_CHARACTERSET';
Try using NCHAR, NVARCHAR2 or NCLOB

Resources