I have a function:
At line execute immediate 'select ' || schemaname || '.' || value1 || '_seq.nextval from dual' into cnpParmId;
Am getting error as SQL Error: ORA-00904: "CNPPARMID": invalid identifier.
I tried to put the cnpParmId inside the quotes, tried into cnpParmId from dual, in all possible ways. But its not working.
Please give me some ideas to solve this issue.
Thanks!!
Your function compiles successfully, and you get the error at runtime:
select test(user, 'T42') from dual;
SQL Error: ORA-00904: "CNPPARMID": invalid identifier
ORA-06512: at "MYSCHEMA.TEST", line 23
You said the error was on the first execute immediate, but that is line 21 not line 23, and if it was that cnpParmId reference it was complaining about then it would cause a compilation error - the function would be created but with errors/warnings, and it wouldn't be possible to call it.
So it's the second execute immediate, at line 23, which is erroring at runtime (reformatted slightly):
execute immediate
'select ''T'' from dual where cnpParmId not in ' ||
'(select value1 from ' || schemaname || '.' || tablename || ')'
into good;
As GolezTrol said, the dynamic statement is executed in a SQL context that has no visibility of any of your PL/SQL variables. It's the same as running the generated statement:
select 'T' from dual where cnpParmId not in (select value1 from myschema.t42);
... directly in SQL*Plus or SQL Developer, which also gets:
SQL Error: ORA-00904: "CNPPARMID": invalid identifier
00904. 00000 - "%s: invalid identifier"
As a variation of GolezTrol's concatenation, you could use a bind variable to prevent hard-parsing each time round your loop, but you also need to provide your primary key column name as value1 also won't be recognised; and that has to be concatenated in:
execute immediate
'select ''T'' from dual where :cnpParmId not in ' ||
'(select ' || value1 || ' from ' || schemaname || '.' || tablename || ')'
into good using cnpParmId;
which compiles and runs.
You could also use not exists rather than not in, which might perform better since you're looking for the (indexed) primary key:
execute immediate
'select ''T'' from dual where not exists (select null from '
|| schemaname || '.' || tablename || ' where ' || value1 || ' = :cnpParmId)'
into good using cnpParmId;
You can also move the query that finds value1 outside the loop; there's no benefit to calling that repeatedly.
It looks like you're doing this because you have primary key values that weren't generated from the sequence. If you're still adding new records like that - e.g. via a trigger that only uses the sequence if the passed key column is null - then you need a hack like this or an insert loop that catches the ORA-01001. But this approach still has a race condition - another session can simultaneously do a manual insert with the same value your function finds, and one of the sessions will get an error.
It would usually be better to only use the sequence; if you are now doing that, or can change to do that, then a one-off adjustment of all your sequences to be higher than the current maximum key value would be simpler.
Using execute immediate, you execute the statement outside of the scope of the function, so it can't use the PLSQL variable. I'd solve this by executing it as a normal query and use SELECT INTO or a cursor to fetch the query result.
But it should also work if you simply substitute the value into the query string yourself, like this:
Change
'select ''T'' from dual where cnpParmId not in ' ||
into
'select ''T'' from dual where ' || cnpParmId || ' not in ' ||
Related
I have this instruction
UPDATE TABLE1
SET INC =
(select INC from TABLE2
WHERE KEY = 'KEY_VALUE1'
FETCH FIRST 1 ROW ONLY);
This working fine if i run from sqlPlus or if I use in PLSQL but, if I using in Dynamic SQL, not working
sqlStmt:= 'UPDATE TABLE1'
|| 'SET INC = '
|| '(select INC from TABLE2 '
|| 'WHERE KEY = ''' || v_key_value || ''' '
|| 'FETCH FIRST 1 ROW ONLY); ';
BEGIN
EXECUTE IMMEDIATE sqlStmt;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('{"errorcode":"' || SQLERRM);
ROLLBACK;
END;
This instruction return this error:
{"errorcode":"ORA-00933: comando SQL terminato erroneamente
Someone can you help me?
Regards,
Marco
You don't want to have a semicolon at the end of the string you are building and passing to execute immediate.
It's not the cause of your error. But it would be much kinder to the database to write this using bind variables rather than concatenating literals. Of course, since there is no reason to be using dynamic SQL for this sort of update statement, I'm guessing your actual use case is different and that you are actually using bind variables and/or there is actually a reason why bind variables aren't an option.
I get the following error message in a stored procedure that I created:
ORA-00933: SQL command not properly ended
ORA-06512: at line 11
I have tried Googling it, but could not find anything applicable as it tells my to try to eliminate any 'ORDER BY'.
declare
cursor a_tab is
select table_name
from all_tables
where owner = 'OFFERINGWORKSPACE'
and (TABLE_NAME like 'EBA_%' or TABLE_NAME = 'SURVEY_2.0');
v_tab_name varchar2(500);
begin
open a_tab;
loop
fetch a_tab into v_tab_name;
exit when a_tab%notfound;
EXECUTE IMMEDIATE 'delete ' || v_tab_name;
end Loop;
close a_tab;
open a_tab;
Loop
fetch a_tab into v_tab_name;
Exit when a_tab%notfound;
EXECUTE IMMEDIATE 'insert into ' || v_tab_name || '(select * from OFFERINGWORKSPACE.'||v_tab_name ||')';
End Loop;
Close a_tab;
End;
There is a clue in your cursor query:
... TABLE_NAME = 'SURVEY_2.0');
The period in that breaks the database object naming rules:
Nonquoted identifiers can only contain alphanumeric characters from your database character set and the underscore (_). Database links can contain periods (.) and "at" signs (#).
so that table name must be a quoted identifier. You therefore need to quote it in your statements:
EXECUTE IMMEDIATE 'delete "' || v_tab_name || '"';
and
EXECUTE IMMEDIATE 'insert into "' || v_tab_name
|| '"(select * from OFFERINGWORKSPACE."'||v_tab_name ||"')';
db<>fiddle showing the errors from those commands (simplified to one schema, and static SQL), and how adding the double quotes fixes them.
I'm creating a function that accepts two parameters. And one of my parameter will serve as the database link for my statement. I've tried concatenating it. How will I be able to achieve this?
It shows this error
ORA-00923: FROM keyword not found where expected ORA-06512 at
"NOINK.CHECK_SECOND_REF_DIE", line 13.
Below is the code.
drop function check_second_ref_die;
create or replace function check_second_ref_die(lotNumber in VARCHAR2, db_link in VARCHAR2)
return varchar2
is
row_count NUMBER;
sql_statement VARCHAR2(300);
BEGIN
sql_statement := 'SELECT COUNT(*) FROM wcrepo.WCR_WAFER_REFERENCE#lepftds.itg.ti.com
WHERE waferconfigfile = (SELECT waferconfigfile FROM program_setup_rev#' || db_link ||
'WHERE device = (SELECT device FROM noink.lot WHERE lot_num = ' ||lotNumber || ')
AND setup_cnt=0) AND status =' || 'Approved' || 'AND ref_die_type =' || 'Secondary';
execute immediate sql_statement into row_count;
IF (row_count != 0) THEN
RETURN 'TRUE';
ELSE
RETURN'FALSE';
END IF;
END;
This is the code when I try to call the function
SELECT CASE
WHEN check_second_ref_die ('8019572', 'rfabtwdb.dal.make.ti.com') = 'TRUE'
THEN 'EXISTS' ELSE 'NOT EXISTS'
END
AS RESULT
FROM DUAL
AND status =' || 'Approved' || 'AND
This is wrong. Remove the concatenation operators and we have ...
AND status =ApprovedAND
... which is not valid SQL. To reference string literals you need to escape single quotes. The simplest way is to use two of them:
AND status =''Approved'' AND
You'll need to fix all the string literals in your code.
Dynamic SQL is hard because it turns compilation errors into runtime errors. You can make it easier to debug your code by including some simple instrumentation. If your code had this line before the EXECUTE IMMEDIATE you could have seen the executed statement and probably spotted the bloomer for yourself.
dbms_output.put_line(v_sql);
I am getting the following error:
00000 - "missing right parenthesis"
when I execute my procedure:
CREATE OR REPLACE PROCEDURE ALTER_TABLE_COLUMN_NOT_NULL(
var_tabname IN VARCHAR2,
var_clname IN VARCHAR2,
var_defvalue IN VARCHAR2 )
IS
l_isnull VARCHAR2(1);
BEGIN
SELECT isnull INTO l_isnull FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = var_tabname AND COLUMN_NAME = var_clname;
IF l_isnull = 'Y' THEN
EXECUTE IMMEDIATE 'ALTER TABLE ' || var_tabname ||
' MODIFY COLUMN (' || var_clname ||
' DEFAULT ' || var_defvalue || ' NOT NULL)';
END IF;
END;
I know that according to the error, the right parenthesis is missing. I tried many ways of rewriting it, but I can't manage to fix it.
I am executing my procedure the following way:
BEGIN
ALTER_TABLE_COLUMN_NOT_NULL('FIRSTNAME', 'PRICE', '-');
END;
Writing dynamic SQL is hard, because compilation errors become runtime errors.
In this case I think the problem is that MODIFY COLUMN is wrong syntax. It's just MODIFY.
You may also run into some problems with your default of '-'. If price is a number that will fail because - is an invalid number. If price is a string you'll need to escape the passed value with additional quotes.
But probably you want to make this generic, so you need to write some more sophisticated handling which tests for datatype of the target column and formats default value appropriately.
"Can u give me a hint or any link how one can determine the datatype of a passed value in plsql?"
It's not the passed value which matters, it's the datatype of the modified column. You can get that from the USER_TAB_COLUMNS view which you're already querying.
Print your query to make sure it written correctly
DBMS_OUTPUT.PUT_LINE('ALTER TABLE ' || var_tabname || ' MODIFY COLUMN (' || var_clname || ' DEFAULT ' || var_defvalue || ' NOT NULL)');
I have a pl/sql function and in that i have the following piece of code:
execute immediate 'select ' || schemaname || '.' || value1 || '_seq.nextval from dual into cnpParmId';
for this line, I am getting an error:
SQL Error: ORA-00933: SQL command not properly ended
In the above code I am getting the value1 from the result of a select query. schemaname is the input of the function and cnpParmId is the return value of the function.
I tried different ways to solve this but I still get the error.
It's hard to say without showing us more of your procedure, but I think it's a fair guess that you didn't mean to concatenate cnpParmId in your dynamic SQL (how could the dynamic SQL possibly know how to interpret cnpParmId?). cnpParmId is probably defined somewhere in your procedure.
Instead, you probably meant to use the into clause of the execute immediate command:
execute immediate 'select ' || schemaname || '.' || value1 || '_seq.nextval from dual'
into cnpParmId;