9.3 Set Operator Guidelines & ORDER BY Rules
Key Takeaways
- In all compound queries, the column names and column aliases in the final output are strictly determined by the SELECT list of the first query block.
- An ORDER BY clause can appear ONLY ONCE in a compound query, positioned at the very end of the entire statement, and must reference column names/aliases from the first query or 1-based numeric positions.
- Set operators cannot be performed on Large Object (LOB) datatypes (BLOB, CLOB, NCLOB, BFILE) or legacy LONG/LONG RAW datatypes (ORA-00932 / ORA-00997).
- All four set operators (UNION, UNION ALL, INTERSECT, MINUS) have equal precedence in Oracle SQL and are evaluated from left to right (top to bottom) unless overridden by parentheses.
- Compound queries can be embedded inside CREATE TABLE AS SELECT (CTAS), INSERT INTO ... SELECT, CREATE VIEW statements, and inline views in the FROM clause.
9.3 Set Operator Guidelines & ORDER BY Rules
Writing compound queries in Oracle SQL requires adhering to strict syntactic and structural rules established by the relational engine. While combining queries with UNION, UNION ALL, INTERSECT, and MINUS provides immense expressive power, the 1Z0-071 exam heavily tests edge cases, sorting limitations, datatype restrictions, and precedence behaviors.
This section breaks down the universal guidelines and common error traps associated with set operations in Oracle Database.
Output Column Names and Column Aliases
A fundamental rule of Oracle compound queries governs how column headers in the final output result set are labeled:
The Column Naming Rule: The column names and column aliases displayed in the final query result set are determined strictly and exclusively by the
SELECTlist of the first component query.
Any column aliases defined in the second, third, or subsequent component queries are completely ignored by Oracle for header formatting.
-- Demonstrating Column Header Determination
SELECT employee_id AS emp_identification, first_name AS given_name, salary AS monthly_compensation
FROM employees
WHERE department_id = 10
UNION ALL
SELECT contractor_id AS c_id, contractor_name AS c_name, hourly_rate * 160 AS rate
FROM contractors
WHERE department_id = 10;
OUTPUT COLUMN HEADERS:
+--------------------+------------+----------------------+
| EMP_IDENTIFICATION | GIVEN_NAME | MONTHLY_COMPENSATION |
+--------------------+------------+----------------------+
| 200 | Jennifer | 4400.00 |
| 901 | Robert | 8000.00 |
+--------------------+------------+----------------------+
Notice that the output headers use EMP_IDENTIFICATION, GIVEN_NAME, and MONTHLY_COMPENSATION from Query 1. The aliases C_ID, C_NAME, and RATE from Query 2 have no effect on output naming.
The Rules of the ORDER BY Clause in Compound Queries
Sorting data in compound queries follows very specific rules that differ significantly from single SELECT statements. Questions testing ORDER BY in set operations appear frequently on the 1Z0-071 exam.
+-----------------------------------------------------------------------------------+
| ORDER BY RULES IN SET OPERATIONS |
| |
| 1. Placement: Must appear ONLY ONCE at the VERY END of the compound query. |
| 2. Referencing: Must use Column Names/Aliases from QUERY 1, or Numeric Positions.|
| 3. Illegality: Cannot be placed on individual component queries (unless inline). |
+-----------------------------------------------------------------------------------+
Rule 1: Placement at the Very End
The ORDER BY clause can appear only once in the entire compound statement, and it must be the last clause of the final component query.
-- INVALID QUERY: ORDER BY inside component query raises ORA-00933
SELECT employee_id, first_name FROM employees WHERE department_id = 10
ORDER BY employee_id -- ERROR: ORDER BY cannot be placed here!
UNION ALL
SELECT contractor_id, contractor_name FROM contractors WHERE department_id = 10;
Oracle Error:
ORA-00933: SQL command not properly ended.
-- VALID QUERY: Single ORDER BY at the very end
SELECT employee_id, first_name FROM employees WHERE department_id = 10
UNION ALL
SELECT contractor_id, contractor_name FROM contractors WHERE department_id = 10
ORDER BY employee_id;
Rule 2: Valid Identifiers in the ORDER BY Clause
Because the result set column names are established by the first query block, the terminating ORDER BY clause can reference:
- Column names from the
SELECTlist of the first query. - Column aliases defined in the
SELECTlist of the first query. - 1-based numeric positional notation (
ORDER BY 1, 2 DESC).
Attempting to reference a column name or alias that exists only in the second or subsequent query blocks raises an ORA-00904 error:
-- INVALID QUERY: Referencing Query 2 alias in ORDER BY
SELECT employee_id AS emp_num, last_name FROM employees
UNION ALL
SELECT contractor_id AS cont_num, contractor_name FROM contractors
ORDER BY cont_num; -- ERROR: CONT_NUM is not recognized from Query 1
Oracle Error:
ORA-00904: "CONT_NUM": invalid identifier.
-- VALID CORRECTIONS:
-- Option A: Reference Query 1 alias
SELECT employee_id AS emp_num, last_name FROM employees
UNION ALL
SELECT contractor_id AS cont_num, contractor_name FROM contractors
ORDER BY emp_num;
-- Option B: Reference 1-based positional number
SELECT employee_id AS emp_num, last_name FROM employees
UNION ALL
SELECT contractor_id AS cont_num, contractor_name FROM contractors
ORDER BY 1 DESC;
Unsupported Datatypes in Set Operations
Not all Oracle datatypes can be used with set operators. Set operators must compare full row values to evaluate equality, perform deduplication, or sort records. Certain data structures do not support direct binary or hash comparisons in the relational engine.
+-----------------------------------------------------------------------------------+
| DATATYPE SUPPORT IN SET OPERATIONS |
| |
| SUPPORTED DATATYPES: |
| - Character: VARCHAR2, CHAR, NVARCHAR2, NCHAR |
| - Numeric: NUMBER, FLOAT, BINARY_FLOAT, BINARY_DOUBLE |
| - Datetime: DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, INTERVAL |
| - Identifiers: ROWID, UROWID |
| |
| UNSUPPORTED DATATYPES (Raise ORA-00932 / ORA-00997): |
| - Large Objects: BLOB, CLOB, NCLOB, BFILE |
| - Legacy Types: LONG, LONG RAW |
| - Collections: VARRAY, Nested Tables, Object Types (unless MAP method defined) |
+-----------------------------------------------------------------------------------+
Why LOBs and LONGs Are Prohibited
CLOBandBLOBcolumns can store gigabytes of unstructured data. Comparing multi-gigabyte LOB locators across millions of rows for sorting or duplicate elimination would exhaust memory and disk subsystems.LONGandLONG RAWcolumns are legacy storage formats with strict restrictions (e.g., only oneLONGcolumn per table, cannot be used inWHERE,GROUP BY,DISTINCT, or set operations).
-- INVALID QUERY: CLOB in set operation raises ORA-00932
SELECT document_id, document_title, document_body_clob FROM legal_docs_2024
UNION
SELECT document_id, document_title, document_body_clob FROM legal_docs_2025;
Oracle Error:
ORA-00932: inconsistent datatypes: expected - got CLOB.
Workaround for LOB Queries
If LOB data must be retrieved from compound sets, perform the set operation on unique primary keys first, or convert a bounded substring of the CLOB using DBMS_LOB.SUBSTR:
-- Valid Workaround: Substring extraction for comparison
SELECT document_id, DBMS_LOB.SUBSTR(document_body_clob, 4000, 1) AS doc_preview
FROM legal_docs_2024
UNION ALL
SELECT document_id, DBMS_LOB.SUBSTR(document_body_clob, 4000, 1) AS doc_preview
FROM legal_docs_2025;
Compound Query Precedence & Parenthetical Grouping
When three or more component queries are combined using multiple set operators, Oracle evaluates them according to strict precedence rules:
The Precedence Rule: All four set operators (
UNION,UNION ALL,INTERSECT,MINUS) have EQUAL precedence. Oracle evaluates compound queries strictly from left to right (top to bottom) in the order they appear in the SQL text.
DEFAULT EVALUATION FLOW (Equal Precedence - Left to Right):
Query A \
--- [Operator 1] ---> Intermediate Result Set \
Query B / --- [Operator 2] ---> Final Result
Query C /
Overriding Precedence with Parentheses
To alter the default top-to-bottom evaluation sequence, you can enclose component queries within parentheses. The parenthesized compound query will be evaluated first, and its result set will be passed to the outer operator.
PARENTHESIZED EVALUATION FLOW:
Query B \
--- [Operator 2] ---> Intermediate Set
Query C / |
v
Query A ------------------------------------------------------------> [Operator 1] ---> Final Result
Concrete Example: Precedence Impact on Output
Consider three sets of numbers:
- $\text{Set } A = {1, 2, 3, 4}$
- $\text{Set } B = {3, 4, 5, 6}$
- $\text{Set } C = {4, 5, 7}$
Scenario 1: Default Left-to-Right Evaluation (A UNION B MINUS C)
SELECT num FROM set_a
UNION
SELECT num FROM set_b
MINUS
SELECT num FROM set_c;
- First operation:
Set A UNION Set B$\rightarrow {1, 2, 3, 4, 5, 6}$ - Second operation:
\{1, 2, 3, 4, 5, 6\} MINUS Set C (\{4, 5, 7\})$\rightarrow \mathbf{{1, 2, 3, 6}}$
Scenario 2: Parenthesized Evaluation (A UNION (B MINUS C))
SELECT num FROM set_a
UNION
(SELECT num FROM set_b
MINUS
SELECT num FROM set_c);
- Parenthesized operation:
Set B MINUS Set C$\rightarrow {3, 4, 5, 6} - {4, 5, 7} = {3, 6}$ - Outer operation:
Set A (\{1, 2, 3, 4\}) UNION \{3, 6\}$\rightarrow \mathbf{{1, 2, 3, 4, 6}}$
Key Takeaway:
Scenario 1returns[1, 2, 3, 6], whereasScenario 2returns[1, 2, 3, 4, 6]. Adding parentheses completely changes the outcome!
Compound Queries in DDL, DML, and Subqueries
Compound queries can be seamlessly integrated into broader SQL statements:
1. Create Table As Select (CTAS)
CREATE TABLE all_active_personnel AS
SELECT employee_id, first_name, last_name, email, hire_date FROM employees
UNION ALL
SELECT contractor_id, first_name, last_name, email, contract_start FROM contractors;
2. Multi-Row Insert via Subquery
INSERT INTO audit_log_summary (user_id, action_date, action_name)
SELECT user_id, login_time, 'LOGIN' FROM login_history
UNION ALL
SELECT user_id, logout_time, 'LOGOUT' FROM logout_history;
3. Inline Views in the FROM Clause
SELECT department_id, COUNT(*) AS staff_count, AVG(compensation) AS avg_comp
FROM (
SELECT department_id, salary AS compensation FROM employees
UNION ALL
SELECT department_id, hourly_rate * 160 AS compensation FROM contractors
)
GROUP BY department_id
HAVING COUNT(*) > 5
ORDER BY avg_comp DESC;
Common Set Operator Errors Reference Guide
| Oracle Error Code | Error Message | Underlying Cause | Resolution Strategy |
|---|---|---|---|
ORA-01789 | query block has incorrect number of result columns | Component queries have different column counts (e.g., Query 1 has 3 cols, Query 2 has 4 cols). | Add matching placeholder literals (NULL, 0, '') to balance column counts. |
ORA-01790 | expression must have same datatype as corresponding expression | Columns in the same positional slot belong to incompatible datatype families (e.g., DATE vs VARCHAR2). | Use explicit conversion functions (TO_CHAR, TO_DATE, TO_NUMBER) to match types. |
ORA-00933 | SQL command not properly ended | An ORDER BY clause was placed inside an individual component query instead of at the very end. | Move the ORDER BY clause to the very end of the compound statement. |
ORA-00904 | "NAME": invalid identifier | The ORDER BY clause referenced a column name or alias that exists only in Query 2 or subsequent queries. | Reference column names/aliases from Query 1, or use positional sorting (ORDER BY 1). |
ORA-00932 | inconsistent datatypes: expected - got CLOB | A set operator was attempted on an unsupported datatype (CLOB, BLOB, BFILE). | Remove LOB columns, query by primary key, or use DBMS_LOB.SUBSTR(). |
ORA-00997 | illegal use of LONG datatype | A set operator was attempted on a LONG or LONG RAW column. | Migrate column to CLOB/VARCHAR2 or exclude from the set operation. |
Examine the following compound query in Oracle SQL: SELECT employee_id AS emp_num, first_name || ' ' || last_name AS full_name, salary FROM employees WHERE department_id = 10 UNION ALL SELECT contractor_id AS cont_id, contractor_name AS c_name, hourly_rate * 2000 AS annual_pay FROM contractors WHERE department_id = 10 ORDER BY full_name; What column headers are displayed in the final output result set, and does the ORDER BY clause execute successfully?
Why does the following SQL statement fail to execute in Oracle Database? SELECT product_id, product_name, product_description FROM inventory_archive UNION SELECT product_id, product_name, product_description FROM inventory_active; (Assume PRODUCT_DESCRIPTION is defined with the CLOB datatype).
Examine the following compound query with multiple set operators: SELECT dept_id FROM t1 UNION SELECT dept_id FROM t2 MINUS SELECT dept_id FROM t3; Given that all set operators have equal precedence in Oracle SQL and evaluate from left to right, how can a developer force the MINUS operation between T2 and T3 to execute before the UNION with T1?