This question already has answers here:
PL/SQL, how to escape single quote in a string?
(5 answers)
Closed 1 year ago.
I have the below regular expression which works perfectly fine using sql, but the same cannot be included in dynamic sql qyery, have tried escaping all the character but it still throws error.
here is what I have tried:
reg := 'select regexp_replace(data, ||'\.||(docx|pdf|msg)|| ', ||'.\1, ') from table where id=1'
Can you help to include this within dynamic sql?
select regexp_replace(data, '\.(docx|pdf|msg) ', '.\1, ') from table where id=1;
It looks that single quotes bother you.
If so, use the q-quoting mechanism, such as:
SQL> declare
2 reg varchar2(500);
3 begin
4 reg := q'[select regexp_replace(data, ||'\.||(docx|pdf|msg)|| ', ||'.\1, ') from table where id=1]';
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
However, we use dynamic SQL when there's something dynamic. There's nothing dynamic in your query, so - why do you use it? Are you sure you need it? What is the "real" problem you're trying to solve? Maybe it doesn't require dynamic SQL at all.
Related
This question already has answers here:
Declaring & Setting Variables in a Select Statement
(5 answers)
Declare bind variables in SQL*Plus
(2 answers)
Closed 3 years ago.
I started a new job and needing to learn Oracle for the job. I am trying to convert this simple code so I can build more complex queries down the road
DECLARE #NPI = VARCHAR(20)
SET #NPI = '123456789'
SELECT *
FROM AFFILIATION
WHERE NPI = #NPI
I am trying to figure out to set parameters in Oracle and then use them in the WHERE statement or other places within the code.
I think I have figured out part of my question but not sure of the full conversion
DECLARE NPI1 varchar(20):= '123456789'
I am looking to set verables/parameters and use them later in the code. YES I dont need it in this query but If i know how to use it for the query I can build much more complex Oracle queries.
Use a bind variable:
VARIABLE npi VARCHAR2(20);
Then use PL/SQL to set its value:
BEGIN
:npi = '1234567890';
END;
/
or EXEC:
EXEC :npi = '1234567890';
Then you can use it in your query:
SELECT *
FROM AFFILIATION
WHERE NPI = :npi
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.
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.
This question already has answers here:
Parsing PL/SQL code to check against syntax and semantic errors
(4 answers)
Closed 6 years ago.
I would like to be able to validate that a piece of code is correct using only PL/SQL.
For example, I have the following code in a variable, I would like to validate it:
my_code:='BEGIN
package1.get_wordlist_keywords_PG;
package1.get_wordlist_keyword_cat_PG;
END;
'
I would like to do something like:
result:=validate_code(my_code);
and result would be "valid" or "invalid" (or with error message etc.)
I am sure this would be possible, as Oracle Apex allows users to enter PL/SQL and runs a validation on the code when it is saved.
I am on Oracle 12c.
Thanks!
P.S. - I do not need to validate a simple sql select, it needs to be a PL/SQL code block.
Probably put your code in a procedure instead of anonymous block.
CREATE OR REPLACE PROCEDURE p1 AS
BEGIN
package1.get_wordlist_keywords_PG;
package1.get_wordlist_keyword_cat_PG;
END;
/
show errors;
After the execution, the procedure may or may not be created successfully. Though the procedure is created successfully, the code inside the procedure
is not executed.
CREATE OR REPLACE PROCEDURE VALIDATE_PLSQL
(
PLSQL IN VARCHAR2
, MY_RESULT OUT VARCHAR2
) AS
my_code varchar2(31900);
validate_code varchar2(32000);
status varchar2(4000);
BEGIN
my_code:=PLSQL;
validate_code:='create or replace procedure testp1 AS '||my_code;
BEGIN
status:='PASSED';
EXECUTE IMMEDIATE validate_code;
exception
when OTHERS then
status:='FAILED';
END;
EXECUTE IMMEDIATE 'drop procedure testp1';
MY_RESULT:=status;
END VALIDATE_PLSQL;
Pass in the block to be validated in "PLSQL" get the results in "MY_RESULT"
Clunky, but works!
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.