Chapter 05 · Oracle SQL Fundamentals: Joins, Subqueries, Set Operations, and Hierarchical Queries

SELECT Semantics, NULL, Expressions, Conversion, NLS Effects, and Deterministic Ordering

Make Oracle SELECT results dependable by separating SQL NULL from assumptions about empty strings, controlling conversion and NLS behavior, and ordering rows deterministically.

Intermediate → Advanced100–120 minutesSELECT semantics + NLS/ordering labOracle AI Database 26ai · RU 23.26.3 baselineOracle AI Database Free · SQLcl/SQL*Plus/SQL DeveloperLast reviewed: August 2026

Learning outcomes

ServiceHub is importing work-order events from several clients. One client sends an empty status string, another formats dates according to its local session, and a report uses ORDER BY priority even though many rows share the same priority. Every query looks reasonable in isolation, yet the application produces missing rows, ambiguous dates, and unstable pagination. This lesson turns those surprises into an Oracle-specific mental model.

01

Explain Oracle SQL’s current treatment of zero-length character strings and use IS NULL correctly.

02

Separate stored datetime values from NLS-dependent textual representations and implicit conversions.

03

Use explicit datetime literals and format models so SQL does not depend on session globalization settings.

04

Reason about expression evaluation, aliases, filtering, and deterministic ORDER BY behavior.

05

Build an evidence card that records the session NLS state before blaming data or the optimizer.

Prerequisite connection

Courses 01–02 established relational SQL and modeling, while Chapters 01–04 established the ServiceHub PDB/schema, instance, storage, and Oracle object/type semantics. Here the focus is not basic SELECT syntax; it is the Oracle behavior that can make otherwise portable-looking SQL mean something different.

Lab and version baseline

Mandatory examples target a disposable ServiceHub schema in Oracle AI Database Free 26ai. The chapter was reviewed against the July 2026 RU 23.26.3 documentation, SQL Developer 26.2, and SQLcl 26.2.1. No paid option, management pack, RAC, Data Guard, Exadata, or cloud service is required. Oracle AI Database Free remains limited to 2 foreground CPUs, 2 GB combined SGA/PGA memory, and 12 GB user data and receives no Oracle patches or Support service requests; use it as a learning engine, not a production default.

1. Start with values, not their display

Oracle stores a DATE in a fixed internal representation containing year, month, day, hour, minute, and second. It does not store the string 25-AUG-26 or 2026-08-25. Those strings are presentation or conversion choices. Likewise, NUMBER is not stored with your session’s decimal separator. This distinction matters because client and session settings can change how Oracle converts between typed values and text.

The session parameter NLS_DATE_FORMAT controls the default format used when a DATE is implicitly converted to text or when text is implicitly converted to DATE. NLS_NUMERIC_CHARACTERS similarly affects decimal and group separators in character/number conversion. SQL Developer, OCI-based clients, and JDBC clients can initialize session NLS values differently, so a database-level default is not proof of what a particular session actually uses.

sql · capture the session evidence before testing conversions
SELECT    SYS_CONTEXT('USERENV','CON_NAME') AS con_name,    SYS_CONTEXT('USERENV','CURRENT_SCHEMA') AS current_schema,    SESSIONTIMEZONE AS session_tzFROM dual;SELECT parameter, valueFROM nls_session_parametersWHERE parameter IN (    'NLS_DATE_FORMAT',    'NLS_TIMESTAMP_FORMAT',    'NLS_TIMESTAMP_TZ_FORMAT',    'NLS_DATE_LANGUAGE',    'NLS_NUMERIC_CHARACTERS')ORDER BY parameter;

This evidence proves the current session’s settings. It does not prove that another connection pool, SQL Developer worksheet, or application session uses the same settings.

2. Oracle SQL currently collapses a zero-length character string to NULL

In Oracle SQL, a zero-length character string is currently treated as NULL. That means an application that tries to distinguish “empty but present” from “missing” using VARCHAR2 and the literal '' does not get two distinguishable SQL states. This is a major portability difference from PostgreSQL and from engines that preserve an empty string as a non-null value.

sql · observe empty-string and NULL behavior
SELECT    CASE WHEN '' IS NULL THEN 'empty string behaves as NULL' ELSE 'distinct' END AS empty_test,    CASE WHEN LENGTH('') IS NULL THEN 'LENGTH returned NULL' ELSE 'length exists' END AS length_testFROM dual;SELECT 'matched' AS resultFROM dualWHERE '' = '';SELECT 'matched' AS resultFROM dualWHERE '' IS NULL;

The equality predicate does not return a row because comparisons with NULL evaluate to UNKNOWN, not true. IS NULL is the correct test. Do not “fix” this with = NULL; that has the same three-valued-logic problem.

Data-model consequence

If the business must distinguish “not supplied” from “supplied as an empty value,” model that distinction explicitly—for example with a status flag or a non-empty sentinel defined by the business. Do not rely on a zero-length VARCHAR2 as a second state.

3. Deliberately wrong approach: let NLS decide what a date string means

The most dangerous NLS bugs are often wrong results rather than syntax errors. The same text can represent different dates under different session formats. The following experiment changes only the session and asks Oracle to convert the same text without an explicit format model.

sql · the same text can mean two different dates
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MM-YYYY';SELECT TO_CHAR(TO_DATE('04-05-2026'), 'YYYY-MM-DD') AS interpreted_dateFROM dual;-- 2026-05-04ALTER SESSION SET NLS_DATE_FORMAT = 'MM-DD-YYYY';SELECT TO_CHAR(TO_DATE('04-05-2026'), 'YYYY-MM-DD') AS interpreted_dateFROM dual;-- 2026-04-05

Nothing about the character literal changed; the session interpretation did. This is precisely why production SQL should not use implicit text-to-date conversion for fixed-format application data.

sql · repair with typed literals or explicit format models
SELECT DATE '2026-05-04' AS typed_dateFROM dual;SELECT TO_DATE('2026-05-04', 'YYYY-MM-DD') AS parsed_dateFROM dual;SELECT TO_TIMESTAMP_TZ(         '2026-05-04 14:30:00 +04:00',         'YYYY-MM-DD HH24:MI:SS TZH:TZM'       ) AS parsed_timestampFROM dual;

Typed ANSI date literals are independent of NLS_DATE_FORMAT. Explicit format models make the text contract visible. Bind variables are even better when an application already holds a typed date/time value.

4. Logical query semantics and aliases

SQL is declarative: you describe the result, and Oracle is free to transform the execution as long as semantics are preserved. A useful reasoning order is FROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY, but this is a conceptual model, not a promise about physical execution order. The optimizer can reorder joins, push predicates, transform subqueries, and choose access paths.

One practical consequence is alias scope. A select-list alias is available to the final ORDER BY, but it is generally not available to the same query block’s WHERE clause because filtering conceptually occurs before projection.

sql · make an expression reusable with an inline view
SELECT event_id, total_amountFROM (    SELECT event_id,           labor_amount + parts_amount AS total_amount    FROM servicehub_sql_event)WHERE total_amount >= 500ORDER BY total_amount DESC, event_id;

This structure gives the expression a named result in an inner query block and then filters that result in an outer query block. Later lessons show how common table expressions and optimizer transformations affect the physical plan without changing the required result.

5. Deterministic ordering requires a complete tie-breaker

Without an ORDER BY, SQL result order is not guaranteed. Even with ORDER BY priority, rows that share the same priority have no specified relative order unless you add another ordering key. An index, hash join, parallel plan, changed statistics, or different fetch can expose that freedom.

sql · a stable application order includes a unique tie-breaker
SELECT event_id, priority, occurred_atFROM servicehub_sql_eventORDER BY priority DESC,         occurred_at DESC,         event_id ASC;

For pagination, the tie-breaker is essential. If the ordering keys are not unique, two executions can legally place equal-key rows differently, causing duplicates or omissions between pages. Also state the desired NULLS FIRST or NULLS LAST behavior when null placement matters to the application contract.

6. Hands-on lab: build a SELECT semantics probe

Run the lab as SERVICEHUB_OWNER in the disposable course PDB. It creates one small table, demonstrates Oracle’s empty-string behavior, records the session’s NLS state, and proves a deterministic order. Cleanup removes only the probe table.

sql · setup and evidence
DROP TABLE servicehub_sql_event IF EXISTS PURGE;CREATE TABLE servicehub_sql_event (    event_id      NUMBER PRIMARY KEY,    event_code    VARCHAR2(30) NOT NULL,    status_code   VARCHAR2(20),    priority      NUMBER NOT NULL,    occurred_at   DATE NOT NULL,    labor_amount  NUMBER(10,2) DEFAULT 0 NOT NULL,    parts_amount  NUMBER(10,2) DEFAULT 0 NOT NULL);INSERT INTO servicehub_sql_event    (event_id,event_code,status_code,priority,occurred_at,labor_amount,parts_amount)VALUES    (1,'EVT-001','OPEN',2,DATE '2026-08-25',300,250);INSERT INTO servicehub_sql_event    (event_id,event_code,status_code,priority,occurred_at,labor_amount,parts_amount)VALUES    (2,'EVT-002','',2,DATE '2026-08-25',100,50);INSERT INTO servicehub_sql_event    (event_id,event_code,status_code,priority,occurred_at,labor_amount,parts_amount)VALUES    (3,'EVT-003',NULL,1,DATE '2026-08-24',80,20);COMMIT;SELECT event_id, event_code,       CASE WHEN status_code IS NULL THEN 'NULL' ELSE status_code END AS status_evidenceFROM servicehub_sql_eventORDER BY event_id;SELECT event_id, priority, occurred_atFROM servicehub_sql_eventORDER BY priority DESC, occurred_at DESC, event_id;
sql · cleanup
DROP TABLE servicehub_sql_event PURGE;

Verification checklist:

  • Rows 2 and 3 both show a null status because the empty string was not preserved as a distinct VARCHAR2 value.
  • The stored dates are created from typed literals and do not depend on NLS_DATE_FORMAT.
  • The final ordering includes event_id as a unique tie-breaker.
  • Your NLS evidence comes from the current session, not a remembered database default.

7. Production judgment

Keep typed data typed across the application/database boundary. Use bind variables for dates and numbers, explicit format models at genuine text boundaries, and deterministic sort keys for APIs and pagination. NLS parameters are valuable for presentation and localization; they are poor hidden contracts for machine-to-machine data exchange. Record client/driver session initialization when investigating conversion bugs.

No special edition, option, pack, initialization parameter change, restart, or COMPATIBLE change is required for this lesson. The examples are PDB-local SQL. The main risks are correctness and security: implicit conversion can change results and, in dynamically constructed SQL, NLS-dependent conversion can even contribute to injection vulnerabilities. Lesson 2 moves from single-table semantics to joins, where row preservation and row multiplication create a different class of correctness failures.

8. Summary and next step

Oracle SQL currently treats zero-length character strings as null, three-valued logic requires IS NULL, NLS settings can change text conversion, typed literals and explicit formats remove ambiguity, and ordering is deterministic only when the complete ordering key resolves ties. With those foundations stable, the next lesson builds joins without accidentally losing or multiplying ServiceHub rows.

Check your understanding

  1. Why can an application not distinguish '' from NULL in a VARCHAR2 column using ordinary Oracle SQL semantics?
  2. Why is DATE '2026-05-04' safer than relying on a session to interpret '04-05-2026'?
  3. Does a database-level NLS_DATE_FORMAT prove what a JDBC connection will use?
  4. Why can ORDER BY priority still be nondeterministic?
  5. What is wrong with WHERE status_code = NULL?
Review the answers

Oracle currently treats a zero-length character string as NULL, so both states collapse at the SQL character-value boundary.

The typed DATE literal has an unambiguous SQL-defined representation and does not depend on NLS_DATE_FORMAT.

No. Client and session initialization can override database defaults; inspect the actual session.

Rows with equal priority have no specified relative order. Add a stable tie-breaker such as a unique event_id.

Equality with NULL evaluates to UNKNOWN. Use IS NULL or IS NOT NULL.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.