/*
* Comprehensive PL/SQL script for Oracle Database storage and space utilization reporting.
* Output is formatted for SQL*Plus/Toad using DBMS_OUTPUT with meticulously aligned columns.
* Enhancements include:
* - Database name and total occupied/free space as header.
* - Segment-based used space in overall summary for accuracy comparison.
* - Simplified temporary tablespace utilization using DBA_TEMP_FREE_SPACE (Oracle 11g+).
* - Free space fragmentation report.
* - Segment level report limited to top 20 largest objects (using ROWNUM for Oracle 11g+ compatibility).
* - Partition_name included in segment report for granularity.
* - UNDO tablespaces included in overall reports.
* - Improved column formatting with totals where feasible.
* - Fixed ORA-00979 in Section 1 using CTE for cleaner aggregation.
* - Added Section 6 for real-time temporary tablespace usage via GV$TEMP_SPACE_HEADER.
* - Removed ASM Diskgroup Utilization (ASM not used).
* - Fixed ORA-00937 (Database Summary), ORA-00900 (Section 4), and ORA-00979 (Section 1).
* - Adjusted DBMS_OUTPUT padding for perfect alignment.
*
* Ensure SELECT privileges on:
* DBA_TABLESPACES, DBA_DATA_FILES, DBA_FREE_SPACE, DBA_SEGMENTS,
* DBA_TEMP_FILES, DBA_TEMP_FREE_SPACE, GV$TEMP_SPACE_HEADER, V$DATABASE.
* Compatible with Oracle 11g and later.
* To ensure output visibility:
* - SQL*Plus: Run `SET SERVEROUTPUT ON SIZE 1000000; SET LINESIZE 200;` before executing.
* - Toad: Enable DBMS Output pane and set display width to at least 200 characters.
* If no output or misalignment occurs, check:
* - DBMS_OUTPUT enabled.
* - Sufficient privileges.
* - Data in queried views (e.g., non-temporary tablespaces, segments).
*/
BEGIN
-- Enable DBMS_OUTPUT with a large buffer
DBMS_OUTPUT.ENABLE(1000000);
-- Declare cursors for each report section
DECLARE
-- Cursor for Database Summary (Section 0)
CURSOR db_summary_cur IS
SELECT
d.name AS db_name,
ROUND(SUM(df.bytes) / (1024 * 1024 * 1024), 2) AS total_allocated_gb,
ROUND(SUM(df.bytes - NVL(fs.bytes, 0)) / (1024 * 1024 * 1024), 2) AS total_used_gb,
ROUND(SUM(NVL(fs.bytes, 0)) / (1024 * 1024 * 1024), 2) AS total_free_gb,
ROUND((SUM(df.bytes - NVL(fs.bytes, 0)) / SUM(df.bytes)) * 100, 2) AS total_used_pct
FROM
dba_data_files df
LEFT JOIN (
SELECT file_id, SUM(bytes) AS bytes
FROM dba_free_space
GROUP BY file_id
) fs ON df.file_id = fs.file_id
CROSS JOIN (
SELECT name FROM v$database
) d
WHERE
df.tablespace_name IN (SELECT tablespace_name FROM dba_tablespaces WHERE contents != 'TEMPORARY')
GROUP BY
d.name;
-- Cursor for Overall Tablespace Utilization (Section 1)
CURSOR overall_tablespace_cur IS
WITH segment_space AS (
SELECT tablespace_name, ROUND(SUM(bytes) / (1024 * 1024 * 1024), 2) AS segment_used_gb
FROM dba_segments
GROUP BY tablespace_name
),
file_space AS (
SELECT
t.tablespace_name,
t.status,
SUM(f.bytes) / (1024 * 1024 * 1024) AS total_size_gb,
SUM(f.bytes - NVL(s.bytes, 0)) / (1024 * 1024 * 1024) AS used_space_gb,
SUM(NVL(s.bytes, 0)) / (1024 * 1024 * 1024) AS free_space_gb,
SUM(DECODE(f.autoextensible, 'YES', f.maxbytes, f.bytes)) / (1024 * 1024 * 1024) AS max_size_gb
FROM
dba_tablespaces t
JOIN
dba_data_files f ON t.tablespace_name = f.tablespace_name
LEFT JOIN (
SELECT file_id, SUM(bytes) AS bytes
FROM dba_free_space
GROUP BY file_id
) s ON f.file_id = s.file_id
WHERE
t.contents != 'TEMPORARY'
GROUP BY
t.tablespace_name, t.status
)
SELECT
fs.tablespace_name,
fs.status,
ROUND(fs.total_size_gb, 2) AS total_size_gb,
ROUND(fs.used_space_gb, 2) AS used_space_gb,
NVL(ss.segment_used_gb, 0) AS segments_used_gb,
ROUND(fs.free_space_gb, 2) AS free_space_gb,
ROUND((fs.used_space_gb / fs.total_size_gb) * 100, 2) AS allocated_pct_used,
ROUND(fs.max_size_gb, 2) AS max_size_gb,
ROUND((fs.used_space_gb / fs.max_size_gb) * 100, 2) AS max_pct_used
FROM
file_space fs
LEFT JOIN
segment_space ss ON fs.tablespace_name = ss.tablespace_name
ORDER BY
allocated_pct_used DESC;
-- Cursor for Tablespace Utilization by Datafile (Section 2)
CURSOR datafile_util_cur IS
SELECT
df.tablespace_name,
df.file_name,
ROUND(df.bytes / (1024 * 1024 * 1024), 2) AS current_size_gb,
ROUND((df.bytes - NVL(fs.bytes, 0)) / (1024 * 1024 * 1024), 2) AS used_space_gb,
ROUND(NVL(fs.bytes, 0) / (1024 * 1024 * 1024), 2) AS free_space_gb,
ROUND(((df.bytes - NVL(fs.bytes, 0)) / df.bytes) * 100, 2) AS used_pct,
df.autoextensible,
CASE
WHEN df.autoextensible = 'YES' THEN ROUND(df.maxbytes / (1024 * 1024 * 1024), 2)
ELSE NULL
END AS max_size_gb
FROM
dba_data_files df
LEFT JOIN (
SELECT file_id, SUM(bytes) AS bytes
FROM dba_free_space
GROUP BY file_id
) fs ON df.file_id = fs.file_id
ORDER BY
df.tablespace_name, df.file_id;
-- Cursor for Segment Level Utilization (Top 20 Largest Objects, Section 3)
CURSOR segment_util_cur IS
SELECT
owner,
segment_name,
partition_name,
segment_type,
tablespace_name,
ROUND(bytes / (1024 * 1024 * 1024), 2) AS size_gb
FROM (
SELECT
owner,
segment_name,
partition_name,
segment_type,
tablespace_name,
bytes
FROM
dba_segments
WHERE
tablespace_name IN (SELECT tablespace_name FROM dba_tablespaces WHERE contents != 'TEMPORARY')
AND owner NOT IN ('SYS', 'SYSTEM', 'SYSMAN', 'DBSNMP', 'OUTLN', 'APPQOSSYS', 'GSMADMIN_INTERNAL',
'LBACSYS', 'DIP', 'ORACLE_OCM', 'AUDSYS', 'XDB', 'MDSYS', 'OLAPSYS', 'ORDDATA',
'ORDPLUGINS', 'ORDSYS', 'WMSYS', 'EXFSYS', 'CTXSYS', 'ANONYMOUS', 'APEX_%',
'FLOWS_FILES', 'MGMT_VIEW', 'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR',
'SI_INFORMTN_SCHEMA', 'XS$NULL', 'MDDATA', 'OJVMSYS', 'APEX_PUBLIC_USER',
'AUDSYS', 'GGSYS', 'DVF', 'DVSYS', 'LBAC_SYS', 'CDB_ONLY_SYS')
ORDER BY
bytes DESC
)
WHERE ROWNUM <= 20; -- Compatible with Oracle 11g+
-- Cursor for Temporary Tablespace Utilization (Section 4)
CURSOR temp_tablespace_cur IS
SELECT
fs.tablespace_name,
ROUND(fs.allocated_space / (1024 * 1024 * 1024), 2) AS allocated_size_gb,
ROUND((fs.allocated_space - fs.free_space) / (1024 * 1024 * 1024), 2) AS used_space_gb,
ROUND(fs.free_space / (1024 * 1024 * 1024), 2) AS free_space_gb,
ROUND(((fs.allocated_space - fs.free_space) / fs.allocated_space) * 100, 2) AS used_pct,
ROUND(SUM(DECODE(tf.autoextensible, 'YES', tf.maxbytes, tf.bytes)) / (1024 * 1024 * 1024), 2) AS max_size_gb
FROM
dba_temp_free_space fs
JOIN
dba_temp_files tf ON fs.tablespace_name = tf.tablespace_name
GROUP BY
fs.tablespace_name, fs.allocated_space, fs.free_space
ORDER BY
used_pct DESC;
-- Cursor for Free Space Fragmentation (Section 5)
CURSOR fragmentation_cur IS
SELECT
tablespace_name,
COUNT(*) AS fragments,
ROUND(MAX(bytes) / (1024 * 1024 * 1024), 2) AS largest_chunk_gb,
ROUND(SUM(bytes) / (1024 * 1024 * 1024), 2) AS total_free_gb
FROM
dba_free_space
GROUP BY
tablespace_name
ORDER BY
fragments DESC;
-- Cursor for Real-Time Temporary Tablespace Usage (Section 6)
CURSOR realtime_temp_cur IS
SELECT
ts.tablespace_name,
ROUND(SUM(tf.bytes) / (1024 * 1024 * 1024), 2) AS total_temp_size_gb,
ROUND(SUM(tu.used_space) / (1024 * 1024 * 1024), 2) AS used_temp_space_gb,
ROUND(SUM(tf.bytes - tu.used_space) / (1024 * 1024 * 1024), 2) AS free_temp_space_gb,
ROUND((SUM(tu.used_space) / SUM(tf.bytes)) * 100, 2) AS used_pct
FROM
dba_temp_files tf
JOIN
dba_tablespaces ts ON tf.tablespace_name = ts.tablespace_name
LEFT JOIN (
SELECT tablespace_name, SUM(bytes_used) AS used_space
FROM gv$temp_space_header
GROUP BY tablespace_name
) tu ON ts.tablespace_name = tu.tablespace_name
WHERE
ts.contents = 'TEMPORARY'
GROUP BY
ts.tablespace_name
ORDER BY
ts.tablespace_name;
-- Variable to track if data was found for each section
v_data_found BOOLEAN;
BEGIN
-- Section 0: Database Summary
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Database Summary --');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE(RPAD('DB_NAME', 30) || RPAD('Total Allocated(GB)', 20) ||
RPAD('Total Used(GB)', 18) || RPAD('Total Free(GB)', 18) ||
RPAD('Used Pct(%)', 12));
DBMS_OUTPUT.PUT_LINE(RPAD('-', 30, '-') || ' ' || RPAD('-', 18, '-') || ' ' ||
RPAD('-', 16, '-') || ' ' || RPAD('-', 16, '-') || ' ' ||
RPAD('-', 10, '-')); -- Total: 96 chars
v_data_found := FALSE;
FOR rec IN db_summary_cur LOOP
v_data_found := TRUE;
DBMS_OUTPUT.PUT_LINE(RPAD(rec.db_name, 30) ||
RPAD(TO_CHAR(rec.total_allocated_gb, '999,999,999.99'), 20) ||
RPAD(TO_CHAR(rec.total_used_gb, '999,999,999.99'), 18) ||
RPAD(TO_CHAR(rec.total_free_gb, '999,999,999.99'), 18) ||
RPAD(TO_CHAR(rec.total_used_pct, '999.99'), 12));
END LOOP;
IF NOT v_data_found THEN
DBMS_OUTPUT.PUT_LINE('No data found for Database Summary. Check privileges or data in DBA_DATA_FILES/DBA_TABLESPACES.');
END IF;
-- Section 1: Overall Tablespace Utilization
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- 1. Overall Tablespace Utilization (Summary with Autoextend and Segments) --');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE(RPAD('TABLESPACE_NAME', 25) || RPAD('STATUS', 10) ||
RPAD('Allocated(GB)', 15) || RPAD('Used(GB)', 15) ||
RPAD('Segments(GB)', 15) || RPAD('Free(GB)', 15) ||
RPAD('Used Pct(%)', 12) || RPAD('Max Size(GB)', 15) ||
RPAD('Max Pct(%)', 12));
DBMS_OUTPUT.PUT_LINE(RPAD('-', 25, '-') || ' ' || RPAD('-', 8, '-') || ' ' ||
RPAD('-', 13, '-') || ' ' || RPAD('-', 13, '-') || ' ' ||
RPAD('-', 13, '-') || ' ' || RPAD('-', 13, '-') || ' ' ||
RPAD('-', 10, '-') || ' ' || RPAD('-', 13, '-') || ' ' ||
RPAD('-', 10, '-')); -- Total: 124 chars
v_data_found := FALSE;
FOR rec IN overall_tablespace_cur LOOP
v_data_found := TRUE;
DBMS_OUTPUT.PUT_LINE(RPAD(rec.tablespace_name, 25) ||
RPAD(rec.status, 10) ||
RPAD(TO_CHAR(rec.total_size_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.used_space_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.segments_used_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.free_space_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.allocated_pct_used, '999.99'), 12) ||
RPAD(TO_CHAR(rec.max_size_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.max_pct_used, '999.99'), 12));
END LOOP;
IF NOT v_data_found THEN
DBMS_OUTPUT.PUT_LINE('No data found for Overall Tablespace Utilization. Check privileges or data in DBA_TABLESPACES/DBA_DATA_FILES.');
END IF;
-- Section 2: Tablespace Utilization by Datafile
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- 2. Tablespace Utilization by Datafile (Granular) --');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE(RPAD('TABLESPACE_NAME', 25) || RPAD('FILE_NAME', 50) ||
RPAD('Current Size(GB)', 18) || RPAD('Used(GB)', 15) ||
RPAD('Free(GB)', 15) || RPAD('Used Pct(%)', 12) ||
RPAD('Autoextend?', 12) || RPAD('Max Size(GB)', 15));
DBMS_OUTPUT.PUT_LINE(RPAD('-', 25, '-') || ' ' || RPAD('-', 48, '-') || ' ' ||
RPAD('-', 16, '-') || ' ' || RPAD('-', 13, '-') || ' ' ||
RPAD('-', 13, '-') || ' ' || RPAD('-', 10, '-') || ' ' ||
RPAD('-', 10, '-') || ' ' || RPAD('-', 13, '-')); -- Total: 152 chars
v_data_found := FALSE;
FOR rec IN datafile_util_cur LOOP
v_data_found := TRUE;
DBMS_OUTPUT.PUT_LINE(RPAD(rec.tablespace_name, 25) ||
RPAD(SUBSTR(rec.file_name, 1, 50), 50) ||
RPAD(TO_CHAR(rec.current_size_gb, '999,999.99'), 18) ||
RPAD(TO_CHAR(rec.used_space_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.free_space_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.used_pct, '999.99'), 12) ||
RPAD(rec.autoextensible, 12) ||
RPAD(NVL(TO_CHAR(rec.max_size_gb, '999,999.99'), 'N/A'), 15));
END LOOP;
IF NOT v_data_found THEN
DBMS_OUTPUT.PUT_LINE('No data found for Tablespace Utilization by Datafile. Check privileges or data in DBA_DATA_FILES.');
END IF;
-- Section 3: Segment Level Utilization (Top 20 Largest Objects)
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- 3. Segment Level Utilization (Top 20 Largest Objects) --');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE(RPAD('OWNER', 20) || RPAD('SEGMENT_NAME', 30) ||
RPAD('PARTITION_NAME', 30) || RPAD('SEGMENT_TYPE', 15) ||
RPAD('TABLESPACE_NAME', 25) || RPAD('Size(GB)', 15));
DBMS_OUTPUT.PUT_LINE(RPAD('-', 20, '-') || ' ' || RPAD('-', 28, '-') || ' ' ||
RPAD('-', 28, '-') || ' ' || RPAD('-', 13, '-') || ' ' ||
RPAD('-', 23, '-') || ' ' || RPAD('-', 13, '-')); -- Total: 133 chars
v_data_found := FALSE;
FOR rec IN segment_util_cur LOOP
v_data_found := TRUE;
DBMS_OUTPUT.PUT_LINE(RPAD(rec.owner, 20) ||
RPAD(rec.segment_name, 30) ||
RPAD(NVL(rec.partition_name, 'NONE'), 30) ||
RPAD(rec.segment_type, 15) ||
RPAD(rec.tablespace_name, 25) ||
RPAD(TO_CHAR(rec.size_gb, '999,999.99'), 15));
END LOOP;
IF NOT v_data_found THEN
DBMS_OUTPUT.PUT_LINE('No data found for Segment Level Utilization. Check privileges or data in DBA_SEGMENTS.');
END IF;
-- Section 4: Temporary Tablespace Utilization
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- 4. Temporary Tablespace Utilization (Using DBA_TEMP_FREE_SPACE) --');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE(RPAD('TABLESPACE_NAME', 25) || RPAD('Allocated(GB)', 15) ||
RPAD('Used(GB)', 15) || RPAD('Free(GB)', 15) ||
RPAD('Used Pct(%)', 12) || RPAD('Max Size(GB)', 15));
DBMS_OUTPUT.PUT_LINE(RPAD('-', 25, '-') || ' ' || RPAD('-', 13, '-') || ' ' ||
RPAD('-', 13, '-') || ' ' || RPAD('-', 13, '-') || ' ' ||
RPAD('-', 10, '-') || ' ' || RPAD('-', 13, '-')); -- Total: 99 chars
v_data_found := FALSE;
FOR rec IN temp_tablespace_cur LOOP
v_data_found := TRUE;
DBMS_OUTPUT.PUT_LINE(RPAD(rec.tablespace_name, 25) ||
RPAD(TO_CHAR(rec.allocated_size_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.used_space_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.free_space_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.used_pct, '999.99'), 12) ||
RPAD(TO_CHAR(rec.max_size_gb, '999,999.99'), 15));
END LOOP;
IF NOT v_data_found THEN
DBMS_OUTPUT.PUT_LINE('No data found for Temporary Tablespace Utilization. Check privileges or data in DBA_TEMP_FREE_SPACE.');
END IF;
-- Section 5: Free Space Fragmentation
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- 5. Free Space Fragmentation by Tablespace --');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE(RPAD('TABLESPACE_NAME', 25) || RPAD('Fragments', 12) ||
RPAD('Largest Chunk(GB)', 18) || RPAD('Total Free(GB)', 15));
DBMS_OUTPUT.PUT_LINE(RPAD('-', 25, '-') || ' ' || RPAD('-', 10, '-') || ' ' ||
RPAD('-', 16, '-') || ' ' || RPAD('-', 13, '-')); -- Total: 70 chars
v_data_found := FALSE;
FOR rec IN fragmentation_cur LOOP
v_data_found := TRUE;
DBMS_OUTPUT.PUT_LINE(RPAD(rec.tablespace_name, 25) ||
RPAD(TO_CHAR(rec.fragments, '999,999'), 12) ||
RPAD(TO_CHAR(rec.largest_chunk_gb, '999,999.99'), 18) ||
RPAD(TO_CHAR(rec.total_free_gb, '999,999.99'), 15));
END LOOP;
IF NOT v_data_found THEN
DBMS_OUTPUT.PUT_LINE('No data found for Free Space Fragmentation. Check privileges or data in DBA_FREE_SPACE.');
END IF;
-- Section 6: Real-Time Temporary Tablespace Usage
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- 6. Real-Time Temporary Tablespace Usage (Using GV$TEMP_SPACE_HEADER) --');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE(RPAD('TABLESPACE_NAME', 25) || RPAD('Total Size(GB)', 15) ||
RPAD('Used(GB)', 15) || RPAD('Free(GB)', 15) ||
RPAD('Used Pct(%)', 12));
DBMS_OUTPUT.PUT_LINE(RPAD('-', 25, '-') || ' ' || RPAD('-', 13, '-') || ' ' ||
RPAD('-', 13, '-') || ' ' || RPAD('-', 13, '-') || ' ' ||
RPAD('-', 10, '-')); -- Total: 84 chars
v_data_found := FALSE;
FOR rec IN realtime_temp_cur LOOP
v_data_found := TRUE;
DBMS_OUTPUT.PUT_LINE(RPAD(rec.tablespace_name, 25) ||
RPAD(TO_CHAR(rec.total_temp_size_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.used_temp_space_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.free_temp_space_gb, '999,999.99'), 15) ||
RPAD(TO_CHAR(rec.used_pct, '999.99'), 12));
END LOOP;
IF NOT v_data_found THEN
DBMS_OUTPUT.PUT_LINE('No data found for Real-Time Temporary Tablespace Usage. Check privileges or data in DBA_TEMP_FILES/GV$TEMP_SPACE_HEADER.');
END IF;
-- Final message
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Comprehensive Oracle Database Storage and Space Utilization Report completed. --');
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE(' ');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error during report generation: ' || SQLERRM);
RAISE;
END;
END;
/
No comments:
Post a Comment