0

I need to fetch all rows in a specific partition of a table and print the values to a file.

CREATE OR REPLACE PROCEDURE
WriteRecordToFile
(
 mypartition IN VARCHAR2,
 myfilename IN VARCHAR2,
 mydirloc IN VARCHAR2
)
IS
 out_file utl_file.file_type;
 chunk_size BINARY_INTEGER := 32767;
BEGIN
 out_file := utl_file.fopen (mydirloc, myfilename, 'w', chunk_size);
 
 FOR rec IN (
 SELECT name FROM my_table PARTITION mypartition
 )
 LOOP
 utl_file.put(out_file, rec.name);
 utl_file.new_line(out_file);
 END LOOP;
 
 utl_file.fclose (out_file);
EXCEPTION
 WHEN OTHERS THEN
 dbms_output.put_line('Error while writing file: '|| sqlerrm);
 IF utl_file.is_open(out_file) THEN
 utl_file.fclose(out_file);
 END IF;
END;
/

However, the above stored procedure only works if there is no 'PARTITION mypartition' in the select statement. I tried to use

EXECUTE IMMEDIATE 'SELECT name FROM my_table PARTITION mypartition'

in above but it still doesn't work. What is the correct way to do query with partition in the stored procedure? I am using Oracle 19c.

asked Feb 28, 2025 at 4:22
1
  • A follow-up discussion was started:
    “What is the benefit of looping over partitions?” Join the conversation
  • Please edit the question and include a minimal reproducible example with: the CREATE TABLE and INSERT statements for your sample data; the complete error message; and the expected output for your sample data. "It still doesn't work" is not a constructive statement as it does not tell us "what" does not work or what the issue was with the thing that is not working. Commented Feb 28, 2025 at 8:48

3 Answers 3

1

"Doesn't work" is pretty much useless. Oracle must have specified the error, and - if you shared it with us - it would help us help you.

Anyway: select statement looks suspicious. documentation says that syntax is

SELECT name FROM my_table PARTITION (mypartition)
 ^ ^
 | |
 parenthesis aren't optional!

so - for the starters - add parenthesis and see what happens next.

answered Feb 28, 2025 at 6:02
Sign up to request clarification or add additional context in comments.

1 Comment

I see the error "Warning: Procedure created with compilation errors." even there is parenthesis there. Anyway I found it is alright if I use EXECUTE IMMEDIATE.
0

First, it's probably a bad design to use PL/SQL and utl_file for so simple a task. It'd be better just to have a client select with a normal SQL query and dump the results locally (to the client).

However, if you must, to make your code work you'd need both to add parenthesis around the partition name and you must use dynamic SQL because you are parameterizing an object name, not merely a bind variable. There are several options for this:

While EXECUTE IMMEDIATE in combination with BULK COLLECT could be used if you want to fetch into a collection (array), at large volumes that puts too much stress on PGA memory usage. If you want a cursor that operates row-by-row instead, you cannot use EXECUTE IMMEDIATE.

You can, however, use a ref cursor (like the system-provided type sys_refcursor) with an OPEN FOR statement to implement a dynamic select. That will avoid the memory demands of a collection. It's an explicit cursor, however, not an implicit one, so you will have to explicitly FETCH from it. You will also need to create a record variable that matches the column layout of your SELECT clause (not strictly necessary if you are selecting only 1 column). See below.

(I've marked the additional/new rows with --NEW. The rest is your code)

CREATE OR REPLACE PROCEDURE
WriteRecordToFile
(
 mypartition IN VARCHAR2,
 myfilename IN VARCHAR2,
 mydirloc IN VARCHAR2
)
IS
 out_file utl_file.file_type;
 chunk_size BINARY_INTEGER := 32767;
 cur sys_refcursor; --NEW
 TYPE rectype IS RECORD (name varchar2(128)); --NEW
 rec rectype; --NEW
BEGIN
 out_file := utl_file.fopen (mydirloc, myfilename, 'w', chunk_size);
 
 OPEN cur FOR 'SELECT name FROM my_table PARTITION ('||mypartition||')';--NEW
 
 FETCH cur INTO rec;--NEW
 WHILE cur%FOUND--NEW
 LOOP
 utl_file.put(out_file, rec.name);
 utl_file.new_line(out_file);
 FETCH cur INTO rec;--NEW
 END LOOP;
 
 CLOSE cur; --NEW
 utl_file.fclose (out_file);
EXCEPTION
 WHEN OTHERS THEN
 dbms_output.put_line('Error while writing file: '|| sqlerrm);
 IF utl_file.is_open(out_file) THEN
 utl_file.fclose(out_file);
 END IF;
END;
/
answered Feb 28, 2025 at 13:32

Comments

0

You can't use parameter for a partition name for the same reasons that you can't use it for a table name.

It's also arguably poor practice to pass an internal database object name such as a table or partition name as part of a business process.

What we normally do is pass the partition key value:

create or replace procedure WriteRecordToFile
 ( inKeyValue in mytable.partkey%type -- sale date, product type etc
 , inFilename in varchar2
 , inDirLoc in varchar2 )
as
 out_file utl_file.file_type;
 chunk_size pls_integer := 32767;
begin
 out_file := utl_file.fopen(inDirLoc, inFilename, 'w', chunk_size);
 for rec in (
 select name from my_table where part_key_value = inKeyValue
 )
 loop
 utl_file.put(out_file, rec.name);
 utl_file.new_line(out_file);
 end loop;
 utl_file.fclose(out_file);
exception
 when others then
 dbms_output.put_line('Error while writing file: ' || sqlerrm);
 if utl_file.is_open(out_file) then
 utl_file.fclose(out_file);
 end if;
end;
/
answered Mar 8, 2025 at 19:13

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.