How to Save Report Views for All Users in an Interactive Report in Oracle APEX

Turn on public reports, limit who can publish them, save public and private views, test them as a Reader, and open a shared view from a button.

Users of an Interactive Report often build the same view again and again: the same filter, the same sort, the same columns. A saved report keeps that view under a name. A public saved report goes one step further: one person builds the view once, and every user of the page can pick it from the Reports list.

Oracle APEX has public reports built into the Interactive Report, but they are switched off by default. This guide turns them on, limits who may publish a view, saves a public and a private report, tests both as a second user, and opens the public view from a button.

Two earlier guides are close to this one. How to Add Control Breaks and Subtotals to an Interactive Report in Oracle APEX saves a layout as the developer's primary default report. How to Remember Each User's Filters with Preferences in Oracle APEX stores filters per user in page items.

This guide covers the views end users save at runtime and share with each other, with no developer session.

The example uses helpdesk requests. The same steps work for any Interactive Report.

Step 1: Create the Tables

Two tables hold the data:

  • HELPDESK_AGENTS has one row per support agent, with a unique name and a team.
  • HELPDESK_REQUESTS has one row per request: a unique request number, subject, category, priority, status, the assigned agent and the date it was opened.

Create the tables with three agents and 12 requests:

Example:

create table helpdesk_agents (
  agent_id        number generated by default on null as identity,
  agent_name      varchar2(100)  not null,
  team            varchar2(30)   not null,
  constraint helpdesk_agents_pk primary key (agent_id),
  constraint helpdesk_agents_name_uk unique (agent_name)
);

create table helpdesk_requests (
  request_id      number generated by default on null as identity,
  request_no      varchar2(20)   not null,
  subject         varchar2(200)  not null,
  category        varchar2(30)   not null,
  priority        varchar2(10)   default on null 'MEDIUM' not null,
  status          varchar2(15)   default on null 'OPEN' not null,
  agent_id        number,
  opened_on       date           default on null sysdate not null,
  constraint helpdesk_requests_pk primary key (request_id),
  constraint helpdesk_requests_no_uk unique (request_no),
  constraint helpdesk_requests_agent_fk foreign key (agent_id) references helpdesk_agents (agent_id),
  constraint helpdesk_requests_priority_ck check (priority in ('HIGH', 'MEDIUM', 'LOW')),
  constraint helpdesk_requests_status_ck check (status in ('OPEN', 'IN PROGRESS', 'RESOLVED'))
);

create index helpdesk_requests_agent_ix on helpdesk_requests (agent_id);
create index helpdesk_requests_status_ix on helpdesk_requests (status, priority);

insert into helpdesk_agents (agent_name, team) values
  ('Meera Nair', 'Network'),
  ('Arjun Rao', 'Hardware'),
  ('Kavya Iyer', 'Software');

insert into helpdesk_requests (request_no, subject, category, priority, status, agent_id, opened_on)
select v.request_no, v.subject, v.category, v.priority, v.status, a.agent_id, v.opened_on
from (values
  ('HD-2001', 'VPN drops every hour',          'Network',  'HIGH',   'OPEN',        'Meera Nair', date '2026-10-01'),
  ('HD-2002', 'Printer on floor 3 jams',       'Hardware', 'LOW',    'RESOLVED',    'Arjun Rao',  date '2026-10-02'),
  ('HD-2003', 'Cannot install the PDF reader', 'Software', 'MEDIUM', 'IN PROGRESS', 'Kavya Iyer', date '2026-10-03'),
  ('HD-2004', 'Wi-Fi slow in meeting room',    'Network',  'MEDIUM', 'OPEN',        'Meera Nair', date '2026-10-05'),
  ('HD-2005', 'Laptop battery swells',         'Hardware', 'HIGH',   'OPEN',        'Arjun Rao',  date '2026-10-06'),
  ('HD-2006', 'Email client crashes on start', 'Software', 'HIGH',   'IN PROGRESS', 'Kavya Iyer', date '2026-10-07'),
  ('HD-2007', 'Request a second monitor',      'Hardware', 'LOW',    'OPEN',        null,         date '2026-10-08'),
  ('HD-2008', 'Firewall blocks the CRM site',  'Network',  'HIGH',   'RESOLVED',    'Meera Nair', date '2026-10-09'),
  ('HD-2009', 'Excel macros disabled',         'Software', 'MEDIUM', 'OPEN',        'Kavya Iyer', date '2026-10-12'),
  ('HD-2010', 'Docking station no display',    'Hardware', 'MEDIUM', 'IN PROGRESS', 'Arjun Rao',  date '2026-10-13'),
  ('HD-2011', 'Password reset link expired',   'Software', 'HIGH',   'OPEN',        null,         date '2026-10-14'),
  ('HD-2012', 'Network drive not mapped',      'Network',  'LOW',    'RESOLVED',    'Meera Nair', date '2026-10-15')
) v (request_no, subject, category, priority, status, agent_name, opened_on)
left join helpdesk_agents a on a.agent_name = v.agent_name;

commit;

select r.request_no, r.subject, r.priority, r.status, a.agent_name
from helpdesk_requests r
left join helpdesk_agents a on a.agent_id = r.agent_id
order by r.request_no;

Output:

Table HELPDESK_AGENTS created.

Table HELPDESK_REQUESTS created.

Index HELPDESK_REQUESTS_AGENT_IX created.

Index HELPDESK_REQUESTS_STATUS_IX created.

3 rows inserted.

12 rows inserted.

Commit complete.

REQUEST_NO    SUBJECT                          PRIORITY    STATUS         AGENT_NAME
_____________ ________________________________ ___________ ______________ _____________
HD-2001       VPN drops every hour             HIGH        OPEN           Meera Nair
HD-2002       Printer on floor 3 jams          LOW         RESOLVED       Arjun Rao
HD-2003       Cannot install the PDF reader    MEDIUM      IN PROGRESS    Kavya Iyer
HD-2004       Wi-Fi slow in meeting room       MEDIUM      OPEN           Meera Nair
HD-2005       Laptop battery swells            HIGH        OPEN           Arjun Rao
HD-2006       Email client crashes on start    HIGH        IN PROGRESS    Kavya Iyer
HD-2007       Request a second monitor         LOW         OPEN
HD-2008       Firewall blocks the CRM site     HIGH        RESOLVED       Meera Nair
HD-2009       Excel macros disabled            MEDIUM      OPEN           Kavya Iyer
HD-2010       Docking station no display       MEDIUM      IN PROGRESS    Arjun Rao
HD-2011       Password reset link expired      HIGH        OPEN
HD-2012       Network drive not mapped         LOW         RESOLVED       Meera Nair

12 rows selected.
  • HELPDESK_REQUESTS_AGENT_FK links a request to an existing agent. AGENT_ID may stay empty, so a request can be unassigned.
  • HELPDESK_REQUESTS_AGENT_IX indexes the foreign key, and HELPDESK_REQUESTS_STATUS_IX supports filters on status and priority.
  • The check constraints allow only the known priorities and statuses.
  • PRIORITY, STATUS and OPENED_ON use DEFAULT ON NULL, so a new request gets MEDIUM, OPEN and today's date without a trigger.

Step 2: Count the Rows the Views Must Show

The first saved view in this guide shows every request that is not resolved. Count those requests by status and priority:

Example:

select status, priority, count(*) as requests
from helpdesk_requests
where status <> 'RESOLVED'
group by status, priority
order by status, priority;

Output:

STATUS         PRIORITY       REQUESTS
______________ ___________ ___________
IN PROGRESS    HIGH                  1
IN PROGRESS    MEDIUM                2
OPEN           HIGH                  3
OPEN           LOW                   1
OPEN           MEDIUM                2

The counts add up to 9 unresolved requests, 4 of them with HIGH priority. These are the row counts to expect later.

Step 3: Create the Interactive Report Page

The report joins each request to its agent. The source query is:

Example:

select r.request_id,
       r.request_no,
       r.subject,
       r.category,
       r.priority,
       r.status,
       a.agent_name,
       r.opened_on
from helpdesk_requests r
left join helpdesk_agents a on a.agent_id = r.agent_id

In Page Designer, click Create (the plus icon) and choose Page. Select the Interactive Report tile:

Create a Page wizard with the Interactive Report tile marked with a red box
Choose the Interactive Report page type.

On the Create Interactive Report screen, enter Page Number 810 and Name Helpdesk Requests. Leave Page Mode Normal and Include Form Page off:

Create Interactive Report screen with Page Number 810 and Name Helpdesk Requests marked with a red box
Page number and name.

Under Data Source, keep Local Database, set Source Type to SQL Query and paste the query above into the editor:

Data Source section with Source Type SQL Query and the report query marked with a red box
The report source is a SQL query.

Under Navigation, keep the defaults: a breadcrumb and a new navigation menu entry with the icon fa-table. Click Create Page:

Navigation section of the Create Interactive Report wizard with the default breadcrumb and navigation menu settings
Keep the navigation defaults and create the page.

Step 4: Allow Public Reports and Limit Who Saves Them

Page Designer opens page 810. Select the Helpdesk Requests region and open the Attributes tab. Under Actions Menu, Save Report is on by default, but Save Public Report is off.

Turn on Save Public Report. A new property appears, Save Public Report Authorization. Set it to Is Administrator, an authorization scheme that already exists in this application:

Actions Menu attributes with Save Report, Save Public Report and Save Public Report Authorization set to Is Administrator marked with a red box
Only administrators may publish a report for everyone.

Every user can still save private reports. Only users who pass the Is Administrator scheme see the Public option when they save.

Next, tidy the columns. Expand Columns, select REQUEST_ID and set Type to Hidden:

REQUEST_ID column with Type set to Hidden marked with a red box
Hide the request ID.

Select OPENED_ON and set Format Mask to DD-MON-YYYY under Appearance:

OPENED_ON column with Format Mask DD-MON-YYYY marked with a red box
Show the date without the time.

Click Save and run the page. The report lists all 12 requests:

Helpdesk Requests interactive report showing all 12 requests
The report before any saved view.

Step 5: Build the View as an Administrator

Sign in to the application as an administrator. In this example, that is SALES_MANAGER, a user with the Administrator role and no App Builder session. Open page 810, click Actions, then Filter:

Actions menu of the interactive report with Filter marked with a red box
Filter is in the Actions menu.

Set Column to Status, Operator to != and Expression to RESOLVED:

Filter dialog with Column Status, Operator not equal and Expression RESOLVED marked with a red box
Hide the resolved requests.

Click Apply. The report shows the 9 unresolved requests, the number from Step 2:

Interactive report showing 9 unresolved requests with the Status filter above the report
Nine requests are not resolved.

Step 6: Save the View as a Public Report

Click Actions, then Report, then Save Report:

Actions menu with the Report submenu open and Save Report marked with a red box
Save Report is under Actions, Report.

Enter Name Unresolved Requests and Description Open and in-progress requests. Tick Public:

Save Report dialog with Name Unresolved Requests, a description and the Public checkbox ticked marked with a red box
The Public checkbox shares the view with all users.

Click Apply. A Reports select list appears next to the search field, showing 1. Unresolved Requests. A Saved Report chip appears above the report, next to the filter:

Interactive report with the Reports list showing Unresolved Requests and a Saved Report chip above the rows
The public report is saved and selected.

The Reports list groups the views. In this test it had a Default group with 1. Primary Report and a Public group with 1. Unresolved Requests.

Step 7: Update the Public Report

The rows of the public report are in no particular order. To add a sort, keep Unresolved Requests selected, click Actions, then Data, then Sort. Set Column 1 to Opened On, Ascending:

Sort dialog with Column 1 Opened On and Direction Ascending marked with a red box
Oldest requests first.

Click Apply, then Actions, Report, Save Report again. The dialog opens with the name, the description and Public already filled in from the selected report:

Save Report dialog prefilled with Unresolved Requests, its description and Public ticked
Saving under the same name updates the report.

Click Apply. In this test, APEX updated the existing public report. It did not create a second one, and the dictionary query in Step 12 shows its new sort column.

Step 8: Save a Private Report

A report saved without Public stays visible to its owner only. In the Reports list, choose 1. Primary Report. Click Actions, then Filter, set Column to Agent Name and Operator to is null:

Filter dialog with Column Agent Name and Operator is null marked with a red box
Find requests without an agent.

Click Apply, then Actions, Report, Save Report. Enter Name Unassigned Requests and Description Requests without an agent. Leave Public unticked:

Save Report dialog with Name Unassigned Requests, a description and Public not ticked marked with a red box
A private report for this user only.

Click Apply. The report shows the two unassigned requests, HD-2007 and HD-2011:

Interactive report showing the private report Unassigned Requests with two rows
The private report is saved.

The Reports list of SALES_MANAGER now has three groups: Default, Private with Unassigned Requests, and Public with Unresolved Requests.

Step 9: Test the Public Report as Another User

Sign in as SALES_USER, a user with the Reader role. Reader does not pass the Is Administrator scheme. Open page 810. The Reports list shows 1. Primary Report and the public 1. Unresolved Requests. The private Unassigned Requests of SALES_MANAGER is not in the list:

Report as SALES_USER showing all 12 requests with the Reports list marked with a red box
SALES_USER starts on the primary report.

Choose 1. Unresolved Requests in the Reports list. The report shows the 9 unresolved requests, sorted by Opened On:

Report as SALES_USER with the public report Unresolved Requests selected showing 9 rows
Another user gets the shared view.

Notice what is missing. The Saved Report chip with its remove button is not shown, because SALES_USER does not own this report. In this test, the Report menu offered only Save Report and Reset, so SALES_USER had no way to delete the public report.

Step 10: Save a Personal Copy as a Reader

Readers can still build on a public report. With Unresolved Requests selected, SALES_USER adds a filter Priority = HIGH. The report shows the 4 high-priority requests from Step 2.

Click Actions, Report, Save Report. The dialog has Name and Description but no Public checkbox. In this test, it opened with the public report's name filled in. Change the Name to High Priority Unresolved and the description to match:

Save Report dialog for SALES_USER with Name High Priority Unresolved and a description and no Public checkbox
A Reader saves private reports only.

Click Apply. The new report appears in a Private group of SALES_USER's Reports list. A Saved Report chip appears, because SALES_USER owns this report:

Report as SALES_USER with the private report High Priority Unresolved showing 4 rows
The Reader's own view.

In a first test, SALES_USER kept the prefilled name and clicked Apply. APEX did not change the public report. It created a private report with the same name, Unresolved Requests, so the Reports list showed that name twice, once under Private and once under Public. Give a personal copy its own name to avoid that.

To delete a private report, its owner clicks the remove (X) button on the Saved Report chip. APEX asks for confirmation:

Delete Report confirmation dialog asking Would you like to delete these report settings
Removing the chip deletes the owner's report.

Apply deletes the report, and Cancel keeps it. The duplicate Unresolved Requests copy from the first test was deleted this way.

Step 11: Check That the Server Enforces the Authorization

The Public checkbox is only hidden from SALES_USER in the browser. As a negative test, a script added a checked checkbox with the same ID to the Save Report dialog of SALES_USER and clicked Apply. The browser sent the public flag to the server.

The server refused it. The Ajax call returned an error that included ORA-02290 for the check constraint WWV_FLOW_WS_RPT_STATUS_CK, and no report was saved, public or private. The authorization scheme is checked on the server, not only when the dialog is drawn.

Step 12: Look at the Saved Reports in the Dictionary

The APEX dictionary views show every saved report of the page, its type, its owner and its filters:

Example:

select report_name, report_type, application_user, report_alias, sort_column_1
from apex_application_page_ir_rpt
where application_id = 400
and page_id = 810
and report_type in ('PRIMARY_DEFAULT', 'PUBLIC', 'PRIVATE')
order by report_type, report_name;

select r.report_name, c.condition_column_name, c.condition_operator, c.condition_expression
from apex_application_page_ir_cond c
join apex_application_page_ir_rpt r on r.report_id = c.report_id
where r.application_id = 400
and r.page_id = 810
and r.report_type in ('PUBLIC', 'PRIVATE')
order by r.report_name, c.condition_column_name;

Output:

REPORT_NAME                 REPORT_TYPE        APPLICATION_USER    REPORT_ALIAS           SORT_COLUMN_1
___________________________ __________________ ___________________ ______________________ ________________
                            PRIMARY_DEFAULT    APXWS_DEFAULT       primary
High Priority Unresolved    PRIVATE            SALES_USER                                 OPENED_ON
Unassigned Requests         PRIVATE            SALES_MANAGER
Unresolved Requests         PUBLIC             SALES_MANAGER       unresolved-requests    OPENED_ON

REPORT_NAME                 CONDITION_COLUMN_NAME    CONDITION_OPERATOR    CONDITION_EXPRESSION
___________________________ ________________________ _____________________ _______________________
High Priority Unresolved    PRIORITY                 =                     HIGH
High Priority Unresolved    STATUS                   !=                    RESOLVED
Unassigned Requests         AGENT_NAME               is null
Unresolved Requests         STATUS                   !=                    RESOLVED
  • REPORT_TYPE is PUBLIC for the shared view and PRIVATE for the two personal ones.
  • APPLICATION_USER is the user who saved the report, SALES_MANAGER for the public one.
  • Only the public report has a REPORT_ALIAS, unresolved-requests. The next step uses it in a link.
  • The second query shows that High Priority Unresolved copied the Status filter of the public report and added its own Priority filter.

Step 13: Open the Public Report from a Button

A link can open a page with a saved report already selected. The request is IR[region static ID]_ followed by the report alias, here IR[helpdesk-requests]_unresolved-requests.

First, give the region an ID the request can use. Select the Helpdesk Requests region, open the Region tab and set HTML DOM ID to helpdesk-requests under Advanced:

Region Advanced properties with HTML DOM ID helpdesk-requests marked with a red box
The link names the region by this ID.

In a first test, this property was empty. Page Designer showed a locked Static ID of helpdesk-requests, but the region had no static ID in the APEX dictionary. The button below opened page 810 without an error, yet showed the Primary report. After HTML DOM ID was set, the same link opened Unresolved Requests.

Next, add the button. Right-click the Helpdesk Requests region and choose Create Button. Set Button Name to UNRESOLVED and Label to Unresolved Requests. Under Layout, keep Region Helpdesk Requests and set Slot to Right of Interactive Report Search Bar:

Button properties with Button Name UNRESOLVED, Label Unresolved Requests, Region and Slot marked with red boxes
The button sits next to the search bar.

Under Behavior, set Action to Redirect to Page in this Application and click Target:

Button Behavior properties with Action Redirect to Page in this Application and Target Page 810 marked with a red box
The button redirects to the same page.

In the Link Builder, set Type to Page in this application and Page to 810. Under Advanced, set Request to IR[helpdesk-requests]_unresolved-requests:

Link Builder with Type Page in this application, Page 810 and Request IR[helpdesk-requests]_unresolved-requests marked with red boxes
The request selects the public report.

Click OK and Save. Sign in as SALES_USER, choose 1. Primary Report and click the Unresolved Requests button. The page reloads with the public report selected and 9 rows:

Report as SALES_USER after clicking the Unresolved Requests button with the public report selected, both marked with red boxes
One click opens the shared view.

The wizard set Page Access Protection of page 810 to Arguments Must Have Checksum. The button URL had a cs checksum parameter added by APEX. A hand-typed URL with the same request and no checksum failed with "Session state protection violation", so declarative links are the way to reach a saved report.

Step 14: Know How Public Reports Move Between Environments

Public and private reports are saved at runtime, as data of the workspace. They are not part of the page definition the way the primary default report is. Compare an application export with and without the public reports option:

Example:

set serveroutput on
declare
  l_files apex_t_export_files;
  function hits(p_files apex_t_export_files) return number is
    l_count number := 0;
  begin
    for i in 1 .. p_files.count loop
      if dbms_lob.instr(p_files(i).contents, 'Open and in-progress requests') > 0 then
        l_count := l_count + 1;
      end if;
    end loop;
    return l_count;
  end;
begin
  l_files := apex_export.get_application(p_application_id => 400);
  dbms_output.put_line('Default export, files with the public report: ' || hits(l_files));
  l_files := apex_export.get_application(p_application_id => 400, p_with_ir_public_reports => true);
  dbms_output.put_line('With public reports, files with the public report: ' || hits(l_files));
end;
/

Output:

Default export, files with the public report: 0
With public reports, files with the public report: 1

PL/SQL procedure successfully completed.

The default export did not contain the public report. With p_with_ir_public_reports set to true, it did. Without that option, the public views stay behind in the source workspace.

Things to Know

  • Save Public Report is off by default. Turn it on per Interactive Report and use Save Public Report Authorization to decide who may publish views.
  • Users without the authorization see no Public checkbox, and the server rejected a forged public save in this test.
  • Only the owner sees the Saved Report chip with the remove button, so other users cannot delete a public report.
  • Saving a public report again under the same name updates it for everyone. A user without the authorization who saves under that name gets a private copy instead.
  • Users reopened the page on the report they last viewed, also in a new session.
  • A link to a saved report needs the region's HTML DOM ID and a checksum, which declarative buttons and links add automatically.
  • Default exports leave out public reports. Include them when you move the application, or recreate the views.

Related Guides

Conclusion

Public reports let one person build a report view and share it with every user of an Interactive Report in Oracle APEX. Turn on Save Public Report, limit it with an authorization scheme, and save the view with Public ticked. Other users pick it from the Reports list and can save their own private copies.

In this example, the Reader saw the public report but could not change, delete or publish one, even with a forged request. A button with the report alias opened the shared view directly, once the region had an HTML DOM ID.

Get more Vinish.dev tutorials on Google

See my articles more often when you search Google.

Vinish Kapoor
Vinish Kapoor

An Oracle ACE, author of four books on Oracle APEX, SQL and PL/SQL, and Oracle Forms, and a software developer building Oracle database applications since 2001.

guest

0 Comments
Oldest
Newest Most Voted