How to insert special characters into oracle table? - oracle

How to insert special characters into Oracle table?
I found example where this is evident what this 'special character' will be and is escaped for instance with another comma.
In my code I do not know what this character will be. Can be &, ", ', ....
Is there any escape function in Oracle or I have to do write piece of code?
My code is:
l_sql := 'INSERT INTO similar (product_id, product_name) VALUES (' || l_product_id || ',''' || l_desc || ''')';
Regards

It appears that you are using EXECUTE IMMEDIATE to run this. Is there a specific reason you would do that, and not just put a normal INSERT command in your procedure when you already have your values stored in variables (l_product_id and l_desc)?
The correct approach would be to issue the insert command directly and avoid concatenating strings entirely. Then it doesn't matter what the content of your variables is, and you're not leaving yourself potentially vulnerable to SQL injection attacks.
INSERT INTO similar (product_id, product_name) VALUES (l_product_id, l_desc);
I can't imagine off the top of my head why you would, but if you absolutely must use EXECUTE IMMEDIATE, then do it this way using bind variables:
l_sql := 'INSERT INTO similar (product_id, product_name) VALUES ( :x, :y )';
EXECUTE IMMEDIATE l_sql USING l_product_id, l_desc;
Either way your "special character" problem should go away.

Related

How to use this execute immediate create table to insert values in table

I am using execute immediate to create table and use this table into my code to insert some values when i run this code .it gives me error that table and view does not exist.why?. this code has ability to create table because when i use drop and create table command with existing table by using execute immediate then my code works fine and when i just remove drop table syntax, my code does not work, Please help me to clear my concept about dynamic SQL-----------
SET serveroutput ON
DECLARE
ddl_table VARCHAR2(200);
r_emp SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST();
v_array SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST('ACCT_ID',
'PARENT_ACCT_ID',
'CUST_ID',
'ACCT_NAME',
'BILLING_CYCLE_TYPE',
'PAID_FLAG',
'BILL_DELIVER_METHOD');
BEGIN
ddl_table := 'CREATE TABLE test123(
v_column VARCHAR2(50),
v_count NUMBER
)';
EXECUTE IMMEDIATE ddl_table;
DBMS_OUTPUT.ENABLE;
FOR i IN 1 .. v_array.COUNT LOOP
r_emp.EXTEND;
EXECUTE IMMEDIATE 'SELECT COUNT(*)
FROM account_profile
WHERE NOT REGEXP_LIKE(' ||v_array(i) || ',''[A-Za-z0-9.]'')'
INTO r_emp(i);
IF r_emp(i) <> 0 THEN
DBMS_OUTPUT.PUT_LINE(v_array(i) || ': ' || r_emp(i));
INSERT INTO test123 VALUES (v_array(i), r_emp(i));
END IF;
END LOOP;
END;
/
Error report -
ORA-06550: line 24, column 17:
PL/SQL: ORA-00942: table or view does not exist
Your problem is that the annonymous block is pre-validated (pre-compiled) before it is valid. Oracle will check all objects in use before executing it. Since you are creating test123 dynamically it doesn't exist so your insert statement fails.
You can instead, use an EXECUTE IMMEDIATE command to also insert the data on your test123 table.
The way you use the EXECUTE IMMEDIATE for an insert command is either concatenating the parameters or preparing them, I prefer the later. Like this
execute immediate 'insert into test123 values (:param1,:param2)' using v_array(i), r_emp(i);
Here is the official documentation for the EXECUTE IMMEDIATE command.
Though it shows how it works and explain the usage of it, it doesn't particularly answer you direct question on the comments.
So
can you explain :param1,:param2
Those are called "binding" parameters that will be replaced by the variables used after the using statement. It doesn't matter their name only the order in which they appear on the string. The number of parameters within the dynamic string needs to match the number of parameters after the using statement.
why we use it with : colon and what are these
The colon : there is just to make it easier for the parser to know what to replace and where when using the variables you provided after the using statement
Translating that execute immediate it would be something like this:
... values (:param1,:param2)' using v_array(i), r_emp(i)
Hey "execute immediate" whenever you see :param1 please replace it with the content of the variable I'm providing as v_array(i) and whenever you see :param2 please replace it with the content of the variable I'm providing as r_emp(i)

Single quote in execute immediate variable - Oracle PLSQL

I have a stored procedure which has:
execute immediate 'SELECT COUNT(S_NM) FROM '||lc_s_d_tb_nm||' WHERE S_NM IN('''||in_s_nm||''') AND '||lc_s_t_col||'='''||in_s_type||''' ' into lc_s_count;
The parameter in_s_nm is being sent by another function and one of the value is - Test - Mother's Identifier
Because of ' (apostrophe), my sql is not working.
How can I fix it so it works?
You should stop right there.. Don't use, I repeat, don't ever use concatenation of values in a dynamic SQL ( except for Table and column names or for educational purposes :-; ). It is vulnerable to SQL Injection and it could become a security threat.
Your query should be rewritten as
EXECUTE IMMEDIATE 'SELECT COUNT(S_NM) FROM '||lc_s_d_tb_nm||'
WHERE S_NM = :s_nm
AND '||lc_s_t_col||'= :s_type' into lc_s_count USING in_s_nm,in_s_type;
DEMO
Just use replace(in_s_nm, '''', '''''') instead of in_s_nm.
In 10g Oracle introduced the Quote Operator as an alternative or rather an extension that eliminates, at least most if not all, of that double quotation problem. For example try:
select q'/this is a single quote ', and this a double '' and even a triple '''/' from dual
union all
select 'this is a single quote '', and this a double '''' and even a triple ''''''' from dual;
I think you'll find the first much easier to deal with than the second although they produce the same result.

Getting table data with execute immediate in a loop

I am trying to extract data from tables. The names of multiple tables can be given as comma separated values (like a,b,c) and based on that I need to extract the data into a file. Here is the code, which is run through SQL*Plus:
declare
p_schema_name varchar2(1000) := '&1';
p_table_names varchar2(4000) := '&2';
p_statement varchar2(4000);
begin
p_statement := 'select * from :x'||'.'||':y';
for foo in (
select
regexp_substr (replace(p_table_names, ' ', ''), '[^,]+', 1, level) as txt
from dual
connect by
regexp_substr (replace(p_table_names, ' ', ''), '[^,]+', 1, level) is not null)
loop
execute immediate p_statement using p_schema_name, foo.txt;
end loop;
end;
When I execute this script then I get the following error:
ORA-00903: invalid table name
ORA-06512: at line 14
Where I am doing wrong?
You can only bind variables, not object names. The bind substitution is done when your query is executed, not when it is parsed. The object names have to be known at parse time.
You have to concatenate the schema and table name into the query:
...
begin
p_statement := 'select * from ';
...
execute immediate p_statement || p_schema_name ||'.'|| foo.txt;
end loop;
end;
Of course that now has the potential for SQL injection, so you need to sanitise the inputs. You can check if they are valid names, or check the extracted tables exist in the specified schema before trying to execute the query. You might find the DBMS_ASSERT package useful.
Although your query won't actually be executed at the moment; from the documentation:
If dynamic_sql_statement is a SELECT statement, and you omit both into_clause and bulk_collect_into_clause, then execute_immediate_statement never executes.
You need to select your data into something, which is going to be tricky if the tables that can be passed in have different structures. If you plan to write the queried data into a file and don't know the structure then you need to use the DBMS_SQL package rather then execute immediate.
Table names and Column names cannot be passed as Bind variables to an Execute immediate statement!
Instead use them as variables and concatenate them.
But then the other error would be that you are missing an INTO clause for the Execute immediate statement processing a SELECT statement as said by the other contributor.
Thanks,
B
As per your question how you are going to handle the output of SELECT * query from PLSQL. I guess you either need to have a ref cursor to anyway use this. Also as per your code if you loop through multiple tables the output will be always overwritten by the next one so you will get the last query output only.
So for this spool the output in a file and iterate to next table.
Hope this info helps.

Defining variable for repeated use in PL/SQL anonymous blocks

I am using Oracle SQL Developer.
I have an anonymous block that drops a table if it exists.
I don't have permission to create procedures or functions, so I have to call the anonymous block repeatedly.
To simplify things, I would like to store the names of all the affected tables in variables at the beginning of my script, and then refer to the appropriate variables later.
DEFINE v_InputTable = 'Table Name';
DECLARE
InputTable VARCHAR2(80) := &v_InputTable;
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ' || InputTable;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
/
When I try this, I get an error "PLS-00103: Encountered the symbol "TABLE" when expecting one of the following:..."
Can someone please explain what I am doing wrong.
Substitution variables are replaced in a fairly simplistic way. You have to enclose your references to strings within single quotes, where they become a literal. Instead of what you have, that becomes:
DECLARE
InputTable VARCHAR2(80) := '&v_InputTable';
You don't really need the PL/SQL variable here, you can use the substitution variable directly in the dynamic statement (still within a quoted string):
DEFINE v_InputTable = 'Table Name';
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE &v_InputTable';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
/
You can also define a bind variable with the variable command, rather than define, but for this usage a substitution is probably simpler.
You could run that drop comand statically as plain SQL of course, but I guess you want to hide the table-not-found error.
The error suggests your defined value is actually literally 'Table Name', which is an invalid name anyway unless you treat it as a quoted identifier - and it's really better not to do that. But if you must, or are playing around to see how they work, remember the case is fixed too, and every reference to it has to be identical and quoted. If you are trying to drop (and then recreate?) a table with a space in the name, you'd need to wrap the value in double quotes:
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE "&v_InputTable"';
... or if you want a separate variable and concatenate the dynamic statement:
DECLARE
InputTable VARCHAR2(80) := '"&v_InputTable"';

I Need to Insert a multiple tables data into single table using below code i tried but i have error

If i type my source tables name, data are copy into our target table:
'Create or Replace procedure p
(source_tab varchar2,target_tab varchar2)
As
query varchar2(200);
Type I_tab is table of varchar2(100000) index by binary_integer;
Rec_i I_tab;
Begin
query=’select * from’||source_tab;
Execute immediate query bulk collect into rec_i;
Forall i in rec_i.first..rec_i.last
Execute immediate’insert into’||target_tab||’values’||rec_i(i);
Commit;
End;
/
In the absence of anything useful like the actual compilation or runtime errors are we can do is guess.
As it happens your code has several obvious bloomers.
You appear to be using MS Word type smart quotes ’ whereas Oracle expects regular ASCII dumb quotes '. So that would be a compilation error.
The maximum size of a VARCHAR2 is 32767 so your nested table statement will hurl a compilation error.
You need to put spaces around the key words in the dynamic SQL. Otherwise you'll get a runtime error. So ’insert into’||target_tab||’values’ needs to 'insert into '||target_tab||' values ' . Make sure you check all the strings.
In PL/SQL the assignment operator is :=; = is the test for equality.
Less obvious, but we can't use EXECUTE IMMEDIATE in a FORALL. It's not a programmatic loop, and it needs to be a DML (SQL) statement: EXECUTE IMEMDIATE is PL/SQL. However you can do the same thing with
execute immediate
'insert into '|| target_tab ||
' select * from '|| source_tab

Resources