Dynamic SQL Error with REPLACE double quotes to single quotes - sql

I want single quotes around the string. For example: select 'APPLE' from dual; will display - APPLE.
But I want output as APPLE. Below select gives desire output.
SELECT REPLACE('"'||'APPLE'||'"','"','''') from dual;
1st concat double quotes and then replace double quotes to single quotes.
The problem arises when I am trying to add this select in dynamic SQL.
Have tried adding quotes but no luck, please suggest. Thanks
CREATE OR REPLACE PACKAGE PORTAL AS
type ref_cursor is ref cursor;
END;
create or replace procedure SP_REPLACE_TEST(p_cursor out PORTAL.ref_cursor)
IS
TABLENM varchar2(200);
vsql2 varchar2(200);
BEGIN
TABLENM := 'APPLE';
vsql2 := 'select REPLACE('||'''"'''||'||'||TABLENM||'||'||'''"'''||''','''||'''"'''||''','''||') from DUAL';
open p_cursor for vsql2;
END;
VARIABLE resultSet REFCURSOR;
EXEC SP_REPLACE_TEST(:resultSet);
PRINT :resultSet;

Related

How to make a function that takes code like "SELECT * FROM SOME_TABLE" as an input and returns a table as an output?

I want to create a function that takes some code as an input (e.g. Select * FROM SOME_TABLE) and returns the result of a query as an output.
I want to use it in procedures in order to return tables as a result.
It should look like this:
BEGIN
--some procedure code
CREATE TABLE SOME_TABLE as Select * FROM ...;
Select * FROM table(my_function('Select * FROM SOME_TABLE'));
END;
Important tips:
The resulting table can have multiple columns, from 1 to +inft
The resulting table can have multiple rows, from 1 to +inft
So the size of a table can be both very small or very large.
The input query can have several where, having, partition, and other Oracle constructions.
I want to have a table as an output, not DBMS_OUTPUT.
I can't install any modules/applications, or use other languages hints. However, I can manually create types, functions, procedures.
I tried to search in the net but could not find a solution that meets all my expectations. The best link I've found was this:
https://sqljana.wordpress.com/2017/01/22/oracle-return-select-statement-results-like-sql-server-sps-using-pipelined-functions/
DBMS_SQL.RETURN_RESULT works if your "code" is a select query
DECLARE
l_cur SYS_REFCURSOR;
l_query VARCHAR2(4000) := 'select * from SOME_TABLE';
BEGIN
OPEN l_cur for l_query;
DBMS_SQL.RETURN_RESULT(l_cur);
END;
/
you can create a function that has a string as parameter and return a cursor.
select statement you should pass as a string. in a function you can open a Cursor.
declare
v_sql varchar2(100) := 'select 1,2,3,4,5 from dual';
cur_ref SYS_REFCURSOR;
function get_data(in_sql in varchar2) return SYS_REFCURSOR
as
cur_ret SYS_REFCURSOR;
begin
OPEN cur_ret FOR in_sql;
return cur_ret;
end;
begin
:cur_ref := get_data(v_sql);
end ;
if your select statement is longer than 32K than you maybe should use a clob instead of varchar2 for your Parameter type. But you have to try that

Pass SQL string to oracle stored procedure and get results with execute immediate

I am trying to pass in a SQL string to a stored procedure and using EXECUTE IMMEDIATE to return the results. Something like this:
CREATE PROCEDURE P360_RCT_COUNT (sqlString IN VARCHAR2)
AS
BEGIN
EXECUTE IMMEDIATE sqlString;
END;
/
I am not sure how to accomplish it. With the above, when I execute the SP using the command below, I get an error:
EXECUTE P360_RCT_COUNT 'SELECT COUNT(DISTINCT ENTITY_ID),ADDR_COUNTY FROM P360_V_RCT_COUNT GROUP BY ADDR_COUNTY';
The error is: ORA-06550: line 1, column 22:
PLS-00103: Encountered the symbol "SELECT COUNT(ENTITY_ID),ADDR_COUNTY
FROM P360_V_RCT_COUNT GROUP " when expecting one of the following:
:= . ( # % ; The symbol ":=" was substituted for "SELECT
COUNT(DISTINCT ENTITY_ID),ADDR_COUNTY FROM P360_V_RCT_COUNT GROUP " to
continue.
Basically I am building a SQL string in a system and need to pass it in to the SP and get the results back to the system. I am relatively new to stored procedures in Oracle.
The easiest way to work with a result set is sys_refcursor. This can be used quite easily with JDBC or ODBC.
Your procedure would look like this:
CREATE PROCEDURE P360_RCT_COUNT (
sqlString IN VARCHAR2
, p_result_set out sys_refcursor)
AS
BEGIN
open p_result_set for sqlString;
END;
/
Obviously the precise details of how you call it will vary according to your client. But in SQL*Plus it would be:
var rc refcursor
exec P360_RCT_COUNT( 'SELECT COUNT(DISTINCT ENTITY_ID),ADDR_COUNTY FROM P360_V_RCT_COUNT GROUP BY ADDR_COUNTY', :rc);
print rc
To return lists of values in a OUT parameter you need to decide the type(s) to use.
Say, for example, you have to return some varchar2 and some date lists, you could use something like this:
create or replace type tabOfVarchar2 is table of varchar2(100);
create or replace type tabOfDates is table of date;
create or replace procedure testProc(pString IN varchar2,
pOutVarchar1 OUT tabOfVarchar2,
pOutVarchar2 OUT tabOfVarchar2,
pOutVarchar3 OUT tabOfVarchar2,
pOutDates OUT tabOfDates
) is
begin
execute immediate pString
bulk collect into pOutVarchar1, pOutVarchar2, pOutVarchar3, pOutDates;
end;
This is way you can test this procedure:
declare
v1 tabOfVarchar2 ;
v2 tabOfVarchar2;
v3 tabOfVarchar2;
d1 tabOfDates ;
vSQL varchar2(100) := 'select ''a'', ''b'', ''c'', sysdate from dual';
begin
testProc(vSQL, v1, v2, v3, d1);
--
for i in v1.first .. v1.last loop
dbms_output.put_line(v1(i) || '/' || v2(i) || '/' || v3(i) || '/' || to_char(d1(i), 'dd/mm/yyyy'));
end loop;
end;
which gives:
a/b/c/14/04/2017
This only works with queries that give exactly a fixed number of columns, of known types.

comma separated parameter in plsql stored procedure

create or replace procedure PROC_MYDATA (inputStr IN VARCHAR2,
p_RecordSet IN OUT SYS_REFCURSOR) is
begin
OPEN p_RecordSet FOR
(select * from myTable where name in (inputStr));
end PROC_MYDATA;
In the PLSQL Test window, I am trying to set,
inputStr = 'A','B'
and I am getting this error:
ORA-01722: invalid number
I also tried to put escape character for single quote.
inputStr = '''A''','''B'''
Same error.
Can someone please help me understand what am I doing wrong?
I'm afraid it doesn't work this way:
SELECT * from myTable where name in (inputStr);
You can use dynamic SQL, as in #Bob Jarvis' answer, or you can do the following:
SELECT * FROM myTable WHERE REGEXP_LIKE(name, '^(' || REPLACE(inputStr, ',', '|') || ')$');
The difficulty with the latter is that, in Oracle, a regular expression can be at most 512 bytes long. So your inputStr would be limited to 508 bytes (since we're adding four bytes for the anchors and the grouping).
To use a list of comma-separated values you'll need to build and execute the statement dynamically:
create or replace procedure PROC_MYDATA (inputStr IN VARCHAR2,
p_RecordSet IN OUT SYS_REFCURSOR)
is
strSql VARCHAR2(32767);
begin
strSql := 'select * from myTable where name in (' || inputStr || ')';
OPEN p_RecordSet FOR strSql;
end PROC_MYDATA;
You should use this with a string which contains the single-quote characters in it to delimit each string; thus, use
DECLARE
inputStr VARCHAR2(100);
csrCursor SYS_REFCURSOR;
BEGIN
inputStr = '''A'', ''B''';
PROC_MYDATA(inputStr, csrCursor);
-- ...code to use csrCursor;
CLOSE csrCursor;
END;
Share and enjoy.
This is faster
SELECT * from myTable where name in (select regexp_substr(inputStr,'[^,]+', 1, level) from dual
connect by regexp_substr(inputStr, '[^,]+', 1, level) is not null);

'insert into' in 'execute immediate' clause

Can you check this and tell me why I've got an error, please? How should it look? I have no idea what's wrong here. I need to create a table in a function, and in the same function insert data into this table:
create or replace
function new_tab ( pyt IN varchar2) return number
IS
a number;
b varchar2(20);
begin
a:= ROUND(dbms_random.value(1, 3));
b:='example';
-- This works perfect
execute immediate 'CREATE TABLE create_tmp_table'|| a ||'(i VARCHAR2(50))';
-- Here`s the problem
execute immediate 'insert into create_tmp_table'||a|| 'values ('|| b ||')';
exception
when others then
dbms_output.put_line('ERROR-'||SQLERRM);
return 0;
end;
My result is:
ERROR-ORA-00926: missing VALUES keyword. Process exited.
Where is the mistake?
As you are creating a dynamic insert command you have to create it as is. So you are missing the single quotes for the value that is varchar:
execute immediate
'insert into create_tmp_table'||a|| ' values ('''|| b ||''');';
^here ^and here
And a good suggestion for this type of error is to do some debug. On your case you could create a varchar2 variable and put your insert on it then you use the dbms_output.put_line to this variable. Then you will have your sql command that you can test direct on your database. Something like:
declare
sqlCommand varchar2(1000);
--define a and b
begin
--put some values in a and b
sqlCommand := 'insert into create_tmp_table'||a|| ' values ('''|| b ||''');';
dbms_output.put_line(sqlCommand);
end;
Then you will know what is wrong with the dynamic command.
execute immediate 'insert into TABLE'||a||' (COLUMN_NAME) values (:val)' using b;
This way you don't have to bother with escaping your values (SQL-injection hack) and correctly casting the type.
http://docs.oracle.com/cd/B13789_01/appdev.101/b10807/13_elems017.htm

Stored Procedure outputting String and Cursor

Hey guys, I have a stored procedure that outputs just the column of a table. Instead, I'd like to have 'There are' [column count] 'students.' as an output. Example below.
CREATE OR REPLACE PROCEDURE active_students (arc in out sys_refcursor)
as
begin
open arc for select count(*) from student;
end;
This generates
Count(*)
30
would like it to read
There are 30 students.
Use:
CREATE OR REPLACE PROCEDURE JSU4290M.active_students (arc in out sys_refcursor)
AS
BEGIN
OPEN arc FOR
SELECT 'There are '|| COUNT(*) ||' students.' AS col
FROM STUDENT;
END;
The double pipe (||) is Oracle's (and now ANSI standard) means of concatenating strings. Oracle will implicitly convert the integer value to a string.