Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I want to insert million of records into a file using oracle and without using a loop or java code.
while browsing I found something as util_file in oracle which is used to record rows into file but was unable to use it. can some please help me in understanding or writing the code to write the resultset returned by a select query into a file or even a procedure would even work.
I tried below procedure it run successfully but doesnot create file with data
create or replace procedure familydetails
( p_file_dir IN varchar2, p_filename IN varchar2 )
IS v_filehandle utl_file.file_type;
cursor family Is
select * from fmly_detl
begin
v_filehandle :=utl_file.fopen('C:\tempfolder','sqltest.txt','W');
utl_file.new_line(v_filehandle);
for fmly IN fmly_detl LOOP
utl_file.putf(v_filehandle,'family %s details:s\n',fmly.last_name,fmly.first_name,fmly.indv_id);
end loop;
utl_file.put_line(v_filehandle,'END OF REPORT');
UTL_FILE.fclose(v_filehandle);
end familydetails;
1) if you use sqlplus in unix.. Here is a simple solution, put the below as a script_name.ksh and execute it (ksh script_name.ksh)
sqlplus -s user_id/password#sid << ! >> ~/sql_output.txt
set feedback off;
set pages 0;
set linesize 20000;
set arraysize 1000;
set tab off;
--Your Query, with proper padding , or comma seprated
--Eg Select employee_id||'|'||employee_name||'|'||employee_age
-- from employee;
!
2) If you use a IDE like SQL Developer or TOAD, you can execute the Query and Export it.
3) But for PL/SQL
test_dir mentioned below, is a directory in the host machine , accessible to Oracle. It should be listed in *ALL_DIRECTORIES* dictionary table.
DECLARE
fileHandler UTL_FILE.FILE_TYPE;
cursor emp_cursor is select employee_id,employee_name,employee_age FROM employee;
TYPE emp_type IS TABLE OF emp_cursor%ROWTYPE INDEX BY PLS_INTEGER;
l_emp_type emp_type;
v_fetch_limit NUMbER := 10000;
BEGIN
fileHandler := UTL_FILE.FOPEN('test_dir', 'sql_output.txt', 'W',max_linesize => 4000);
open emp_cursor;
LOOP
FETCH emp_cursor BULK COLLECT INTO l_emp_type LIMIT v_fetch_limit;
EXIT WHEN l_emp_type.COUNT < v_fetch_limit;
// Used to control the fetch size.
FOR I IN 1..l_emp_type.COUNT LOOP
UTL_FILE.PUTF(fileHandler, '%s|%s|%s',l_emp_type(I).employee_id,
l_emp_type(I).employee_name,
l_emp_type(I).employee_age);
END LOOP;
UTL_FILE.FFLUSH(fileHandler);//Flush the buffer to file
END LOOP
UTL_FILE.FCLOSE(fileHandler);
IF(emp_cursor%ISOPEN) THEN
emp_cursor.close();
END IF;
EXCEPTION
WHEN utl_file.invalid_path THEN
raise_application_error(-20000, 'ERROR: Invalid PATH FOR file.');
IF(emp_cursor%ISOPEN) THEN
emp_cursor.close();
END IF;
END;
/
Finally, copy it from the UTL_FILE directory in Server.
The directory may be a NAS mount too. Just the Oracle need to have write access to it.
4) Like a PL/SQL, a Pro*C program, or Any OCI interface too will work! Generally, Options 3 and 4 gives you good control in the process you do!
Good Luck!
EDIT: Added improvements over fetch size and flushing
Related
I have a large source data set (a few million rows) that requires complex processing, resulting in much larger amount of data, which should be then offloaded and stored as files. The storage requires dividing up resulting data based on certain parameters, namely N source rows that meet certain criteria.
Since it's possible to compute the said parameters within PL/SQL, it was decided that the most efficient way would be to create a package, specify a spec-level cursor for source rows in it, then write a procedure that would partially consume the opened cursor until the criteria is meet and fill temporary tables with resulting data, which would then be offloaded, and the procedure would be called again, repeating until there's no more source rows. PL/SQL basically looks like this:
create or replace PACKAGE BODY generator as
cursor glob_cur_body(cNo number) is
select *
from source_table
where no = cNo
order by conditions;
procedure close_cur is
begin
if glob_cur_body%isopen then
close glob_cur_body;
end if;
end close_cur;
procedure open_cur(pNo number) is
begin
close_cur;
open glob_cur_body(pNo);
end open_cur;
function consume_cur return varchar2 is
v source_table%rowtype;
part_id varchar2(100);
begin
fetch glob_cur_body into v;
if glob_cur_body%notfound then
return null;
end if;
--Clear temporary tables
--Do the processing until criteria is meet of there's no more rows
--Fill the temporary tables and part_id
return part_id;
end consume_cur;
end generator;
And the consumer is doing the following (in pseudocode)
generator.open_cur;
part_id = generator.consume;
while ( part_id != null )
{
//offload data from temp tables
part_id = generator.consume;
}
generator.close_cur;
It's working fine, but unfortunately there's one problem: a spec-level cursor makes the package stateful, meaning that its recompilation results in ORA-04068 for sessions that already accessed it before. It makes maintenance cumbersome, because there's a lot more to the package besides said functions, and it's actively used for unrelated purposes.
So, I want to get rid of the spec-level cursor, but I'm not sure if that's possible. Some ideas I've already discarded:
Re-opening the cursor and skipping N rows: terrible performance, unreliable because affected by any changes to data made between opens
Fetching the source cursor into plsql table: size too large.
Filling up the entire unload tables at once, splitting them later: size too large, subpar performance.
Opening the cursor as refcursor and storing refcursor variable in a dedicated package: impossible, as pl/sql doesn't allow sys_refcursor variables at spec levels
Having open_cur procedures return refcursor, storing it in the offloader, and then somehow passing it to consume_cur: looked viable, but the offloader is in Java, and JDBC doesn't allow binding of SYS_REFCURSOR parameters.
Changing consume_cur to pipelined function: could have worked, but oracle buffers pipelined rows, meaning it would execute multiple times when fetching data from it row-by-row. Also counterintuitive.
Only other idea I've had so far is to make a dedicated package storing said cursor, having open and close procedures and get_cursor returning refcursor; then call get_cursor from generator.consume_cur. That would make the dedicated package (which is unlikely to change) stateful and main package stateless. However, it seems like a half-baked patch rather than a problem solution. Is there a more decent way of achieving what I need? Perhaps changing the logic completely without affecting performance and storage limits too much.
I have a problem to understand your question. But I can provide clarification for your ideas.
Opening the cursor as refcursor and storing refcursor variable in a
dedicated package: impossible, as pl/sql doesn't allow sys_refcursor
variables at spec levels
The workaround with dbms_sql.
create table test_rows as (select level rr from dual connect by level <= 100);
create or replace package cursor_ctx is
ctx_number integer;
end;
declare
p_cursor sys_refcursor;
begin
open p_cursor for 'select rr from test_rows';
cursor_ctx.ctx_number := DBMS_SQL.TO_CURSOR_NUMBER(p_cursor);
end;
This part consuming is data from the cursor.
declare
p_cursor sys_refcursor;
type l_number is table of number;
v_numbers l_number;
begin
if DBMS_SQL.IS_OPEN(cursor_ctx.ctx_number) then
p_cursor := DBMS_SQL.TO_REFCURSOR( cursor_ctx.ctx_number);
fetch p_cursor bulk collect into v_numbers limit 10;
if v_numbers.count < 10 then
dbms_output.put_line('No more data, close cursor');
close p_cursor;
cursor_ctx.ctx_number := null;
else
cursor_ctx.ctx_number := DBMS_SQL.TO_CURSOR_NUMBER(p_cursor);
end if;
for i in nvl(v_numbers.first,1) .. nvl(v_numbers.last,-1) loop
dbms_output.put_line(v_numbers(i));
end loop;
else
dbms_output.put_line('Null or cursor close ');
end if;
end;
Pipelined function has future to split input cursor into chunk. Parallel Enabled Pipelined Table Functions
JDBC allows using sys_refcursor as an output parameter. sys_refcursor = ResultSet.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
i am trying to create a table using below code.
set serveroutput on;
DECLARE
cursor c1 is select '''create table demo1 (demo varchar2(100))''' c2 from dual;
testvar c1%rowtype;
BEGIN
open c1;
fetch c1 into testvar;
close c1;
execute immediate testvar.c2;
END;
but it is giving
ORA-00900: invalid SQL statement
ORA-06512: at line 8
00900. 00000 - "invalid SQL statement"
What is wrong in this code.
You need nothing more than except these 3 lines of code if you really want to do it dynamically using a PLSQL block. No need for selecting from dual .
declare
vsql varchar2 (100) := 'create table demo1 (demo varchar2(100))';
begin
execute immediate vsql;
end;
Note: It does not makes any sense selecting create table statement from a select. If you have any other specific requirement, please mention so that people can help you here.
Btw, you block will work simplly once you remove the extra ' as mentioned by William
set serveroutput on;
DECLARE
cursor c1 is select 'create table demo1 (demo varchar2(100))' c2 from dual;
testvar c1%rowtype;
BEGIN
open c1;
fetch c1 into testvar;
close c1;
execute immediate testvar.c2;
END
;
I'm about to learn pl/sql and currently I'm not understanding whats going wrong with my code.
What I'm trying to do is to dynamically copy(backup) a specific table.
So easy thing: I already created a backupTable, because I will use that quite often actually.
So the first try was following:
EXECUTE IMMEDIATE 'INSERT INTO '||sSchema_||'.backupTable
SELECT * FROM '||sSchema_||'.table'
This doesnt work as one of the columns contains LONG datatype
Exception ORA-00997: illegal use of LONG datatype
So the next step was trying to pack the thing into a loop and fetch each row individually:
--Initialized as
TYPE cur_typ IS REF CURSOR;
cCursor cur_typ;
rRecord table%rowtype;
--Make sure cursor is closed
IF cCursor%ISOPEN THEN
CLOSE cCursor;
END IF;
--Run the copying
OPEN cCursor FOR 'SELECT * FROM '||sSchema_||'.table';
LOOP
FETCH cCursor INTO rRecord;
EXIT WHEN cCursor%NOTFOUND;
EXECUTE IMMEDIATE 'INSERT INTO '||sSchema_||'.updateTable 'VALUES rRecord';
END LOOP;
CLOSE cCursor;
Which is not being executed due to:
ORA-03001: unimplemented feature
After that I tried to use different other ways to write that loop e.g.
EXECUTE IMMEDIATE 'INSERT INTO '||sSchema_||'.updateTable 'VALUES :1' USING rRecord;
All with the same result: unimplemented feature.
So here comes the question: How do I create a dynamic copy of tables containg LONG datatype? Does anyone has any idea?
Thanks a lot in advance
donny
The target table should be using a LOB (CLOB or BLOB) type.
The LONG RAW datatype is provided for backward compatibility with existing applications. For new applications, use the BLOB and BFILE datatypes for large amounts of binary data.
Oracle also recommends that you convert existing LONG RAW columns to LOB columns. LOB columns are subject to far fewer restrictions than LONG columns. Further, LOB functionality is enhanced in every release, whereas LONG RAW functionality has been static for several releases.
Source: Oracle Database Concepts
CREATE TABLE a_table
(
long_col LONG
);
CREATE TABLE a_backupTable
(
clob_col VARCHAR2(4000)
);
INSERT INTO a_table VALUES ('a');
-- 1 rows inserted.
DECLARE
l_cur SYS_REFCURSOR;
l_long LONG;
BEGIN
OPEN l_cur FOR SELECT long_col FROM a_table;
LOOP
FETCH l_cur INTO l_long;
EXIT WHEN l_cur%NOTFOUND;
INSERT INTO a_backupTable VALUES(l_long);
END LOOP;
CLOSE l_cur;
COMMIT;
END;
-- anonymous block completed
SELECT * FROM a_backupTable;
-- a
This question is similar to a couple others I have found on StackOverflow, but the differences are signficant enough to me to warrant a new question, so here it is:
I want to obtain a result set from dynamic SQL in Oracle and then display it as a result set in a SqlDeveloper-like tool, just as if I had executed the dynamic SQL statement directly. This is straightforward in SQL Server, so to be concrete, here is an example from SQL Server that returns a result set in SQL Server Management Studio or Query Explorer:
EXEC sp_executesql N'select * from countries'
Or more properly:
DECLARE #stmt nvarchar(100)
SET #stmt = N'select * from countries'
EXEC sp_executesql #stmt
The question "How to return a resultset / cursor from a Oracle PL/SQL anonymous block that executes Dynamic SQL?" addresses the first half of the problem--executing dynamic SQL into a cursor. The question "How to make Oracle procedure return result sets" provides a similar answer. Web search has revealed many variations of the same theme, all addressing just the first half of my question. I found this post explaining how to do it in SqlDeveloper, but that uses a bit of functionality of SqlDeveloper. I am actually using a custom query tool so I need the solution to be self-contained in the SQL code. This custom query tool similarly does not have the capability to show output of print (dbms_output.put_line) statements; it only displays result sets. Here is yet one more possible avenue using 'execute immediate...bulk collect', but this example again renders the results with a loop of dbms_output.put_line statements. This link attempts to address the topic but the question never quite got answered there either.
Assuming this is possible, I will add one more condition: I would like to do this without having to define a function or procedure (due to limited DB permissions). That is, I would like to execute a self-contained PL/SQL block containing dynamic SQL and return a result set in SqlDeveloper or a similar tool.
So to summarize:
I want to execute an arbitrary SQL statement (hence dynamic SQL).
The platform is Oracle.
The solution must be a PL/SQL block with no procedures or functions.
The output must be generated as a canonical result set; no print statements.
The output must render as a result set in SqlDeveloper without using any SqlDeveloper special functionality.
Any suggestions?
The closest thing I could think of is to create a dynamic view for which permission is required. This will certainly involve using a PL/SQL block and a SQL query and no procedure/function. But, any dynamic query can be converted and viewed from the Result Grid as it's going to be run as a select query.
DEFINE view_name = 'my_results_view';
SET FEEDBACK OFF
SET ECHO OFF
DECLARE
l_view_name VARCHAR2(40) := '&view_name';
l_query VARCHAR2(4000) := 'SELECT 1+level as id,
''TEXT''||level as text FROM DUAL ';
l_where_clause VARCHAR2(4000):=
' WHERE TRUNC(1.0) = 1 CONNECT BY LEVEL < 10';
BEGIN
EXECUTE IMMEDIATE 'CREATE OR REPLACE VIEW '
|| l_view_name
|| ' AS '
|| l_query
|| l_where_clause;
END;
/
select * from &view_name;
You seem to be asking for a chunk of PL/SQL code that will take an arbitrary query returning result set of undetermined structure and 'forward/restructure' that result set in some way such that is can easily be rendered by some "custom GUI tool".
If so, look into the DBMS_SQL for dynamic SQL. It has a DESCRIBE_COLUMNS procedure which returns the columns from a dynamic SELECT statement. The steps you would need are,
Parse the statement
Describe the result set (column names and data types)
Fetch each row, and for each column, call the datatype dependent function to return that value into a local variable
Place those local variables into a defined structure to return to the calling environment (eg consistent column names [such as col_1, col_2] probably all of VARCHAR2)
As an alternative, you could try building the query into an XMLFOREST statement, and parse the results out of the XML.
Added :
Unlike SQL Server, an Oracle PL/SQL call will not 'naturally' return a single result set. It can open up one or more ref cursors and pass them back to the client. It then becomes the client's responsibility to fetch records and columns from those ref cursors. If your client doesn't/can't deal with that, then you cannot use a PL/SQL call.
A stored function can return a pre-defined collection type, which can allow you to do something like "select * from table(func_name('select * from countries'))". However the function cannot do DML (update/delete/insert/merge) because it blows away any concept of consistency for that query. Plus the structure being returned is fixed so that
select * from table(func_name('select * from countries'))
must return the same set of columns (column names and data types) as
select * from table(func_name('select * from persons'))
It is possible, using DBMS_SQL or XMLFOREST, for such a function to take a dynamic query and restructure it into a pre-defined set of columns (col_1, col_2, etc) so that it can be returned in a consistent manner. But I can't see what the point of it would be.
Try try these.
DECLARE
TYPE EmpCurTyp IS REF CURSOR;
v_emp_cursor EmpCurTyp;
emp_record employees%ROWTYPE;
v_stmt_str VARCHAR2(200);
v_e_job employees.job%TYPE;
BEGIN
-- Dynamic SQL statement with placeholder:
v_stmt_str := 'SELECT * FROM employees WHERE job_id = :j';
-- Open cursor & specify bind argument in USING clause:
OPEN v_emp_cursor FOR v_stmt_str USING 'MANAGER';
-- Fetch rows from result set one at a time:
LOOP
FETCH v_emp_cursor INTO emp_record;
EXIT WHEN v_emp_cursor%NOTFOUND;
END LOOP;
-- Close cursor:
CLOSE v_emp_cursor;
END;
declare
v_rc sys_refcursor;
begin
v_rc := get_dept_emps(10); -- This returns an open cursor
dbms_output.put_line('Rows: '||v_rc%ROWCOUNT);
close v_rc;
end;
Find more examples here. http://forums.oracle.com/forums/thread.jspa?threadID=886365&tstart=0
In TOAD when executing the script below you will be prompted for the type of v_result. From the pick list of types select cursor, the results are then displayed in Toad's data grid (the excel spreadsheet like result). That said, when working with cursors as results you should always write two programs (the client and the server). In this case 'TOAD' will be the client.
DECLARE
v_result sys_refcursor;
v_dynamic_sql VARCHAR2 (4000);
BEGIN
v_dynamic_sql := 'SELECT * FROM user_objects where ' || ' 1 = 1';
OPEN :v_result FOR (v_dynamic_sql);
END;
There may be a similar mechanism in Oracle's SQL Developer to prompt for the binding as well.
I have a following oracle stored procedure
CREATE OR REPLACE
PROCEDURE getRejectedReasons
(
p_cursor IN OUT SYS_REFCURSOR)
AS
BEGIN
OPEN p_cursor FOR SELECT * FROM reasons_for_rejection;
END;
However, when I run this stored procedure in sql-developer then I dont see anything. I just see something like this:
Connecting to the database oracleLocal.
Process exited.
Disconnecting from the database oracleLocal.
I'm coming from MS sql server and am used to seeing actual results when running a stored procedure like this. Is this stored procedure not returning results because I am using a cursor??
The stored procedure is returning something it's just you aren't doing anything with the results.
You can do this simply by running the following script in SQLDeveloper:
VARIABLE csr REFCURSOR;
EXEC getRejectedReasons(:csr); -- the colon identifies the parameter as a variable
PRINT csr;
Another method is to fetch each row and do some sort of processing:
DECLARE
-- sys_refcursor is weakly typed
refcsr SYS_REFCURSOR;
-- define a record so we can reference the fields
rej_rec Reasons_for_Rejection%ROWTYPE;
BEGIN
getRejectedReasons(refcsr);
-- loop through the results
LOOP
-- gets one row at a time
FETCH refcsr INTO rej_rec;
-- if the fetch doesn't find any more rows exit the loop
EXIT WHEN refcsr%NOTFOUND;
-- Do something here.
-- For example : DBMS_OUTPUT.PUT_LINE(rej_rec.reason_desc);
END LOOP;
END;
You opened the cursor. You didn't select anything from it, update it, or advance it.
All open does, effectively, to select the matching rows into temporary memory, so you can advance the cursor row by row. Which you didn't do.
One of the differences between Oracle and SQL Server is that the latter returns result sets naturally. I'd use a function, by the way.
In Oracle, functions typically return a single element. Cursors came later.
There's some documentation online that will help you understand the use of refcursor bind variables. Here's one such for SQL*Plus:
http://download.oracle.com/docs/cd/B19306_01/server.102/b14357/ch5.htm#sthref1122
I think in SQL Developer you can do the same thing with autoprint on, although I haven't tested that.
Found a blog that also discusses something similar:
http://vadimtropashko.wordpress.com/cursors/
ETA: Ok. Ignore what I wrote. Listen to someone else. Apparently it's wrong, as I got down voted.
What tpdi said is correct. You have to do something with the cursor after you declare it.
Here's an example using two cursors in nested loops
PROCEDURE update_insert_tree (exid_in IN NUMBER, outvar_out OUT VARCHAR2)
IS
nxtid NUMBER;
phaseid NUMBER;
rowcounter1 NUMBER;
BEGIN
rowcounter1 := 0;
outvar_out := 0;
FOR acur IN (SELECT dept_exercise_id, phase
FROM ep_dept_exercise
WHERE exercise_id = exid_in)
LOOP
<<dept_loop>>
FOR thecur IN (SELECT document_name, thelevel, sortnum, type_flag,
ex_save_id
FROM ep_exercise_save
WHERE exercise_id = exid_in)
LOOP
phaseid := acur.phase;
IF phaseid = 0
THEN
phaseid := 10;
UPDATE ep_dept_exercise
SET phase = 10
WHERE dept_exercise_id = acur.dept_exercise_id;
END IF;
<<doc_loop>>