UTL_FILE – Practical Guide | mrcaption49
This implementation demonstrates an end-to-end CSV export process in Oracle using UTL_FILE. First, two relational tables—emp_department and employee—are created to simulate HR data. Sample records are inserted into both tables. A procedure export_employee_csv is then defined to build a CLOB string by first adding a CSV header and then appending employee details by joining the tables. This CLOB is passed to a helper procedure generate_csv, which efficiently writes the CLOB content to a physical .csv file using chunked writes via UTL_FILE. The chunking ensures large data volumes are handled safely. A dedicated Oracle Directory (NGCSUTL) is created and granted access, pointing to an OS path for file export. When export_employee_csv is executed, it generates a timestamped CSV file at the designated location. This modular approach cleanly separates data preparation from file I/O. The solution is production-ready, handles exceptions gracefully, and ensures clean file generation.
✅ End-to-End CSV File Generation Using UTL_FILE – Practical Guide
This is a complete and production-like workflow that shows how to:
- Create data tables 💾
- Populate them with sample data 🧪
- Convert that data into CSV format using a CLOB 🧱
- Export the content into a .csv file via UTL_FILE ✨
Let’s go step by step.
🧱 Step 1: Define the Base Tables
You start by creating two related tables:
- emp_department – Holds department details.
- employee – Holds employee details and references the department using a foreign key.
CREATE TABLE emp_department ( dept_id NUMBER PRIMARY KEY, dept_name VARCHAR2(50) ); CREATE TABLE employee ( emp_id NUMBER PRIMARY KEY, emp_name VARCHAR2(100), email VARCHAR2(100), dept_id NUMBER, salary NUMBER(10,2), doj DATE, CONSTRAINT fk_dept FOREIGN KEY (dept_id) REFERENCES emp_department(dept_id) ); 💡 This setup simulates a mini HR system.
🧪 Step 2: Insert Sample Data
Now insert data into the department and employee tables.
INSERT INTO emp_department VALUES (1, 'Finance'); INSERT INTO emp_department VALUES (2, 'HR'); INSERT INTO emp_department VALUES (3, 'Engineering'); INSERT INTO employee VALUES (101, 'Alice Thomas', 'alice@example.com', 1, 70000, TO_DATE('2021-05-10','YYYY-MM-DD')); INSERT INTO employee VALUES (102, 'Bob Martin', 'bob@example.com', 2, 60000, TO_DATE('2020-03-15','YYYY-MM-DD')); INSERT INTO employee VALUES (103, 'Carol Evans', 'carol@example.com', 3, 95000, TO_DATE('2019-11-01','YYYY-MM-DD')); 📌 The data is now ready to be transformed and exported.
📤 Step 3: Create the CSV Export Procedure (export_employee_csv)
This procedure does 3 main things:
- Builds a CSV header line.
- Loops through all employees and appends a line for each one.
- Calls generate_csv to write the CLOB to a .csv file.
CREATE OR REPLACE PROCEDURE export_employee_csv IS v_file_name VARCHAR2(100); v_emp_data CLOB := EMPTY_CLOB(); BEGIN v_file_name := 'EMPLOYEE_EXPORT_' || TO_CHAR(SYSDATE, 'YYYYMMDD_HH24MI') || '.csv'; -- Header line v_emp_data := 'EMP_ID,EMP_NAME,EMAIL,DEPARTMENT,SALARY,DATE_OF_JOINING' || CHR(10); -- Data lines FOR rec IN ( SELECT e.emp_id, e.emp_name, e.email, d.dept_name, e.salary, TO_CHAR(e.doj, 'YYYY-MM-DD') AS doj FROM employee e JOIN emp_department d ON e.dept_id = d.dept_id ) LOOP v_emp_data := v_emp_data || TO_CLOB( rec.emp_id || ',' || rec.emp_name || ',' || rec.email || ',' || rec.dept_name || ',' || rec.salary || ',' || rec.doj || CHR(10) ); END LOOP; -- Generate the CSV file generate_csv(v_file_name, 'NGCSUTL', v_emp_data); END; ✅ This keeps data formatting and file writing cleanly separated.
🧾 Step 4: UTL_FILE-Based CSV Generator (generate_csv)
This utility handles large CLOBs safely, by:
- Reading the CLOB in chunks (32,767 characters max),
- Writing each chunk line-by-line into the file,
- Ensuring the file is closed properly even in case of error.
CREATE OR REPLACE PROCEDURE generate_csv ( p_fileName VARCHAR2, p_dir_name VARCHAR2, p_clob CLOB ) IS c_chunk_size CONSTANT BINARY_INTEGER := 32767; l_file UTL_FILE.FILE_TYPE; l_pos INTEGER := 1; l_clob_len INTEGER := DBMS_LOB.GETLENGTH(p_clob); l_buffer VARCHAR2(32767); BEGIN l_file := UTL_FILE.FOPEN(p_dir_name, p_fileName, 'W', c_chunk_size); WHILE l_pos <= l_clob_len LOOP l_buffer := DBMS_LOB.SUBSTR(p_clob, c_chunk_size, l_pos); UTL_FILE.PUT_LINE(l_file, l_buffer); l_pos := l_pos + LENGTH(l_buffer); END LOOP; UTL_FILE.FCLOSE(l_file); EXCEPTION WHEN OTHERS THEN IF UTL_FILE.IS_OPEN(l_file) THEN UTL_FILE.FCLOSE(l_file); END IF; RAISE; END; 🛡️ Built-in exception handling prevents partial file corruption.
📂 Step 5: Create the Oracle Directory (if not already done)
Make sure the directory object (NGCSUTL) is defined in Oracle and points to a valid OS path where Oracle has write access.
CREATE OR REPLACE DIRECTORY NGCSUTL AS '/u01/app/oracle/exports'; GRANT READ, WRITE ON DIRECTORY NGCSUTL TO your_user; 💬 This is required only once and is managed by a DBA/admin.
🚀 Step 6: Execute the Procedure
Run it like this:
BEGIN export_employee_csv; END; After execution, you’ll find a file like:
EMPLOYEE_EXPORT_20250720_1050.csv in the path: /u01/app/oracle/exports (or your mapped path for NGCSUTL).
🧾 Output Sample
File content:
EMP_ID,EMP_NAME,EMAIL,DEPARTMENT,SALARY,DATE_OF_JOINING 101,Alice Thomas,alice@example.com,Finance,70000,2021-05-10 102,Bob Martin,bob@example.com,HR,60000,2020-03-15 103,Carol Evans,carol@example.com,Engineering,95000,2019-11-01 ✅ Summary
Step What You Did Purpose
1️⃣ Created tables (employee, emp_department) Sample dataset setup
2️⃣ Inserted employee and department data Seeded data
3️⃣ Built CLOB line-by-line with data Prepared memory content
4️⃣ Used generate_csv with UTL_FILE Persisted to disk
5️⃣ Executed the export procedure File created as CSV
Top comments (0)