Export Data to Excel Instantly in Oracle APEX Without Displaying Any Report

Introduction:

 In Oracle APEX, exporting data to Excel is often tied to Interactive Reports or Grids, requiring the data to be displayed before download. But what if you could skip all that? Export Excel Directly in Oracle APEX Without Showing Data on the Screen — No Report Actions, No Regions, Just Pure PL/SQL! Say goodbye to manual “Actions → Download” clicks and unnecessary report rendering. With a single button, a clean redirect, and a pre-rendering PL/SQL process, you can instantly trigger an Excel download — delivering faster performance and a smoother user experience, all without exposing the data on the page.

Why we need to do:

In many business applications, users don’t always need to view data on-screen — they just need the file. Displaying a large report in APEX before exporting can slow down performance, consume unnecessary server resources, and clutter the UI. By providing a direct Excel export, we:

  • Save Time– One click instantly downloads the file, avoiding extra navigation.
  • Improve Performance– Skip rendering large datasets in the browser.
  • Enhance Security– Prevent sensitive data from being visible on the screen.
  • Streamline UX– Give users a clean, focused action without distractions.

This approach is ideal for dashboards, admin tools, and scenarios where the only goal is to deliver an export-ready file quickly and securely.

How do we solve: We can achieve a direct Excel export in Oracle APEX by bypassing Interactive Reports/Grids entirely and generating the file dynamically through PL/SQL. The solution involves.

Step-by-step Approach:

  1. Create Classic Report Region:
  2. Create a Button to Used to HTML CODE

Button Type To be Selected as Link Redirect to Another Page

  1. To trigger the Excel download instantly, create a button and set its action to Redirect to Page in this Application. Specify the target page (for example, Page 2) where your Excel export process is defined. When the user clicks this button, APEX immediately redirects to the specified page, and the Before Header PL/SQL process on that page runs to generate and send the Excel file to the browser. Because the file is delivered before any HTML rendering occurs, the user never sees the page content — only the direct Excel download prompt.

Code:

Pre-Rendering Code:
DECLARE

BEGIN

  — Tell browser this is an Excel download

  owa_util.mime_header(‘application/vnd.ms-excel’, FALSE);

  htp.p(‘Content-Disposition: attachment; filename=”Onhand_Serial_Report.xls”‘);

  owa_util.http_header_close; 

  — Start HTML table

  htp.p(‘<html><body><table border=”1″>’);

  — Table header

  htp.p(‘<tr>

          <th>Heat Number</th>

          <th>Serial Number</th>

          <th>srl_no_total_count</th>

          <th>Product Code</th>

          <th>Product Desc</th>

          <th>From Subinventory</th>

          <th>Next Subinventory</th>

          <th>Machine Group</th>          

        </tr>’);

  — Loop over your full query

  FOR rec IN (

SELECT

    GET_HEAT_NUMBER(a.heat_item_id) AS Heat_Number,

    MASS_ONHAND_SERIAL_NO1(a.subinventory_id, a.heat_item_id) AS serial_number,

     REGEXP_COUNT(MASS_ONHAND_SERIAL_NO1(a.subinventory_id, a.heat_item_id), ‘[^,]+’) AS srl_no_total_count,

    MASS_FND_UTILS.get_product_code(a.item_id) AS product_code,    

    MASS_FND_UTILS.get_product_desc(a.item_id) AS product_desc,  

    SUBINVENTORY_NAME_WITH_CODE(a.subinventory_id) AS From_Subinventory,  

    NVL(    SUBINVENTORY_NAME_WITH_CODE(MASS_INV_SUBINV_PKG.NEXT_SUBINVENTORY(a.heat_item_id, a.subinventory_id, ‘N’)),’OUT-SOURCE PROCESS’) AS Next_Subinventory,

    GET_MACHINE_GROUP1(a.subinventory_id, a.item_id, a.inward_id) AS Machine_Group   

FROM (SELECT DISTINCT a.heat_item_id, a.item_id, a.subinventory_id, a.inward_id

    FROM MASS_INV_ITEM_ONHAND_SL1 a  WHERE a.ONHAND_QUANTITY <> 0 AND a.subinventory_id NOT IN (14259, 14260, 14255, 14256, 64, 1518, 19556, 16223, 16)

      AND GET_MACHINE_GROUP1(a.subinventory_id, a.item_id, a.inward_id) IN (‘MPI MACHINE’)) a  

WHERE EXISTS (SELECT 1 FROM MASS_MOV_INV_APPROVAL appr  WHERE appr.APPROVAL_ID = :P747_APPROVAL_ID

AND appr.MACHINE_GROUP = GET_MACHINE_GROUP1(a.subinventory_id, a.item_id, a.inward_id)) ) LOOP

    — Print each row

    htp.p(‘<tr>’);

    htp.p(‘<td>’ || rec.Heat_Number || ‘</td>’);

    htp.p(‘<td>’ || rec.serial_number || ‘</td>’);

    htp.p(‘<td>’ || rec.srl_no_total_count || ‘</td>’);

    htp.p(‘<td>’ || rec.product_code || ‘</td>’);

    htp.p(‘<td>’ || rec.product_desc || ‘</td>’);    

    htp.p(‘<td>’ || rec.From_Subinventory || ‘</td>’);

    htp.p(‘<td>’ || rec.Next_Subinventory || ‘</td>’);

    htp.p(‘<td>’ || rec.Machine_Group || ‘</td>’);

    htp.p(‘</tr>’);

  END LOOP; 

  — End HTML

  htp.p(‘</table></body></html>’); 

  — Stop normal APEX rendering

  apex_application.stop_apex_engine;

END;

output:

Conclusion: 

Direct Excel export in Oracle APEX without displaying data on the screen offers a faster, cleaner, and more secure way to deliver information to users. By combining a simple button action with a pre-rendering PL/SQL process, we eliminate unnecessary report rendering, reduce page load times, and improve user experience. This approach is especially valuable for large datasets, sensitive information, or situations where the sole purpose is to provide a downloadable file. With this method, exporting becomes a one-click, hassle-free task.

Recent Posts