Reputation: 33
I wrote a procedure that will automatically get the data from the given query and put the reuslt data set into a file in directory with delimiters. It works good for smaller queries like select * from table_1
but not for big queries like :
SELECT
i.row_id,
translate(i.x_notes_txt, chr(10)||chr(13)||'|' , ' '),
null
FROM communication i,
contact c
WHERE i.last_upd >= (SELECT to_char(last_updated_dt, 'DD-MON-YYYY')
FROM extract_status
WHERE extract_nm = 'INTN300')
AND i.last_upd < sysdate
AND i.x_interaction_type_cd NOT IN ('XRAC','FMS','ATV','IRL')
AND i.pr_con_id = c.row_id
AND c.x_Prospect_Ind = 'Y';
while calling procedure that accepts query procdure : - tab_to_flat('with_the_above_query')
it is showing errors like
1) PLS-00103: Encountered the symbol "|" .
2) Encountered the symbol "),
null
FROM communication i,
And many more ..Can anybody help how to pass these queries as a input????
/* Formatted on 06/06/2013 1:42:56 PM (QP5 v5.163.1008.3004) */
CREATE OR REPLACE FUNCTION tab_to_flat (input_query IN CLOB,
dir_name IN VARCHAR2,
file_name IN VARCHAR2,
seperator IN VARCHAR2)
RETURN NUMBER
IS
c_seperator VARCHAR2 (3) := ' ';
incoming_seperator VARCHAR2 (3) := seperator;
no_of_rows NUMBER;
rec_tab DBMS_SQL.DESC_TAB;
col_cnt INTEGER;
src_id INTEGER DEFAULT DBMS_SQL.open_cursor;
val_varchar VARCHAR2 (32767);
val_num NUMBER;
val_date DATE;
file_input UTL_FILE.file_type;
l_start NUMBER;
row_cnt NUMBER := 0;
BEGIN
l_start := DBMS_UTILITY.get_time;
file_input :=
UTL_FILE.fopen (dir_name,
file_name,
'w',
32767);
DBMS_SQL.parse (src_id, input_query, 1);
DBMS_SQL.describe_columns (src_id, col_cnt, rec_tab);
FOR i IN 1 .. col_cnt
LOOP
CASE (rec_tab (i).col_type)
WHEN 1
THEN
DBMS_SQL.define_column (src_id,
i,
val_varchar,
32767);
WHEN 2
THEN
DBMS_SQL.define_column (src_id, i, val_num);
--when 8 then dbms_sql.define_column_long(src_id,i);
WHEN 12
THEN
DBMS_SQL.define_column (src_id, i, val_date);
ELSE
DBMS_SQL.define_column (src_id,
i,
val_varchar,
32767);
END CASE;
END LOOP;
no_of_rows := DBMS_SQL.execute (src_id);
LOOP
EXIT WHEN (DBMS_SQL.FETCH_ROWS (src_id) <= 0);
c_seperator := ' ';
FOR j IN 1 .. col_cnt
LOOP
CASE (rec_tab (j).col_type)
WHEN 1
THEN
DBMS_SQL.COLUMN_VALUE (src_id, j, val_varchar);
UTL_FILE.put (file_input, c_seperator || val_varchar);
WHEN 2
THEN
DBMS_SQL.COLUMN_VALUE (src_id, j, val_num);
UTL_FILE.put (file_input, c_seperator || val_num);
-- when 8 then dbms_sql.column_value_long(src_id,j,4000,1);
WHEN 12
THEN
DBMS_SQL.COLUMN_VALUE (src_id, j, val_date);
UTL_FILE.put (
file_input,
c_seperator || TO_CHAR (val_date, 'MM/DD/YYYY HH24:MI:SS'));
ELSE
DBMS_SQL.COLUMN_VALUE (src_id, j, val_varchar);
UTL_FILE.put (file_input, c_seperator || val_varchar);
END CASE;
c_seperator := incoming_seperator;
END LOOP;
UTL_FILE.new_line (file_input);
row_cnt := row_cnt + 1;
END LOOP;
DBMS_SQL.close_cursor (src_id);
DBMS_OUTPUT.put_line (
'The execution time is : ' || (DBMS_UTILITY.get_time - l_start));
RETURN row_cnt;
EXCEPTION
WHEN OTHERS
THEN
IF (SQLCODE = -942)
THEN
DBMS_OUTPUT.put_line ('Please check the table_name');
ELSE
RAISE;
END IF;
END;
Upvotes: 3
Views: 750
Reputation: 191275
It looks like you just aren't escaping the quotes that are included in the query string, so you're calling it as
tab_to_flat('SELECT i.row_id, translate(i.x_notes_txt, chr(10)||chr(13)||'|' , ' '),...')
The single quote around the |
you're concatenating after the chr(13)
is the immediate problem, but there are others. You could either go through and carefully double-up every quote inside the string:
tab_to_flat('SELECT i.row_id, translate(i.x_notes_txt, chr(10)||chr(13)||''|'' , '' ''),...')
... or more readibly use the quoted value syntax:
tab_to_flat(q'[SELECT i.row_id, translate(i.x_notes_txt, chr(10)||chr(13)||'|' , ' '),...]')
... where the q'[ ... ]'
enclose your original string and allow you to use single quote marks without having to escape them. You just need to be sure that the actual query doesn't contain [
or ]
, or pick different delimiters if it does.
This says nothing about whether what you're doing is a good approach and if you can find a better way to approach your problem, and doesn't address SQL injection etc.; this is just to fix the problem with what you're currently calling and how you're doing it.
Upvotes: 3
Reputation: 632
What you can do is to use am oracle cursor like this :
FUNCTION SELECT_FROM_MY_TABLE(v_QUERY_TO_BE_EXECUTED VARCHAR2)
RETURN SYS_REFCURSOR
IS
c_my_cursor SYS_REFCURSOR;
BEGIN
OPEN c_my_cursor FOR
v_QUERY_TO_BE_EXECUTED -- When working with Ref Cursors, open-for can be used directly, instead of execute immediate.
RETURN c_my_cursor;
END SELECT_FROM_MY_TABLE;
So basically you have a function, that returns a cursor which contains the information from your query. When you use the cursor, you do it like this :
PROCEDURE procedure_use_cursor
IS
c_my_cursor SYS_REFCURSOR;
r_my_table_row my_table%ROWTYPE;
BEGIN
c_my_cursor := SELECT_FROM_MY_TABLE;
LOOP
FETCH c_my_cursor INTO r_my_table_row;
EXIT WHEN c_my_cursor%NOTFOUND ;
-- do what you want with r_my_table_row
END LOOP;
END procedure_use_cursor;
Upvotes: 0