I have to write a function which edits predefined characteristics of a task. I'm using execute immediate but I'm getting this error:
> Error report -
ORA-00933: SQL command not properly ended
ORA-06512: at "C##U1519.BEARBEITE", line 7
ORA-06512: at line 2
00933. 00000 - "SQL command not properly ended"
This is my code
create or replace procedure bearbeite(Aufg_ID Aufgabe.Aufgaben_ID%TYPE, Eigenschaft VARCHAR2, Wert VARCHAR2)
as
sql_query_string2 VARCHAR2(4000);
begin
--überprüfen
sql_query_string2 := 'UPDATE Aufgabe SET ' || Eigenschaft || ' = ' || Wert || ' where Aufgabe.Aufgaben_ID = ' || Aufg_ID;
EXECUTE IMMEDIATE sql_query_string2;
exception
when no_data_found then
dbms_output.put_line('Kein Wert');
end;
-- test
set serveroutput on
begin
bearbeite(1,'Ort','TH WILDAU');
end;
What should I do in order to make it work? Thanks in advance
Dumping values into query strings is dangerous. The most advertised danger is SQL injection, but that doesn't apply in many cases (where user input might have controls already in place). A bigger issue is unexpected syntax errors. More than one person -- I'm sure -- has encountered a name like O'Neil to their detriment when generating a query string.
I strongly recommend the use of parameters. And this is easy in Oracle:
sql_query_string2 := 'UPDATE Aufgabe SET ' || Eigenschaft || ' = :1 where Aufgabe.Aufgaben_ID = :2';
EXECUTE IMMEDIATE sql_query_string2 USING Wert, Aufg_ID;
This also means that you don't have to worry about whether or not to use single quotes.
The parameters can be named rather than numbered.
Sadly, you cannot use parameters for SQL identifiers -- table names, schema names, column names, functions, key words. So, the column name does have to be incorporated into the string.
You should surround varchar2 argument with single quotes ... which in pl/sql should be escaped and becomes ''
sql_query_string2 := 'UPDATE Aufgabe SET ' || Eigenschaft || ' = ''' || Wert || ''' where Aufgabe.Aufgaben_ID = ' || Aufg_ID;
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'm struggling to create a dynamic sql parametrized query. It involves using 'IS NULL' or 'IS NOT NULL'
Here's a simple pl/sql query:
CREATE OR REPLACE PROCEDURE GET_ALL_INFORMATION
(
"PARAM_START_DATE" IN DATE,
"PARAM_END_DATE" IN DATE,
"PARAM_IS_SUBMITTED" IN NUMBER,
"EXTRACT_SUBMITTED_CONTACTS" OUT sys_refcursor
) IS
sql_stmt VARCHAR2(3000);
PARAM_CONDITION VARCHAR2(20);
BEGIN
IF PARAM_IS_SUBMITTED = 1 THEN
PARAM_CONDITION := 'NOT NULL';
ELSE
PARAM_CONDITION := 'NULL';
END IF;
sql_stmt := ' SELECT
REGISTRATION_NUMBER,
NAME PROVIDER_TYPE,
ORGANIZATION
FROM TABLE_A
WHERE
P.DATE_FINALIZED IS :A;
OPEN EXTRACT_SUBMITTED_CONTACTS FOR sql_stmt USING PARAM_CONDITION;
Whereas the parameter (:A) in (USING PARAM_CONDITION) should have 'NULL' or 'NOT NULL'. It does not seem to work the way I envisioned.
Am I missing something?
As explained by GriffeyDog in a comment above, bind parameters could only be used as place holder for values. Not to replace keywords or identifiers.
However, this is not really an issue here, as you are using dynamic SQL. The key idea ifs that you build your query as a string -- and it will be parsed at run-time by the PL/SQL engine when you invoke EXECUTE or OPEN .. FOR.
Simply said, you need a concatenation -- not a bound parameter:
...
sql_stmt := ' SELECT
REGISTRATION_NUMBER,
NAME PROVIDER_TYPE,
ORGANIZATION
FROM TABLE_A
WHERE
P.DATE_FINALIZED IS ' || PARAM_CONDITION;
-- ^^
OPEN EXTRACT_SUBMITTED_CONTACTS FOR sql_stmt;