Answer
Rather than joining directly against the raw history table multiple times with correlated MIN(history_no) subqueries for each milestone, pre-aggregate each milestone into its own one-row-per-order derived table first, using a MIN(...) KEEP (DENSE_RANK FIRST ORDER BY history_no ASC) aggregate pattern grouped by order number for each specific message/status you care about, for example one derived table filtered to 'Released', another to 'Delivered', and so on. Then LEFT JOIN all of these already-small, already-aggregated one-row-per-order derived tables together on order number, rather than joining against the full history table repeatedly. This dramatically reduces the amount of intermediate work compared to correlated subqueries against the full-size history table, avoiding the TEMP-space exhaustion. A few related details worth keeping in mind for this kind of report: use TRUNC() rather than TO_DATE() when you just need the date portion of an already-DATE column; Oracle object/alias names are capped at 30 characters, so keep derived aliases concise; and use LEFT JOIN rather than a plain JOIN between these derived tables, or orders that haven't yet reached every downstream milestone, like ones not yet invoiced, will be silently dropped from the report entirely.