ORA-00904 INVALID IDENTIFIER oracle - sql

I would like to update a table using a column that may not exists. I am doing this but getting an error, I tried to handle but still getting an exception. Is there a way to go about this? to update a table only if a column exists? I am a beginner in Oracle PL/SQL, any help would be appreciated. Thanks.
declare
column_not_exists_exception exception;
pragma exception_init (column_not_exists_exception , -06550);
begin
update table1
set column = case
when column_may_not_exists = 0 then 0
when column_may_not_exists = 1 then 1
else 0
end;
exception when column_not_exists_exception then
dbms_output.put_line('error column does not exists');
end;
The error I get is ORA-06550 and ORA-00904 : "column_may_not_exists" : invalid identifier , cause: usually a pl/sql compilation error

That is certainly a strange requirement, but since PL/SQL must be valid at compilation time, you can't reference a non-existent column directly.
Thus you can do the following
SQL> create table t ( x int, y int );
Table created.
SQL> insert into t values (0,0);
1 row created.
SQL>
SQL> set serverout on
SQL> declare
2 column_not_exists_exception exception;
3 pragma exception_init (column_not_exists_exception , -904);
4 begin
5 execute immediate '
6 update t
7 set y = case
8 when y = 0 then 10
9 when y = 1 then 20
10 else 30
11 end';
12 dbms_output.put_line('All good');
13 exception
14 when column_not_exists_exception then
15 dbms_output.put_line('error column does not exists');
16 end;
17 /
All good
PL/SQL procedure successfully completed.
SQL>
SQL> set serverout on
SQL> declare
2 column_not_exists_exception exception;
3 pragma exception_init (column_not_exists_exception , -904);
4 begin
5 execute immediate '
6 update t
7 set z = case
8 when z = 0 then 10
9 when z = 1 then 20
10 else 30
11 end';
12 dbms_output.put_line('All good');
13 exception
14 when column_not_exists_exception then
15 dbms_output.put_line('error column does not exists');
16 end;
17 /
error column does not exists
PL/SQL procedure successfully completed.

Related

How to Solve an Trigger Compilation Error?

How can I solve this trigger compilation error?
SQL> create or replace trigger neg
2 before
3 insert
4 on tran
5 for each row
6
7 declare
8 no number;
9 begin
10 no:=new.no;
11 if no<=0 then
12 raise_application_error(-20002,'number is negative');
13 end if;
14 end;
15 /
Warning: Trigger created with compilation errors.
SQL> SHO ERROR Errors for TRIGGER NEG:
LINE/COL ERROR
-------- ----------------------------------------------------------------- 4/1 PL/SQL: Statement ignored 4/5 PLS-00201: identifier 'NEW.NO' must
be declared

Find id then assign 1 if id found from table PL sql create procedure

I'm looking to create a procedure that looks for the given customer ID in the database. If the customer exists, it sets the variable found to 1. Otherwise, the found variable is set to 0. However, my call out code block does not provide a result. Did I miss something or my SELECT statement should be something else? Thank you.
CREATE OR REPLACE PROCEDURE find_customer(CUST_ID IN NUMBER, found OUT NUMBER) AS
CUSTID NUMBER := CUST_ID;
BEGIN
SELECT CUSTOMER_ID INTO CUSTID
FROM CUSTOMERS
WHERE CUSTOMER_ID = CUST_ID;
IF CUST_ID = NULL THEN
found := 1;
END IF;
EXCEPTION
WHEN no_data_found THEN
found := 0;
END;
/
DECLARE
CUSTOMER_ID NUMBER := 1;
found NUMBER;
BEGIN
find_customer(1,found);
DBMS_OUTPUT.PUT_LINE (found);
END;
I don't think there's anything other to it than the following part bellow. In your given example, it is not possible to get a null value from it as any null id would probably mean the item doesn't exist. Meaning it doesn't return a row, which triggers the NO_DATA_FOUND exception, which you catch.
This is what you wrote:
IF CUST_ID = NULL THEN
found := 1;
END IF;
This is probably what you meant:
IF CUST_ID IS NOT NULL THEN
found := 1;
END IF;
I'd rewrite it so that
you distinguish parameters from local variables from column names
use table aliases
fix what happens when something is found (is not null, line #11)
while testing, use variable you declared, not a constant (1)
So:
SQL> CREATE OR REPLACE PROCEDURE find_customer (par_cust_id IN NUMBER,
2 par_found OUT NUMBER)
3 AS
4 l_custid NUMBER;
5 BEGIN
6 SELECT c.customer_id
7 INTO l_custid
8 FROM customers c
9 WHERE c.customer_id = par_cust_id;
10
11 IF l_custid IS NOT NULL
12 THEN
13 par_found := 1;
14 END IF;
15 EXCEPTION
16 WHEN NO_DATA_FOUND
17 THEN
18 par_found := 0;
19 END;
20 /
Procedure created.
Testing:
SQL> SET SERVEROUTPUT ON
SQL> SELECT * FROM customers;
CUSTOMER_ID
-----------
100
SQL> DECLARE
2 l_customer_id NUMBER := 1;
3 l_found NUMBER;
4 BEGIN
5 find_customer (l_customer_id, l_found);
6 DBMS_OUTPUT.put_line (l_found);
7 END;
8 /
0
PL/SQL procedure successfully completed.
SQL> DECLARE
2 l_customer_id NUMBER := 100;
3 l_found NUMBER;
4 BEGIN
5 find_customer (l_customer_id, l_found);
6 DBMS_OUTPUT.put_line (l_found);
7 END;
8 /
1
PL/SQL procedure successfully completed.
SQL>
You can simplify it down to:
CREATE OR REPLACE PROCEDURE find_customer(
p_cust_id IN CUSTOMERS.CUSTOMER_ID%TYPE,
p_found OUT NUMBER
) AS
BEGIN
SELECT 1
INTO p_found
FROM CUSTOMERS
WHERE CUSTOMER_ID = p_cust_id;
EXCEPTION
WHEN no_data_found THEN
p_found := 0;
END;
/
The line CUSTOMER_ID = p_cust_id will not match if either side is NULL so you don't need any further checks.
Then you can call it using:
DECLARE
v_found NUMBER;
BEGIN
find_customer(1,v_found);
DBMS_OUTPUT.PUT_LINE (v_found);
END;
/
db<>fiddle here

is there a function without an input but return something

CREATE OR REPLACE FUNCTION FN_MULTAS_TOTAL
RETURN INTEGER
IS
V_TOTAL INT;
BEGIN
SELECT SUM(MULTA)
INTO V_TOTAL
FROM DETALLE_ARRIENDO;
RETURN V_TOTAL;
END;
im working on SQL Developer 11 and i have to call it with
exec FN_MULTAS_TOTAL;
and get an integer value
No problem with such a function:
SQL> create or replace function fn_multas_total
2 return integer
3 is
4 v_total int;
5 begin
6 select sum(multa)
7 into v_total
8 from detalle_arriendo;
9 return v_total;
10 end;
11 /
Function created.
However, you don't call it with exec - it is used in SQL*Plus or SQL Developer or some other tools which support it; it is a "shortcut" for an anonymous begin-end PL/SQL block:
SQL> exec p_test
PL/SQL procedure successfully completed.
SQL> begin
2 p_test;
3 end;
4 /
PL/SQL procedure successfully completed.
It is used for procedures, not functions. You can't just
SQL> begin
2 detalle_arriendo;
3 end;
4 /
detalle_arriendo;
*
ERROR at line 2:
ORA-06550: line 2, column 3:
PLS-00221: 'DETALLE_ARRIENDO' is not a procedure or is undefined
ORA-06550: line 2, column 3:
PL/SQL: Statement ignored
SQL>
which means that you have to declare a variable and fetch function's result into it, e.g.
SQL> declare
2 l_result number;
3 begin
4 l_result := fn_multas_total;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
Usually, we use functions as
SQL> select fn_multas_total from dual;
FN_MULTAS_TOTAL
---------------
100
SQL>
If you desperately want to use exec, then you still have to declare a variable and
SQL> var result number
SQL> exec :result := fn_multas_total;
PL/SQL procedure successfully completed.
SQL> print :result
RESULT
----------
100
SQL>

How can i use variables dynamically by changing their names using code

Want a way to refer different variables by changing their names dynamically in a plsql block.
Tried with simple loops which will change effective names of the variables.
Writing a cascaded plsql block using statement but due to size of existing code it is of no use.
set serveroutput on;
declare
foo1 number:=111;
foo2 number:=222;
begin
execute immediate 'dbms_output.put_line(foo'||'1)';
for i in 0..2
loop
dbms_output.put_line(foo||i);
end loop;
end;
/
expected output to be 111
output is error as below
Error report -
ORA-00900: invalid SQL statement
ORA-06512: at line 5
00900. 00000 - "invalid SQL statement"
Your variables are local. The DBMS_OUTPUT package doesn't know them. So the resulting string dbms_output.put_line(foo1) can not be executed with execute immediate.
The typical way to solve this is to use an array of values rather than separate variables:
declare
type t_array is varray(2) of integer;
v_array t_array := t_array(111, 222);
begin
for i in 1..2 loop
dbms_output.put_line(v_array(i));
end loop;
end;
The same with a dynamic array:
declare
type t_array is table of integer;
v_array t_array := t_array();
begin
v_array.extend(1);
v_array(1) := 111;
v_array.extend(1);
v_array(2) := 222;
for i in 1 .. v_array.count loop
dbms_output.put_line(v_array(i));
end loop;
end;
Let's take it one step at a time. First, static code that works:
SQL> declare
2 foo1 number:=111;
3 foo2 number:=222;
4 begin
5 dbms_output.put_line(foo1);
6 end;
7 /
111
Now, if you want to EXECUTE IMMEDIATE some text, you have to put all the code in the text:
SQL> declare
2 l_code_block varchar2(4000) := '
3 declare
4 foo1 number:=111;
5 foo2 number:=222;
6 begin
7 dbms_output.put_line(foo2);
8 end;
9 ';
10 begin
11 execute immediate l_code_block;
12 end;
13 /
222
Next step: if we want to change a value dynamically, we can and should use a "bind variable".
SQL> declare
2 l_code_block varchar2(4000) := '
3 declare
4 foo1 number:=111;
5 foo2 number:=222;
6 begin
7 dbms_output.put_line(:n);
8 end;
9 ';
10 begin
11 execute immediate l_code_block using 1;
12 end;
13 /
1
But if we try to use a bind variable to change the code, it doesn't work.
SQL> declare
2 l_code_block varchar2(4000) := '
3 declare
4 foo1 number:=111;
5 foo2 number:=222;
6 begin
7 dbms_output.put_line(foo:n);
8 end;
9 ';
10 begin
11 execute immediate l_code_block using 1;
12 end;
13 /
...
Error report -
ORA-06550: line 6, column 25:
PLS-00103: Encountered the symbol "" when expecting one of the following
...
So if we want to change the code dynamically, we have to do a REPLACE on the text.
SQL> declare
2 l_code_block varchar2(4000) := '
3 declare
4 foo1 number:=111;
5 foo2 number:=222;
6 begin
7 dbms_output.put_line(foo#N#);
8 end;
9 ';
10 begin
11 execute immediate replace(l_code_block,'#N#',1);
12 end;
13 /
111
Finally, here is your loop:
SQL> declare
2 l_code_block varchar2(4000) := '
3 declare
4 foo1 number:=111;
5 foo2 number:=222;
6 begin
7 dbms_output.put_line(foo#N#);
8 end;
9 ';
10 begin
11 for i in 1..2 loop
12 execute immediate replace(l_code_block,'#N#',i);
13 end loop;
14 end;
15 /
111
222
Please understand, I am trying to answer your question as asked. This "dynamic" approach should be avoided whenever possible, and it is almost always possible. We would have to back up to the business requirement in order to recommend the most appropriate technique.
Best regards,
Stew Ashton

ORA-06531 after Oracle upgrade

I upgraded my database from Oracle 10 to 11.2. The problem I face is that my geometry in tables don't work any more. My SQL is:
Select
GEOMETRYID, COORDCOUNT, CREATIONDATE, QUALITYID,
SDO_UTIL.TO_WKTGEOMETRY(SDO_CS.TRANSFORM(SDO_UTIL.SIMPLIFY(GEOMETRY, 1, 0.0000005), 27700)) as "WKT"
FROM
NWKGEOMETRY
WHERE
DELETIONDATE IS NULL;
AND SDO_GEOMETRY.GET_GTYPE(GEOMETRY)=2 AND SDO_UTIL.GETNUMVERTICES(GEOMETRY)>2;
and I get an error:
ORA-06531: Reference to uninitialized collection
If I remove TRANSFORM function then all works fine. What could be wrong?
This error:
ORA-06531: Reference to uninitialized collection
means that you have a collection that is not initialized before you use it, for example:
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
SQL> ed
Wrote file afiedt.buf
1 CREATE OR REPLACE TYPE t_employee AS OBJECT(
2 id number,
3 name VARCHAR2(300),
4 CONSTRUCTOR FUNCTION t_employee RETURN SELF AS RESULT
5* )
SQL> /
Type created.
SQL> ed
Wrote file afiedt.buf
1* CREATE OR REPLACE TYPE t_employees AS TABLE OF t_employee
SQL> /
Type created.
SQL> ed
Wrote file afiedt.buf
1 DECLARE
2 l_emp t_employee;
3 l_emps t_employees;
4 BEGIN
5 for i in (SELECT employee_id, first_name
6 FROM employees)
7 loop
8 l_emp := t_employee(i.employee_id, i.first_name);
9 l_emps.extend();
10 l_emps(l_emps.COUNT) := l_emp;
11 end loop;
12 DBMS_OUTPUT.put_line(l_emps(4).name);
13* END;
SQL> /
DECLARE
*
ERROR at line 1:
ORA-06531: Reference to uninitialized collection
ORA-06512: at line 9
As you can see, I have the ORA-06531 error, that's because I haven't initialized the l_emps variable, I have to add l_emps := t_employees();:
SQL> ed
Wrote file afiedt.buf
1 DECLARE
2 l_emp t_employee;
3 l_emps t_employees;
4 BEGIN
5 l_emps := t_employees();
6 for i in (SELECT employee_id, first_name
7 FROM employees)
8 loop
9 l_emp := t_employee(i.employee_id, i.first_name);
10 l_emps.extend();
11 l_emps(l_emps.COUNT) := l_emp;
12 end loop;
13 DBMS_OUTPUT.put_line(l_emps(4).name);
14* END;
SQL> /
David
PL/SQL procedure successfully completed.
So take a look at the sources of all these PL/SQL procedures, the problem is in them.