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.
Related
Here's an example. I get the list like this below
99X2H19JBF11534
16B4H5FHCA12592
ABE4H5FHAA08646
SE0753207527
PAK810869145
PAK810714143
PAK810547887
PAK810340854
PAK820090918
I then use concatenate in excel (and surround the list with quotes and commas) to run queries like below in Oracle SQL Developer.
select * from admin.repair
where repair_nbr in (
'99X2H19JBF11534',
'16B4H5FHCA12592',
'ABE4H5FHAA08646',
'SE0753207527',
'PAK810869145',
'PAK810714143',
'PAK810547887',
'PAK810340854',
'PAK820090918');
I was wondering if other people have an easier way to surround the list with quotes and commas in Oracle SQL developer.
If you got your list from a query, just drag and drop.
We'll not only quote the strings, we'll separate them with commas for you.
If you just have the text, SQL Developer also support block editing. Enable that on the Edit menu, then simply use down arrow to go through each line/curpos and select then paste the quotes.
Or if you're a fan of regex, the Search and Replace (ctrl+R) panel has a RegEx mode you can toggle on.
Disclaimer: I'm a product manager at Oracle for SQL Developer.
Assuming you got your list using query
select val from your_table order by whatever
change your query to
select 'select * from admin.repair where repair_nbr in ('
|| listagg('''' || val || '''', ',
' order by whatever)
|| ');'
from your_table
The result of auxiliar query is the query you require.
Note: You might get ORA-01489 if the result of concatenation is too long but it is different - yet still solvable - story (look for xmlagg function then).
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.
In Oracle, can a bind variable be put in IN() clause if it can be empty? Asking because in the SQL if Oracle see IN() without any data in it, it shows error
ORA-00936: missing expression.
Edit: Failed to mention that no PL/SQL can be used...
Edit2: Also failed to mention that the variable is either in format 1,2,3 or empty string. The empty string cannot be replaced with NULL.
Seems to be working:
declare
l_statement varchar2(32767);
begin
l_statement := 'select * from user_tables where table_name in (:a)';
execute immediate l_statement
using '';
end;
You can do it, it will be syntactically correct.
I hope you are aware that NULL is not equal to anything even to NULL (so NULL=NULL is not TRUE but NULL), it can cause unexpected results in your query, so consider using NVL function if it doesn't affect performance
I'm having the following problem with an old database. We migrated from sql to oracle recently and I'm having trouble with an insert statement where the column name is "default". Any ideas (I'm not allowed to change the column name, that would be by far the best solution!)?
It looks somehow like this, only with a billion more columns and it's inside a large if-when-else construction for validating issues, so I can't drop the execute immediate.
EXECUTE IMMEDIATE 'INSERT INTO trytable (ID, "DEFAULT") VALUES (''monkey1'', 0)'
I don't think the problem comes from your column name, as shown in this working example:
SQL> CREATE TABLE trytable (ID VARCHAR2(10), "DEFAULT" NUMBER);
Table created
SQL> BEGIN
2 EXECUTE IMMEDIATE
3 'INSERT INTO trytable (ID, "DEFAULT") VALUES (''monkey1'', 0)';
4 END;
5 /
PL/SQL procedure successfully completed
Technically, you can have a table column name named DEFAULT, even if it's generally a bad idea that will lead to confusion. You will only be able to interact with it through the double-quote " syntax because DEFAULT is a reserved word.
If you specify double quotes around identifiers, Oracle will treat them as case-sensitive, so you have to make sure that they match the table specs.
In your case, it would help to have the specific error message.
The below will executes if your column name is "DEFAULT":
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO TRYTABLE(ID, "DEFAULT")VALUES(''monkey1'',0)';
END;
"DEFAULT" and "default" makes difference.
I have many PL/SQL functions and procedures that execute dynamic sql.
Is it possible to extract the parsed statements and dbms_output as an debugging aid ?
What I really want is to see the parsed sql (sql statement with substituted parameters).
Example:
I have a dynamic SQL statement like this
SQ:='SELECT :pComno as COMNO,null t$CPLS,t$CUNO,t$cpgs,t$stdt,t$tdat,t$qanp,t$disc,:cS Source FROM BAAN.TTDSLS031'||PCOMNO --1
|| ' WHERE' ||' TRIM(T$CUNO)=trim(:CUNO)' --2
|| ' AND TRIM(T$CPGS)=trim(:CPGS)' --3
|| ' AND T$QANP = priceWorx.fnDefaultQanp ' --4
|| ' AND priceWorx.fdG2J(sysdate) between priceWorx.fdG2J(t$stdt) and priceWorx.fdG2J(t$tdat)' --5
|| ' AND rownum=1 order by t$stdt';--6
execute immediate SQ into R using
PCOMNO,'C' --1
,PCUNO-- 2
,PCPGS;-- 3
What will be the statement sent to the server ?
You can display the bind variables associated with a SQL statement like this:
select v$sql.sql_text
,v$sql_bind_capture.*
from v$sql_bind_capture
inner join v$sql on
v$sql_bind_capture.hash_value = v$sql.hash_value
and v$sql_bind_capture.child_address = v$sql.child_address
--Some unique string from your query
where lower(sql_text) like lower('%priceWorx.fdG2J(sysdate)%');
You probably would like to see the entire query, with all the bind variables replaced by their actual values. Unfortunately, there's no easy way to get exactly what you're looking for, because of the following
issues.
V$SQL_BIND_CAPTURE doesn't store all of the bind variable information. The biggest limitation is that it only displays data "when the bind variable is used in the WHERE or HAVING clauses of the SQL statement."
Matching the bind variable names from the bind capture data to the query is incredibly difficult. It's easy to get it working 99% of the time, but that last 1% requires a SQL and PL/SQL parser, which is basically impossible.
SQL will age out of the pool. For example, if you gather stats on one of the relevant tables, it may invalidate all queries that use that table. You can't always trust V$SQL to have your query.
Which means you're probably stuck doing it the ugly way. You need to manually store the SQL and the bind variable data, similar to what user1138658 is doing.
You can do this with the dbms_output package. You can enable and disable the debug, and get the lines with get_line procedure.
I tested with execute immediate, inserting in a table and it works.
I recently answered another question with a example of using this.
One possible solution of this is to create a table temp(id varchar2,data clob); in your schema and then put the insert statement wherever you want to find the parsed key
insert into temp values(seq.nextval,v_text);
For example
declare
v_text varchar2(2000);
begin
v_text:='select * from emp'; -- your dynamic statement
insert into temp values(seq.nextval,v_text); --insert this script whenever you want to find the actual query
OPEN C_CUR FOR v_text;
-----
end;
Now if you see the table temp, you'll get the data for that dynamic statement.