plsql - dynamically change table name in cursor - sql

i'm getting below error while running the procedure. is the select correct.. trying to pass table name as parameter. Pls help.
PLS-00364: loop index variable 'CURSOR1' use is invalid
PROCEDURE generate_uniqueId(p_table_name IN VARCHAR2) is
--
--
CURSOR unique_id_cur
IS
SELECT /*PARALLEL(20)*/ unique_id
FROM p_table_name;
--
v_file UTL_FILE.file_type;
V_file_name Varchar2 (150);
V_file_parm Varchar2:= ora11g/test/;
v_output varchar2(200);
BEGIN
v_file_name := p_table_name || '.lst';
v_file := UTL_FILE.fopen ('ora11g/test/', 'unique_ID_file', 'A');
FOR cursor1 IN unique_id_cur
LOOP
BEGIN
v_output := cursor1.unique_id;
UTL_FILE.put_line (v_file, v_output);
END;
END LOOP;
UTL_FILE.fflush (v_file);
UTL_FILE.fclose (v_file);
END generate_uniqueId ;

Your PL/SQL code having many syntax issue.
You can pass the table name in cursor declaration in form of "from p_table_name".
CURSOR unique_id_cur
IS
SELECT /*PARALLEL(20)*/ unique_id
FROM p_table_name;
If you are using "VARCHAR2" data type then you have to provide the length of data should contain a variable. Also the string "ora11g/test/" should kept in single quota -'- as 'ora11g/test/'
V_file_parm Varchar2:= ora11g/test/;
The directory that you are passing, am not sure whether it is going to accept or not. But, should create a logical directly in Oracle using "CREATE DIRECTORY" and then pass the newly directory created in "UTL_FILE.FOPEN".
Here is the sample idea to create a procedure that will compile and work for you, create or real procedure like below.
create or replace PROCEDURE generate_uniqueId(p_table_name IN VARCHAR2 default 'abc')
as
CURSOR unique_id_cur
IS
SELECT object_id as unique_id
FROM all_tables
where rownum <=5;
v_file UTL_FILE.file_type;
V_file_name Varchar2(150);
V_file_parm Varchar2(200) := 'ora11g/test/';
v_output varchar2(200);
BEGIN
v_file_name := p_table_name || '.lst';
v_file := UTL_FILE.fopen ('ora11g/test/', 'unique_ID_file', 'A');
FOR cursor1 IN unique_id_cur
LOOP
BEGIN
v_output := cursor1.unique_id;
UTL_FILE.put_line (v_file, v_output);
END;
END LOOP;
UTL_FILE.fflush (v_file);
UTL_FILE.fclose (v_file);
END generate_uniqueId ;
EDIT-1
create or replace PROCEDURE generate_uniqueId(p_table_name IN VARCHAR2 default 'abc')
as
type t1 is table of varchar2(255) index by pls_integer;
v_unique_ids t1;
v_sql varchar2(4000);
v_file UTL_FILE.file_type;
V_file_name Varchar2(150);
V_file_parm Varchar2(200) := 'ora11g/test/';
v_output varchar2(200);
BEGIN
v_file_name := p_table_name || '.lst';
v_file := UTL_FILE.fopen ('ora11g/test/', 'unique_ID_file', 'A');
v_sql := 'select /* PARALLEL(20) */ unique_id from '|| p_table_name;
execute immediate v_sql bulk collect into v_unique_ids;
FOR cursor1 IN v_unique_ids.first..v_unique_ids.last
LOOP
BEGIN
v_output := v_unique_ids(cursor1);
UTL_FILE.put_line (v_file, v_output);
END;
END LOOP;
UTL_FILE.fflush (v_file);
UTL_FILE.fclose (v_file);
END generate_uniqueId ;

Related

How to use "Where" clause in Oracle database (stored procedures)

I am using the following stored procedures in an Oracle database to export the output of the query to a CSV file.
CREATE OR REPLACE PROCEDURE run_query(p_tbl_name IN VARCHAR2
) IS
Select_Stmt VARCHAR2(100) := 'select * from '||p_tbl_name;
p_dir VARCHAR2 (100) := 'DATA_PUMP_DIR';
v_finaltxt VARCHAR2(4000);
v_v_val VARCHAR2(4000);
v_n_val NUMBER;
v_d_val DATE;
v_ret NUMBER;
c NUMBER;
d NUMBER;
col_cnt INTEGER;
f BOOLEAN;
rec_tab DBMS_SQL.DESC_TAB;
col_num NUMBER;
v_fh UTL_FILE.FILE_TYPE;
BEGIN
c := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(c, Select_Stmt, DBMS_SQL.NATIVE);
d := DBMS_SQL.EXECUTE(c);
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
FOR j in 1..col_cnt
LOOP
CASE rec_tab(j).col_type
WHEN 1 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000);
WHEN 2 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_n_val);
WHEN 3 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_d_val);
ELSE
DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000);
END CASE;
END LOOP;
-- This part outputs the HEADER
v_fh := UTL_FILE.FOPEN(upper(p_dir),p_tbl_name||'.csv','w',32767);
FOR j in 1..col_cnt
LOOP
v_finaltxt := ltrim(v_finaltxt||','||lower(rec_tab(j).col_name),',');
END LOOP;
UTL_FILE.PUT_LINE(v_fh, v_finaltxt);
-- This part outputs the DATA
LOOP
v_ret := DBMS_SQL.FETCH_ROWS(c);
EXIT WHEN v_ret = 0;
v_finaltxt := NULL;
FOR j in 1..col_cnt
LOOP
CASE rec_tab(j).col_type
WHEN 1 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
v_finaltxt := ltrim(v_finaltxt||',"'||v_v_val||'"',',');
WHEN 2 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_n_val);
v_finaltxt := ltrim(v_finaltxt||','||v_n_val,',');
WHEN 3 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_d_val);
v_finaltxt := ltrim(v_finaltxt||','||to_char(v_d_val,'DD/MM/YYYY HH24:MI:SS'),',');
ELSE
DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
v_finaltxt := ltrim(v_finaltxt||',"'||v_v_val||'"',',');
END CASE;
END LOOP;
-- DBMS_OUTPUT.PUT_LINE(v_finaltxt);
UTL_FILE.PUT_LINE(v_fh, v_finaltxt);
END LOOP;
UTL_FILE.FCLOSE(v_fh);
DBMS_SQL.CLOSE_CURSOR(c);
END;
/
The above stored procedure is working perfectly and I got the output by using the following script to run this stored procedure
exec run_query person_list;
Here stored_procedure_name is run_query and the table_name is person_list.
Now my question is that how can I use the WHERE clause after the select statement on "line 3" -
Select_Stmt VARCHAR2(100) := 'select * from '||p_tbl_name;
or are there any other ways I can use the where clause.
Thanks in advance.
Select_Stmt VARCHAR2(100) := 'select * from '||p_tbl_name||' where name=''david''';
You have to have the character delimiters; and since you have it inside quotes you have to duplicate them.

I want to create a table and insert a row in same table during run time using dynamic sql

I have created a procedure that accepts table name, 2 column names and 2 values that needed to be inserted on create table.
create or replace procedure SP_TABLE(P_TAB IN VARCHAR2,P_COL_1 IN VARCHAR2,P_COL_2 VARCHAR2,P_ID IN NUMBER,P_NAME IN VARCHAR2)
AS
v_sql varchar2(2000);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE '||P_TAB||' ('||P_COL_1||' NUMBER, '||P_COL_2 ||' VARCHAR2(20))';
v_sql := 'insert into ' ||P_TAB||'values (:1,:2)';
EXECUTE IMMEDIATE v_sql USING P_ID,P_NAME;
END;
/
The procedure was successfully created without any errors. However when i ran the below script i got error like 'ORA-00928: missing SELECT keyword
ORA-06512: at "SQL_PXADYXDREZPVPJSALLEGOZJOB.SP_TABLE", line 7'.
DECLARE
V_TAB VARCHAR2(20) := 'TABLE1';
V_COL1 VARCHAR2(20) := 'ID';
V_COL2 VARCHAR2(20) := 'NAME';
V_ID NUMBER := 1;
V_NAME VARCHAR2(20):= 'RAJA';
BEGIN
SP_TABLE(V_TAB,V_COL1,V_COL2,V_ID,V_NAME);
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_STACK);
END;
/
some one help me with this.
You can add space before values
create or replace procedure SP_TABLE(P_TAB IN VARCHAR2,P_COL_1 IN VARCHAR2,P_COL_2 VARCHAR2,P_ID IN NUMBER,P_NAME IN VARCHAR2)
AS
v_sql varchar2(2000);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE '||P_TAB||' ('||P_COL_1||' NUMBER, '||P_COL_2 ||' VARCHAR2(20))';
v_sql := 'insert into ' ||P_TAB||' values (:1,:2)';
EXECUTE IMMEDIATE v_sql USING P_ID,P_NAME;
END;
/

PL/SQL error : identifier 'NAME' must be declared

I have to call a procedure from a package p_name but it gives error as identifier 'NAME' must be declared
DECLARE
V V_NAME;
V1 VARCHAR2(30);
v_sql VARCHAR2(4000);
BEGIN
SELECT PROCEDURE_NAME BULK COLLECT INTO V from ALL_PROCEDURES
where OBJECT_NAME='p_name';
FOR I IN 1..V.COUNT LOOP
name:='p_name';
v_sql:='begin'||name||'.'||V(I)||';'||'END;';
EXECUTE IMMEDIATE v_sql;
END LOOP;
END;
If this is the only problem, it should be ok like so:
DECLARE
V V_NAME;
V1 VARCHAR2(30);
NAME VARCHAR2(7);
v_sql VARCHAR2(4000);
BEGIN
SELECT PROCEDURE_NAME BULK COLLECT INTO V from ALL_PROCEDURES where
lower(OBJECT_NAME)='p_name';
FOR I IN 1..V.COUNT LOOP
name:=' p_name';
v_sql:='begin'||name||'.'||V(I)||';'||'END;';
EXECUTE IMMEDIATE v_sql;
END LOOP;
END;

DBMS_LOB.APPEND File is getting cut because of concatenation

I have the below block. I want to replace that concatenation and also have a records from the cursor in new line.
For small data set it works,but when the number of rows returned by the cursor is 600+ it cuts the file. I think its because of conversion of CLOB to Varchar2 when || is used.
How do I resolve it?
DECLARE
CURSOR cur IS
SELECT ID, CA_ID, STATUS,S_DATE, E_DATE FROM TEST; -- Here I have a big query
v_MESG CLOB := EMPTY_CLOB();
v_Interim CLOB := EMPTY_CLOB();
v_col VARCHAR2(500);
CRLF VARCHAR2(2) := CHR(13)||CHR(10);
v_fileHandler UTL_FILE.FILE_TYPE;
BEGIN
v_col:= '"ID","CA_ID","Status","S_Date","E_Date"'||CRLF;
dbms_lob.createtemporary(v_MESG, TRUE);
FOR v_cur IN cur LOOP
BEGIN
v_Interim := NULL;
v_Interim:= v_col||v_cur.ID||',"'||
v_cur.CA_ID||'","'||
v_cur.Status||'","'||
v_cur.S_Date||'","'||
v_cur.E_DATE||'"'||CRLF
;
DBMS_LOB.APPEND(v_mesg, v_Interim);
v_col := NULL;
END;
END LOOP;
v_fileHandler := UTL_FILE.FOPEN('XML_PROCESS_TEST',v_file_name , 'w');
UTL_FILE.PUT(v_fileHandler, v_MESG);
UTL_FILE.FCLOSE(v_fileHandler);
END;

Dynamically Identify Table (Table Identified by Variable)

I'm trying to create a procedure that will allow me to write an existing row to another table dynamically but the row declaration and insert-statement in the following snippet don't work. The error message indicates that the view hasn't been identified although outputting the target_table.table_name works just fine.
More will be added to the block later on - such as a column with the operation (e.g. INSERT or UPDATE). This is just a simple example and the last procedure (pass_reference) is used to trigger the procedure.
Any help would be much appreciated.
CREATE OR REPLACE PROCEDURE denormalize (new_cursor sys_refcursor, target_table_name varchar)
IS
target_table user_tables%rowtype;
sql_target_table varchar(200) := 'select * from user_tables where table_name = :target_table_name';
row target_table%rowtype;
BEGIN
execute immediate sql_target_table into target_table using target_table_name;
LOOP
fetch new_cursor into row;
exit when new_cursor%notfound;
insert into target_table values row;
commit;
END LOOP;
END denormalize;
/
CREATE OR REPLACE PROCEDURE pass_reference
AS
new_cursor sys_refcursor;
BEGIN
open new_cursor for select * from sales where sales_id=1;
denormalize(new_cursor, 'NEW_SALES');
END;
/
please check this code, it's not working only as for example, as you see for working columns in your cursor should be named as columns in destination table.
I take this code from package that create html table in mail base on view, hope you found this example useful
good luck
declare
in_view_name varchar2(30);
in_table_name varchar2(30) := 'your_new_table';
out_rc number;
out_rc_txt varchar2(1000);
l_cursor number;
l_sql varchar2(50) := 'select * from ' || in_view_name;
l_col_cnt binary_integer;
l_col_tab dbms_sql.desc_tab;
l_column_value varchar2(4000);
l_is_empty boolean := true;
l_insert_header varchar2(1000);
l_insert varchar2(32000);
begin
out_rc := 0;
out_rc_txt := 'OK';
l_cursor := dbms_sql.open_cursor;
dbms_sql.parse(l_cursor, l_sql, dbms_sql.native);
l_col_cnt := dbms_sql.execute(l_cursor);
dbms_sql.describe_columns(l_cursor, l_col_cnt, l_col_tab);
l_insert_header := 'insert into '||in_table_name||'(';
if l_col_cnt > 0 then
-- header
for i in l_col_tab.first .. l_col_tab.last loop
dbms_lob.append(l_insert_header, l_col_tab(i).col_name);
if i != l_col_tab.last then
dbms_lob.append(l_insert_header, ',');
end if;
dbms_sql.define_column(l_cursor, i, l_column_value, 4000);
end loop;
l_insert_header := l_insert_header || ') values(';
-- data
while dbms_sql.fetch_rows(l_cursor) > 0 loop
l_is_empty := false;
l_insert := l_insert_header;
for i in l_col_tab.first .. l_col_tab.last loop
dbms_sql.column_value(l_cursor, i, l_column_value);
l_insert := l_insert || '''' || l_column_value || ''','
if not in_attachment then
dbms_lob.append(out_table, l_td);
end if;
if (not in_attachment) or (l_column_value is not null) then
dbms_lob.append(out_table, nvl(l_column_value, l_nbsp));
end if;
if (not in_attachment) or (i != l_col_tab.last) then
dbms_lob.append(out_table, l_tdc);
end if;
end loop;
l_insert := substr(l_insert, 1, length(l_insert) - 1) || ')';
execute immediate l_insert;
end loop;
end if;
dbms_sql.close_cursor(l_cursor);
end;