generate excel file using cursor in anonymous block in oracle

2k Views Asked by At

I have below anonymous block where i am using cursor to generate the resultset and save it into TEST_REPORT.csv file. But i am getting error on the line where i am using spool as:

PLS-00103: Encountered the symbol "H" when expecting one of the following:
   := . ( @ % ;

I believe i cannot use spool in PL/SQL but not sure so i have tried below code. And also i cannot use UTL_FILE or UTL_FILE_DIR logic because of security restriction on the Production. As employees works on different department i want to generate separate csv file for each employee with respect to their department.

Is there anyway where i can break this code and use spool to generate csv file or any other logic ? Also if it is not possible to use spool in anonymous block then can i use it during execution of this code to generate files ?

If its not possible using spool then is it possible if i can organize my query result in such a way that it will be easy to export the result into single csv file after executing this anonymous block and then i can separate the single csv file into multiple files depending on the employee with their department manually ?

Generate-And-Run.sql file

SET SERVEROUTPUT ON;
set verify off
SET LONG 100000
SET lines 1000 
SET sqlformat SELECT;
SPOOL C:\Loop-Flattener.sql;

PROMPT VAR V_A VARCHAR2(64);


BEGIN
  FOR TARGET_POINTER IN (select ID,
       name,
       ST_ID      
from TEST_REPORT
where rownum <5)
    LOOP
    DBMS_OUTPUT.PUT_LINE('DEFINE TARGET = '''||TARGET_POINTER.ID||''';');
    DBMS_OUTPUT.PUT_LINE('EXEC :V_A := '''||TARGET_POINTER.ID||'''; ');
    DBMS_OUTPUT.PUT_LINE('@@Target-Csv-Generator.sql;');
  END LOOP;
END;
/

SPOOL OFF;
2

There are 2 best solutions below

20
On BEST ANSWER

As OldProgrammer mentioned, you cannot call SPOOL within PL/SQL. But you can can print to a spooled file from within PL/SQL, and can pre-compile/flatten the loop into a delegating intermediate worker-script that repeatedly calls the csv-generator.

Update. In response to the specifics you provided, the following should work for you.

Example Test data:

INSERT INTO CSS_BOUTIQUE VALUES ('EUR', 'Belgium', 'a0Hb0000006LLdQ');
INSERT INTO CSS_BOUTIQUE VALUES ('EUR', 'Portugal', 'a0HB0000006LLOG');
INSERT INTO CSS_BOUTIQUE VALUES ('EUR', 'Portugal', 'a0HB0000006LLYu');

INSERT INTO CSS_BOUTIQUE VALUES ('ASIA', 'Korea', 'e0HB0000016MEIi');
INSERT INTO CSS_BOUTIQUE VALUES ('ASIA', 'China', 'e0HB0000026MEIi');
INSERT INTO CSS_BOUTIQUE VALUES ('ASIA', 'Japan', 'e0HB0000036MEIi');

INSERT INTO CSS_BOUTIQUE VALUES ('SA', 'Chile', 's0HB0000016MEIi');
INSERT INTO CSS_BOUTIQUE VALUES ('SA', 'Argentina', 's0HB0000026MEIi');
INSERT INTO CSS_BOUTIQUE VALUES ('SA', 'Equador', 's0HB0000036MEIi');

Then create the following two scripts:

Generate-And-Run.sql This script will create a flat, pseudo-loop by generating an intermediate script filled with iterative commands to set new variable names and call a reusable csv-generator.

SET ECHO OFF;
SET FEEDBACK OFF;
SET HEAD OFF;
SET LIN 256;
SET TRIMSPOOL ON;
SET WRAP OFF;
SET PAGES 0;
SET TERM OFF;
SET SERVEROUTPUT ON;

SPOOL Loop-Flattener.sql;

PROMPT VAR V_ZONE_NAME VARCHAR2(64);


BEGIN
  FOR TARGET_POINTER IN (SELECT DISTINCT ZONE FROM CSS_BOUTIQUE)
    LOOP
    DBMS_OUTPUT.PUT_LINE('DEFINE TARGET = '''||TARGET_POINTER.ZONE||''';');
    DBMS_OUTPUT.PUT_LINE('EXEC :V_ZONE_NAME := '''||TARGET_POINTER.ZONE||'''; ');
    DBMS_OUTPUT.PUT_LINE('@@Target-Csv-Generator.sql;');
  END LOOP;
END;
/

SPOOL OFF;

@@Loop-Flattener.sql;

Target-Csv-Generator.sql: This script will do the work of generating a single csv. Please note, the report-name here is a simple REPORT_FOR... without any additional path to help ensure it gets created in the working directory.

SPOOL REPORT_FOR_&&TARGET..csv;

PROMPT zone,market, boutique_id;

select zone||','||
       market||','||
       boutique_id      
from CSS_BOUTIQUE
where rownum <5 and ZONE = :V_ZONE_NAME;

SPOOL OFF;

Then run it:

Place the above two scripts into the directory where you want your CSVs to be created, then Start SQLPlus in that directory

SQL*Plus: Release 12.2.0.1.0 Production on Sun Sep 10 14:38:13 2017
SQL> @@Generate-And-Run

Now, the working-directory has three new files:

REPORT_FOR_EUR.csv
REPORT_FOR_SA.csv
REPORT_FOR_ASIA.csv

And each only has the data for its zone. For example:

cat REPORT_FOR_ASIA.csv 

Yields:

zone,market, boutique_id
ASIA,Korea,e0HB0000016MEIi
ASIA,China,e0HB0000026MEIi
ASIA,Japan,e0HB0000036MEIi
0
On

You cannot call spool within a pl/sql block Spool is a sqlplus command, not pl/sql. Move the statement to before the DECLARE statement.