Monday, May 18, 2026

Non-Equijoins and Self-Joins in Oracle SQL

Non-Equijoins and Self-Joins in Oracle SQL

Non-Equijoins and Self-Joins in Oracle SQL: Complete Guide

Most joins in SQL use the equality operator. However, many real-world business requirements demand joining tables using conditions other than equality. This comprehensive guide covers two advanced and powerful join techniques: Non-Equijoins and Self-Joins.

Learning Objectives
By the end of this guide you will be able to write Non-Equijoins using range operators, perform Self-Joins for hierarchical data, understand performance implications, avoid common mistakes, and apply best practices in real Oracle environments.

1. Understanding Non-Equijoins

A Non-Equijoin is a join that uses a comparison operator other than the equals sign. This includes >, <, >=, <=, BETWEEN, and <>.

When Should You Use Non-Equijoins?

Non-Equijoins are required when relationships between data are based on ranges rather than exact matches. Common business scenarios include:

  • Determining salary grades based on employee compensation ranges
  • Calculating tiered discounts based on purchase volume
  • Matching records within specific date or numeric ranges
  • Assigning tax brackets based on income levels
  • Comparing values across different thresholds or boundaries

Real-World Example 1: Employee Salary Grade Assignment

Let us consider two tables: employees and salary_grades.

CREATE TABLE employees (
  employee_id   NUMBER PRIMARY KEY,
  first_name    VARCHAR2(50),
  salary        NUMBER
);

CREATE TABLE salary_grades (
  grade_level   VARCHAR2(10),
  lowest_sal    NUMBER,
  highest_sal   NUMBER
);

Sample Data:

INSERT INTO employees VALUES (101, 'John', 8500);
INSERT INTO employees VALUES (102, 'Sarah', 12500);
INSERT INTO employees VALUES (103, 'Michael', 6200);
INSERT INTO employees VALUES (104, 'Emily', 9500);
INSERT INTO employees VALUES (105, 'Robert', 15200);

INSERT INTO salary_grades VALUES ('A', 5000, 7999);
INSERT INTO salary_grades VALUES ('B', 8000, 10999);
INSERT INTO salary_grades VALUES ('C', 11000, 14999);
INSERT INTO salary_grades VALUES ('D', 15000, 19999);
INSERT INTO salary_grades VALUES ('E', 20000, 30000);

Expected Result:

EMPLOYEE_IDFIRST_NAMESALARYGRADE_LEVEL
101John8500B
102Sarah12500C
103Michael6200A
104Emily9500B
105Robert15200D

How it works: For each employee row, Oracle checks the BETWEEN condition against every salary grade row. Because the ranges are contiguous and non-overlapping, each employee receives exactly one grade.

Important: If your grade ranges overlap, the query will return multiple rows per employee. Always ensure business rules produce mutually exclusive ranges.

Real-World Example 2: Product Discount Tiers

Another common scenario is assigning discount percentages based on order value ranges.

SELECT o.order_id, o.order_total, d.tier_name, d.discount_pct
FROM   orders o
JOIN   discount_tiers d
  ON   o.order_total BETWEEN d.min_amount AND d.max_amount;

Real-World Example 3: Contract Validity Using Date Ranges

SELECT c.contract_id, c.customer_name, p.price
FROM   contracts c
JOIN   price_history p
  ON   c.contract_date BETWEEN p.effective_from AND p.effective_to;

Multiple Conditions in Non-Equijoin

ON e.salary BETWEEN s.low_sal AND s.high_sal
   AND e.hire_date >= s.grade_start_date

2. Understanding Self-Joins

A Self-Join is a regular join in which a table is joined with itself. This technique is essential when dealing with hierarchical or recursive data stored within a single table.

Common Use Cases of Self-Joins

  • Displaying employees and their managers
  • Managing category and sub-category relationships
  • Handling bill of materials (BOM) structures
  • Finding duplicate or similar records within the same table
  • Comparing current and previous records in time-series data

Detailed Example: Employee and Manager Hierarchy

Consider the following employees table with a self-referencing manager_id column:

INSERT INTO employees VALUES (100, 'CEO', NULL);
INSERT INTO employees VALUES (101, 'VP Sales', 100);
INSERT INTO employees VALUES (102, 'VP Engineering', 100);
INSERT INTO employees VALUES (103, 'Sales Manager', 101);
INSERT INTO employees VALUES (104, 'Engineer Lead', 102);
INSERT INTO employees VALUES (105, 'Junior Engineer', 104);

Self-Join Query:

SELECT e.first_name AS employee_name,
       m.first_name AS manager_name
FROM employees e
LEFT JOIN employees m 
  ON e.manager_id = m.employee_id
ORDER BY e.employee_id;

Result:

EMPLOYEE_NAMEMANAGER_NAME
CEO(null)
VP SalesCEO
VP EngineeringCEO
Sales ManagerVP Sales
Engineer LeadVP Engineering
Junior EngineerEngineer Lead

The LEFT JOIN ensures the top-level manager appears even when manager_id is NULL.

Going Deeper: Manager of Manager

SELECT e.first_name AS employee,
       m1.first_name AS direct_manager,
       m2.first_name AS manager_of_manager
FROM   employees e
LEFT JOIN employees m1 ON e.manager_id = m1.employee_id
LEFT JOIN employees m2 ON m1.manager_id = m2.employee_id;

Combined Example: Employees Earning More Than Their Manager

This query uses both a Self-Join and a Non-Equijoin condition:

SELECT e.first_name AS employee,
       e.salary AS emp_salary,
       m.first_name AS manager,
       m.salary AS mgr_salary
FROM   employees e
JOIN   employees m ON e.manager_id = m.employee_id
WHERE  e.salary > m.salary;

Finding Duplicates with Self-Join

SELECT a.customer_id, a.email
FROM   customers a
JOIN   customers b ON a.email = b.email
                  AND a.customer_id < b.customer_id;

3. Performance Considerations

Both Non-Equijoins and Self-Joins can impact query performance if not implemented carefully.

  • Non-Equijoins often result in full table scans on large tables without proper indexing on range columns.
  • Self-Joins require indexes on the join columns (especially foreign keys like manager_id).
  • Using BETWEEN is generally more efficient and readable than multiple AND conditions.
  • Always review the execution plan for queries involving these join types on large datasets.
  • Keep lookup tables (salary_grades, discount_tiers) small and well-indexed.

4. Common Mistakes and How to Avoid Them

  1. Missing or Incorrect Table Aliases in Self-Joins
    Always use different aliases. Without them Oracle throws an "ambiguous column reference" error.
  2. Ignoring NULL Values in Hierarchical Data
    Top-level managers have NULL in manager_id. Use LEFT JOIN instead of INNER JOIN.
  3. Using Non-Equijoins Without Indexes
    Range conditions perform poorly on large tables without indexes on the columns involved.
  4. Overlapping Ranges
    If grade or tier ranges overlap, you will get duplicate rows per employee/order.
  5. Overcomplicating Queries
    Sometimes a subquery or different table design is cleaner than forcing a Non-Equijoin.

5. Best Practices

  • Always use meaningful and consistent table aliases in Self-Joins.
  • Index columns used in Non-Equijoin conditions for better performance.
  • Prefer BETWEEN over multiple comparison operators when working with ranges.
  • Handle NULL values explicitly when dealing with hierarchical relationships.
  • Test performance with realistic data volumes before production.
  • Document complex join logic clearly for future maintenance.

6. Practice Exercises

Exercise 1: Add an employee with salary 7800. Which grade will they receive?

Exercise 2: Write a query showing each employee with their manager’s manager (two levels up).

Exercise 3: Find all pairs of employees who earn within $500 of each other using a Self-Join.

Exercise 4: Create a Non-Equijoin that assigns performance bands (Low/Medium/High) from a separate scores table.

7. Interactive Practice Quiz

Q1. Which of the following is an example of a Non-Equijoin?

Q2. What does a Self-Join actually do?

Q3. What happens if you do not use table aliases in a Self-Join?

Conclusion

Non-Equijoins and Self-Joins are powerful and essential techniques in Oracle SQL. Non-Equijoins allow you to work with range-based conditions, while Self-Joins enable you to handle hierarchical relationships within a single table.

Mastering these join types will significantly improve your ability to write complex, efficient, and business-relevant SQL queries.

Always remember to consider performance implications and follow best practices when implementing these joins in production environments.

Friday, March 27, 2026

Oracle SQL Implicit Conversion and ROWNUM Explained

Oracle SQL Implicit Conversion and ROWNUM Explained

Oracle SQL: Implicit Conversion and ROWNUM Explained

Oracle SQL is very flexible, but this flexibility can sometimes lead to unexpected results. Two areas where developers often face surprises are Implicit Conversion and ROWNUM. This guide explains both concepts clearly with practical examples.

1. Implicit Conversion in Oracle SQL

Oracle automatically converts data types when it can. This is called implicit conversion. While convenient, it can cause performance problems and incorrect results if not understood properly.

Common Implicit Conversion Scenarios

Example 1: VARCHAR2 to NUMBER

CREATE TABLE employees (
  emp_id     VARCHAR2(10),
  salary     NUMBER
);

-- This works because Oracle converts '101' to number
SELECT * FROM employees WHERE emp_id = 101;

Oracle converts the string '101' to number 101 to compare with the column. However, this can prevent index usage in some cases.

Example 2: DATE and String Comparison

SELECT * FROM employees 
WHERE hire_date = '01-JAN-2023';

Oracle converts the string to a DATE using the default date format (usually DD-MON-YYYY). This works but is risky if the session date format changes.

Best Practice: Always use explicit conversion functions like TO_NUMBER(), TO_DATE(), or TO_CHAR() for clarity and performance.

Why Implicit Conversion Can Be Dangerous

  • Can cause full table scans even when indexes exist
  • May lead to incorrect results with different session settings
  • Makes code harder to debug

2. ROWNUM in Oracle SQL

ROWNUM is a pseudocolumn that returns a number indicating the order in which Oracle selects rows from a table. It is very useful but has some important behaviors that often confuse developers.

How ROWNUM Works

SELECT ROWNUM, first_name, salary
FROM employees;

ROWNUM is assigned before the ORDER BY clause is processed. This is the most common source of confusion.

Common Mistake: Using ROWNUM with ORDER BY

-- Wrong way to get top 5 highest paid employees
SELECT ROWNUM, first_name, salary
FROM employees
ORDER BY salary DESC;

This does not give the top 5 highest salaries because ROWNUM is assigned before sorting.

Correct Way: Using ROWNUM with Subquery

SELECT ROWNUM, first_name, salary
FROM (
  SELECT first_name, salary
  FROM employees
  ORDER BY salary DESC
)
WHERE ROWNUM <= 5;

This works correctly because the inner query sorts first, then ROWNUM is applied on the sorted result.

Other Useful ROWNUM Patterns

-- Get rows 6 to 10 (pagination)
SELECT * FROM (
  SELECT ROWNUM rn, first_name, salary
  FROM employees
  ORDER BY salary DESC
)
WHERE rn BETWEEN 6 AND 10;

Key Takeaways

  • Always use explicit conversion when data types might differ
  • ROWNUM is assigned before ORDER BY
  • Use a subquery when you need to sort first and then limit rows with ROWNUM
  • Be careful with implicit conversion in WHERE clauses — it can hurt performance

Interactive Quiz

Q1. What happens when you compare a VARCHAR2 column with a number using = ?

Q2. When is ROWNUM assigned to rows?

Q3. What is the correct way to get the top 5 highest paid employees using ROWNUM?

Oracle SQL Relational Database Concepts: Tables, Keys and Relationships

Oracle SQL: Relational Database Concepts Explained

Oracle SQL: Relational Database Concepts Explained

Relational databases are the foundation of modern data management systems. Oracle Database, being one of the most powerful and widely used relational database management systems in the world, is built entirely on relational database principles. If you want to truly master Oracle SQL, you must first develop a strong understanding of these fundamental concepts.

In this detailed guide, we will explore every important concept step by step with clear explanations, realistic tables, practical Oracle SQL examples, diagrams, and best practices. By the end of this article, you will have a solid foundation to design efficient databases and write better SQL queries.

1. What is a Relational Database?

A relational database is a type of database that stores and organizes data in the form of tables. These tables are connected to each other through well-defined relationships. The term "relational" comes from the mathematical concept of relations, which in this context refers to tables.

Before the invention of relational databases in the 1970s by Edgar F. Codd, data was typically stored in flat files or hierarchical structures. These older systems had many limitations — they were difficult to query, led to massive data duplication, and made it hard to maintain data consistency.

Relational databases solved these problems by introducing a clean, logical, and mathematically sound way to store and relate data. Today, almost every major application — from banking systems to e-commerce websites to enterprise resource planning (ERP) systems — uses relational databases.

Key Advantages of Relational Databases

  • Data Integrity: Rules and constraints (such as primary keys, foreign keys, and check constraints) ensure that data remains accurate and consistent at all times.
  • Reduced Redundancy: Information is stored only once in the database. When needed, it is referenced from other tables using relationships. This dramatically reduces storage requirements and eliminates update anomalies.
  • Flexibility: Data from multiple tables can be easily combined using JOIN operations. This allows complex questions to be answered efficiently.
  • Security: Relational databases support fine-grained access control. You can control who can see or modify data at the table, row, or even column level.
  • Scalability: Well-designed relational databases can handle enormous volumes of data while maintaining good performance.

2. Core Building Blocks: Tables, Rows, and Columns

Table (Relation)

A table is the basic unit of storage in a relational database. It represents a single entity or concept in the real world. For example, you might have one table for employees, another table for departments, another for customers, and another for orders.

Every table has a fixed structure defined by its columns. This structure is created when you execute the CREATE TABLE statement in Oracle SQL. The structure tells Oracle what kind of data each column can hold (numbers, text, dates, etc.).

Row (Record or Tuple)

A row represents one complete instance of the entity described by the table. If your table is called employees, then each row in that table represents one individual employee. A row contains one value for every column defined in the table.

Column (Attribute or Field)

A column defines a specific piece of information that must be stored for every row. For example, in an employees table you might have columns such as first_name, last_name, email, hire_date, and salary. Every employee row must have values for these columns (subject to any NULL constraints you define).

Practical Oracle Example

CREATE TABLE employees (
  employee_id   NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  first_name    VARCHAR2(50),
  last_name     VARCHAR2(50),
  email         VARCHAR2(100),
  hire_date     DATE,
  salary        NUMBER(10,2),
  department_id NUMBER
);

3. Primary Keys – Uniquely Identifying Each Record

A primary key is a column (or a combination of columns) that uniquely identifies each row in a table. It is one of the most important and fundamental concepts in relational database design.

Characteristics of a Good Primary Key

  • It must be unique — no two rows can have the same primary key value.
  • It cannot be NULL — every row must have a primary key value.
  • It should be stable — it should not change frequently over time.
  • It should be as simple as possible — preferably a single column.

Types of Primary Keys

Surrogate Key: This is an artificial key created specifically for identification purposes. The most common example is an auto-incrementing number. In Oracle, we use GENERATED ALWAYS AS IDENTITY columns. Surrogate keys are highly recommended because they never change and have no business meaning.

Natural Key: This is a key that already exists in the real world, such as an email address, employee code, or social security number. While natural keys can work, they are risky because they can change over time (people change emails, companies change employee codes, etc.).

Creating Primary Key in Oracle (Recommended Way)

CREATE TABLE departments (
  department_id   NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  department_name VARCHAR2(100) NOT NULL,
  location_id     NUMBER
);
Best Practice: In modern Oracle databases (12c and later), always use GENERATED ALWAYS AS IDENTITY to create surrogate primary keys. This is much cleaner than manually managing sequences and triggers.

4. Foreign Keys – Linking Tables Together

A foreign key is a column (or set of columns) in one table that creates a link to the primary key of another table. Foreign keys are what make relational databases truly powerful because they allow you to relate data across multiple tables.

Purpose of Foreign Keys

  • Enforce referential integrity — you cannot insert an employee record that points to a non-existent department.
  • Prevent orphan records — records that point to nothing useful.
  • Enable efficient JOIN operations between tables.

Creating a Foreign Key Constraint in Oracle

CREATE TABLE employees (
  employee_id     NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  first_name      VARCHAR2(50) NOT NULL,
  last_name       VARCHAR2(50) NOT NULL,
  department_id   NUMBER,
  CONSTRAINT fk_emp_dept 
    FOREIGN KEY (department_id) 
    REFERENCES departments(department_id)
);

5. Types of Relationships Between Tables

One-to-Many Relationship (Most Common)

This is by far the most common type of relationship in relational databases. One record in the "parent" table can be related to many records in the "child" table, but each child record belongs to only one parent.

Real-world example: One department can have many employees, but each employee belongs to exactly one department.

Many-to-Many Relationship

In this relationship, many records in one table can be related to many records in another table. This type of relationship cannot be directly represented in a relational database and requires a third "junction" or "bridge" table.

Real-world example: A student can enroll in many courses, and each course can have many students enrolled in it.

CREATE TABLE enrollments (
  student_id NUMBER,
  course_id  NUMBER,
  grade      VARCHAR2(2),
  PRIMARY KEY (student_id, course_id),
  FOREIGN KEY (student_id) REFERENCES students(student_id),
  FOREIGN KEY (course_id) REFERENCES courses(course_id)
);

One-to-One Relationship

In this relationship, one record in one table is linked to exactly one record in another table. This is less common but useful when you want to separate sensitive data or when a single table would otherwise become too wide.

6. Normalization – Organizing Data to Reduce Redundancy

Normalization is the process of organizing data in a relational database to minimize redundancy and avoid data anomalies. There are several "normal forms," but for most practical purposes, the first three normal forms are sufficient.

First Normal Form (1NF)

Each column must contain only atomic (indivisible) values. No column should contain lists or repeating groups. Every row must be unique.

Second Normal Form (2NF)

The table must be in 1NF, and every non-key column must depend on the entire primary key (no partial dependency on part of a composite primary key).

Third Normal Form (3NF)

The table must be in 2NF, and no non-key column should depend on another non-key column (no transitive dependency).

Important Warning: While normalization is extremely important for data integrity, over-normalizing your database can lead to too many tables and slower query performance. Always strike a balance between normalization and performance based on your specific requirements.

7. ACID Properties – Guaranteeing Reliable Transactions

Relational databases follow four important properties known collectively as ACID. These properties guarantee that database transactions are processed reliably even in the presence of errors, power failures, or concurrent access.

  • Atomicity: A transaction is treated as a single, indivisible unit. Either all operations in the transaction succeed, or none of them do.
  • Consistency: A transaction must bring the database from one valid state to another valid state, maintaining all defined rules and constraints.
  • Isolation: Concurrent transactions do not interfere with each other. Each transaction sees the database in a consistent state.
  • Durability: Once a transaction has been committed, it remains committed even if the system crashes immediately afterward.

8. Common Design Mistakes Beginners Make

  1. Using email or phone number as primary key — These values can change over time, breaking all relationships.
  2. Storing the same information in multiple tables — This leads to update anomalies and data inconsistency.
  3. Not defining foreign key constraints — This allows invalid data (orphan records) to enter your system.
  4. Creating tables that are too wide — Tables with 30–40 columns become difficult to maintain and query.
  5. Ignoring indexing strategy — Poor indexing is one of the most common causes of slow database performance.

9. Best Practices for Oracle Database Design

  • Always define a primary key for every table you create.
  • Prefer surrogate keys (using GENERATED ALWAYS AS IDENTITY) over natural keys.
  • Always define foreign key constraints to enforce referential integrity.
  • Normalize your database to at least Third Normal Form (3NF) unless you have a strong performance reason not to.
  • Use consistent and meaningful naming conventions for tables and columns.
  • Document your database design thoroughly so others can understand it.

10. Summary and Key Takeaways

Understanding relational database concepts is absolutely essential for anyone who works with Oracle SQL. Tables, rows, columns, primary keys, foreign keys, and different types of relationships form the foundation upon which all Oracle databases are built.

When you take the time to design your database properly from the very beginning, you avoid countless problems later in the project lifecycle. Good database design leads to better data quality, easier maintenance, more efficient queries, and happier developers and users.

Interactive Quiz

Q1. What is the main purpose of a Primary Key?

Q2. What does a Foreign Key do?

Q3. Which relationship type is most common in relational databases?

Oracle SQL MERGE Statement and Advanced DML Patterns

Oracle SQL MERGE Statement and Advanced DML Patterns

Oracle SQL MERGE Statement and Advanced DML Patterns

MERGE solves the common "upsert" problem — when you have a source of data and need to update matching rows in a target table while inserting rows that do not yet exist, all in a single efficient operation.

This guide covers the full MERGE syntax, the optional DELETE clause inside WHEN MATCHED, how to make WHEN clauses optional, proper use of DEFAULT values, the explicit DEFAULT keyword, and important rules around multi-row DML and constraint checking.

In this post
MERGE syntax and semantics • WHEN MATCHED with optional DELETE • Optional WHEN clauses • DEFAULT values and the DEFAULT keyword • Multi-row DML constraint behavior • Practice questions

1. MERGE — the combined INSERT/UPDATE statement

MERGE solves the "upsert" problem — when you have new data in a staging table and want to update existing rows in the target while inserting new ones. Without MERGE you would need separate UPDATE and INSERT statements with additional logic to decide which rows need which operation.

-- The problem MERGE solves:
-- You have new employee data in a staging table (emp_updates)
-- For each row: if the employee already exists, UPDATE them
--               if they don't exist yet, INSERT them

-- Without MERGE: two separate statements with subquery logic
UPDATE employees SET salary = ...
WHERE  employee_id IN (SELECT employee_id FROM emp_updates);

INSERT INTO employees ...
SELECT * FROM emp_updates
WHERE  employee_id NOT IN (SELECT employee_id FROM employees);

-- With MERGE: one statement handles both cases cleanly
MERGE is DML: Like INSERT, UPDATE, and DELETE, MERGE is a DML statement. It participates in transactions — it can be rolled back until COMMIT is issued.

2. MERGE full syntax

The MERGE syntax has four key parts: the target table, the source, the join condition, and the WHEN clauses.

MERGE INTO employees e                     -- target table
USING      emp_updates u                    -- source table (or subquery)
ON        (e.employee_id = u.employee_id)   -- join condition
WHEN MATCHED THEN                           -- row exists in target
    UPDATE SET
        e.salary        = u.salary,
        e.department_id = u.department_id
WHEN NOT MATCHED THEN                       -- row does not exist in target
    INSERT (employee_id, last_name, salary, department_id)
    VALUES (u.employee_id, u.last_name, u.salary, u.department_id);
PartKeywordPurpose
TargetMERGE INTOThe table being updated or inserted into
SourceUSINGThe data source — a table, view, or subquery
Join conditionON (...)How to match source rows to target rows
Matched rowsWHEN MATCHED THEN UPDATEWhat to do when source row matches target
Unmatched rowsWHEN NOT MATCHED THEN INSERTWhat to do when source row has no match in target
Cannot UPDATE the join column in WHEN MATCHED: The column used in the ON condition cannot be updated in the WHEN MATCHED UPDATE clause. Oracle raises an error if you attempt this.

3. MERGE with WHEN NOT MATCHED

WHEN NOT MATCHED fires for every source row that has no matching row in the target table. You can also add an optional WHERE clause to filter which unmatched rows get inserted.

MERGE INTO employees e
USING      new_hires n
ON        (e.employee_id = n.employee_id)
WHEN NOT MATCHED THEN
    INSERT (employee_id, last_name, email, hire_date, job_id, salary)
    VALUES (n.employee_id, n.last_name, n.email,
             n.hire_date, n.job_id, n.salary)
    WHERE  n.hire_date >= TO_DATE('01-JAN-2024', 'DD-MON-YYYY');
-- The optional WHERE on WHEN NOT MATCHED filters which unmatched rows get inserted
Optional WHERE on WHEN clauses: Both WHEN MATCHED and WHEN NOT MATCHED support their own WHERE clause for fine-grained control.

4. MERGE with WHEN MATCHED — optional DELETE

WHEN MATCHED can include an optional DELETE clause in addition to UPDATE. A row that is matched and updated can also be deleted in the same operation if it satisfies the DELETE condition.

MERGE INTO employees e
USING      emp_changes c
ON        (e.employee_id = c.employee_id)
WHEN MATCHED THEN
    UPDATE SET e.salary = c.new_salary,
               e.job_id = c.new_job_id
    DELETE WHERE (c.status = 'TERMINATED');
-- Step 1: UPDATE is applied to all matched rows
-- Step 2: Of the rows just updated, those where status = 'TERMINATED' are deleted
DELETE condition uses updated values: The DELETE WHERE condition is evaluated after the UPDATE has been applied.

5. Making WHEN clauses optional

Both WHEN MATCHED and WHEN NOT MATCHED are optional. You only need to include the clauses you actually need.

-- UPDATE only — no INSERT for new rows
MERGE INTO employees e
USING      salary_updates u
ON        (e.employee_id = u.employee_id)
WHEN MATCHED THEN
    UPDATE SET e.salary = u.new_salary;
-- Unmatched source rows are silently ignored

-- INSERT only — no UPDATE for existing rows
MERGE INTO employees e
USING      new_hires n
ON        (e.employee_id = n.employee_id)
WHEN NOT MATCHED THEN
    INSERT (employee_id, last_name, salary)
    VALUES (n.employee_id, n.last_name, n.salary);
-- Matched rows are silently ignored
Clauses presentBehaviour
WHEN MATCHED onlyUpdates matched rows — unmatched source rows ignored
WHEN NOT MATCHED onlyInserts unmatched rows — matched rows ignored
Both clausesUpdates matched, inserts unmatched — full upsert
Neither clauseSyntax error — at least one WHEN clause required

6. DEFAULT values in INSERT and UPDATE

A DEFAULT value defined at the column level is used automatically when a row is inserted without specifying that column.

-- Column defined with DEFAULT
CREATE TABLE orders (
    order_id    NUMBER        PRIMARY KEY,
    order_date  DATE          DEFAULT SYSDATE,
    status      VARCHAR2(10)  DEFAULT 'PENDING'
);

-- DEFAULT is used when column is omitted from INSERT
INSERT INTO orders (order_id)
VALUES (1001);
-- order_date gets SYSDATE, status gets 'PENDING'

-- DEFAULT is NOT used when NULL is explicitly inserted
INSERT INTO orders (order_id, status)
VALUES (1002, NULL);
-- status gets NULL — not 'PENDING'
Explicit NULL bypasses DEFAULT: Writing VALUES (..., NULL) stores NULL. The DEFAULT only applies when the column is completely omitted from the INSERT column list.

7. Explicit DEFAULT keyword in DML

You can use the DEFAULT keyword explicitly in INSERT and UPDATE to force the default value.

-- Using DEFAULT explicitly in INSERT
INSERT INTO orders (order_id, order_date, status)
VALUES (1003, DEFAULT, 'EXPRESS');

-- Using DEFAULT in UPDATE
UPDATE orders
SET    status = DEFAULT
WHERE  order_id = 1003;

8. DEFAULT with NULL — important distinction

There is an important three-way distinction between a column with a DEFAULT, a column with no DEFAULT, and explicitly inserting NULL.

ScenarioColumn has DEFAULT 'PENDING'Column has no DEFAULT
Column omitted from INSERTStores 'PENDING'Stores NULL
INSERT ... VALUES (..., NULL)Stores NULLStores NULL
INSERT ... VALUES (..., DEFAULT)Stores 'PENDING'Stores NULL
UPDATE SET col = DEFAULTSets to 'PENDING'Sets to NULL

9. Multi-row DML and constraint checking

When a DML statement affects multiple rows, Oracle checks constraints after all rows have been processed — not row by row.

-- Swapping manager IDs in a self-referencing table
UPDATE employees
SET    manager_id = CASE
                        WHEN manager_id = 100 THEN 101
                        WHEN manager_id = 101 THEN 100
                    END
WHERE  manager_id IN (100, 101);
All or nothing per statement: If any row in a multi-row DML statement violates a constraint, the entire statement is rolled back.

10. Quick reference

RuleDetail
MERGE INTO ... USING ... ONTarget, source, join condition — all required
WHEN MATCHED — cannot update join columnRaises error if ON column appears in UPDATE SET
WHEN MATCHED DELETE WHEREDeletes rows after UPDATE — condition uses updated values
Both WHEN clauses are optionalMust have at least one
MERGE is DMLParticipates in transactions — can ROLLBACK
Omitting column uses DEFAULTColumn not in INSERT list gets its DEFAULT value
Explicit NULL overrides DEFAULTVALUES (..., NULL) stores NULL — ignores DEFAULT
DEFAULT keyword in DMLForces the column's defined default
Multi-row DML is all or nothingOne constraint violation fails the entire statement

11. Practice questions

Q1. A MERGE statement has a WHEN MATCHED THEN UPDATE SET clause. The ON condition uses employee_id. A developer tries to include e.employee_id = u.employee_id in the UPDATE SET. What happens?

Q2. A table has a DEFAULT of 'ACTIVE' on the STATUS column. A developer runs: INSERT INTO orders (order_id, status) VALUES (100, NULL); What value is stored in STATUS?

Q3. A developer runs an INSERT that selects 500 rows from a staging table. Row number 347 violates a UNIQUE constraint. What is the result?

Oracle SQL Advanced Subqueries: Scalar, WITH Clause and DML Subqueries

Oracle SQL Advanced Subqueries: Scalar, WITH Clause and DML Subqueries

Oracle SQL Advanced Subqueries: Scalar, WITH Clause and DML Subqueries — 1Z0-071 Exam Guide

Advanced subqueries build on the basic subquery patterns from Chapter 8. Chapters 16 and 17 go deeper — scalar subqueries in unexpected places, the WITH clause for reusable query blocks, and subqueries used as the target of INSERT, UPDATE, and DELETE statements.

These are not the most common exam questions, but they do appear — and candidates who haven't studied them lose marks that are relatively easy to pick up.

In this post
Scalar subqueries in SELECT and ORDER BY • Multiple-column subqueries • Pairwise vs non-pairwise comparisons • The WITH clause • Using subqueries as targets for UPDATE, INSERT, and DELETE • Practice questions

1. Scalar subqueries — one value in unexpected places

A scalar subquery returns exactly one row and one column — a single value. What makes it useful is where it can be placed. Beyond the WHERE clause, scalar subqueries can appear in the SELECT list, the ORDER BY clause, the HAVING clause, and even the FROM clause of another query.

-- Standard scalar subquery in WHERE (covered in Post 03)
SELECT last_name, salary
FROM   employees
WHERE  salary > (SELECT AVG(salary) FROM employees);

-- Scalar subquery in HAVING
SELECT   department_id, AVG(salary)
FROM     employees
GROUP BY department_id
HAVING   AVG(salary) > (SELECT AVG(salary) FROM employees);
ORA-01427 still applies: A scalar subquery must return exactly one row. If it returns more than one row, Oracle raises ORA-01427 regardless of where the subquery appears — in SELECT, ORDER BY, or anywhere else. If it returns zero rows, it returns NULL.

2. Scalar subquery in SELECT list

A scalar subquery in the SELECT list returns one value per outer row. Oracle executes the inner query once for each row of the outer query — making it behave like a correlated subquery when it references the outer table.

-- Show each employee's salary vs their department average
SELECT e.last_name,
       e.salary,
       e.department_id,
       (SELECT ROUND(AVG(salary), 0)
        FROM   employees i
        WHERE  i.department_id = e.department_id) AS dept_avg
FROM   employees e;
-- For each employee row, the inner query calculates the
-- average salary for that employee's specific department
-- This is a correlated scalar subquery
Non-correlated scalar subquery in SELECT: If the scalar subquery in the SELECT list does not reference the outer query, Oracle runs it once and reuses the same value for every row — not once per row. This is more efficient. The same average-company-salary value appears on every output row.
-- Non-correlated: company average runs once, same value on every row
SELECT last_name,
       salary,
       (SELECT AVG(salary) FROM employees) AS company_avg
FROM   employees;

3. Scalar subquery in ORDER BY

A scalar subquery can be used in ORDER BY to sort results based on a value that is not in the main query's SELECT list or base table.

-- Sort employees by their department's average salary
-- The department average is not in the SELECT list
SELECT   e.last_name, e.salary, e.department_id
FROM     employees e
ORDER BY (SELECT AVG(salary)
           FROM   employees d
           WHERE  d.department_id = e.department_id) DESC;
-- Employees in the highest-paid department appear first

4. Multiple-column subqueries

A subquery can return multiple columns and multiple rows. When used with a multiple-column comparison in the WHERE clause, Oracle compares all the columns together as a unit.

-- Find employees who have the same job and salary as employee 141 or 143
SELECT last_name, job_id, salary
FROM   employees
WHERE  (job_id, salary) IN
       (SELECT job_id, salary
        FROM   employees
        WHERE  employee_id IN (141, 143));
-- Both columns must match — job_id AND salary together
-- This is a pairwise comparison
Column count must match: The number of columns on the left side of IN must match the number of columns returned by the subquery. (job_id, salary) IN (SELECT job_id FROM ...) raises an error — one column on the left, one in the subquery is fine, but mismatches fail.

5. Pairwise vs non-pairwise comparison

The exam distinguishes between pairwise and non-pairwise multiple-column subquery comparisons. The two approaches can produce different results.

-- PAIRWISE: columns must match as a combined pair
SELECT last_name, department_id, salary
FROM   employees
WHERE  (department_id, salary) IN
       (SELECT department_id, MIN(salary)
        FROM   employees
        GROUP BY department_id);
-- Returns employees who earn the minimum salary IN THEIR OWN department
-- dept_id AND salary must match the same row from the subquery

-- NON-PAIRWISE: each column compared independently
SELECT last_name, department_id, salary
FROM   employees
WHERE  department_id IN
           (SELECT department_id FROM employees GROUP BY department_id)
  AND  salary IN
           (SELECT MIN(salary) FROM employees GROUP BY department_id);
-- Returns employees whose salary equals ANY department's minimum
-- NOT necessarily the minimum of their own department
-- Can return more rows than the pairwise version
Pairwise vs non-pairwise gives different results: Pairwise requires both columns to match in the same subquery row. Non-pairwise checks each column against its own subquery independently — a row passes if department_id matches any subquery row AND salary matches any subquery row, even different rows. The exam tests whether you know which approach correctly answers the stated question.

6. The WITH clause — named query blocks

The WITH clause (also called a Common Table Expression or CTE) lets you define a named subquery at the top of a statement and reference it by name later. It is particularly useful when the same subquery would otherwise need to be written multiple times.

-- WITH clause defines a named query block
WITH dept_costs AS (
    SELECT   department_id,
             SUM(salary) AS dept_total
    FROM     employees
    GROUP BY department_id
),
avg_cost AS (
    SELECT AVG(dept_total) AS avg_total
    FROM   dept_costs
)
SELECT d.department_id, d.dept_total
FROM   dept_costs d, avg_cost a
WHERE  d.dept_total > a.avg_total
ORDER BY d.dept_total DESC;
-- dept_costs is defined once but could be referenced multiple times
-- avg_cost references dept_costs inside the WITH block itself
FeatureWITH clauseInline view (subquery in FROM)
Defined where?Once at the top of the statementInline inside the FROM clause
Can be referenced multiple times?Yes — by name anywhere in the main queryNo — each inline view is used once
ReadabilityHigher for complex queriesCan get deeply nested
Stored permanently?No — exists only for that statementNo
WITH clause syntax: Multiple named query blocks are separated by commas inside one WITH keyword. Each block can reference previously defined blocks within the same WITH clause. The main SELECT statement follows immediately after the last closing parenthesis.

7. Subqueries as DML targets — UPDATE with subquery

Chapter 17 covers using subqueries not just as filters inside DML but as the actual target of DML — the table that UPDATE or INSERT operates on. This is a more advanced pattern than the subquery-in-WHERE cases from Chapter 8.

-- UPDATE using a subquery in the FROM clause as target (inline view update)
-- This updates the underlying base table through a subquery
UPDATE (SELECT e.salary, e.department_id
        FROM   employees e
        JOIN   departments d
          ON   e.department_id = d.department_id
        WHERE  d.department_name = 'Sales')
SET    salary = salary * 1.1;
-- The subquery produces the key-preserved row set
-- Oracle updates the base EMPLOYEES table directly
Key-preserved table required: For an UPDATE or DELETE through a subquery target, the subquery must produce a key-preserved result — the primary key of the table being modified must be unique in the subquery's result set. If it is not key-preserved, Oracle raises ORA-01779.

8. INSERT into a subquery target

INSERT can use a subquery as the target table — inserting into a view or an inline view that points back to the base table. The rules are the same as INSERT through a view from Chapter 14.

-- INSERT using a subquery in VALUES (standard multi-row insert)
INSERT INTO emp_backup
SELECT employee_id, last_name, salary, hire_date
FROM   employees
WHERE  department_id = 50;

-- Multi-table INSERT — insert one source row into multiple tables
INSERT ALL
    INTO emp_history   (employee_id, last_name, salary)
         VALUES (employee_id, last_name, salary)
    INTO sal_history   (employee_id, salary, change_date)
         VALUES (employee_id, salary, SYSDATE)
SELECT employee_id, last_name, salary
FROM   employees
WHERE  department_id = 50;
-- Each row from the SELECT is inserted into BOTH target tables
INSERT ALL vs INSERT FIRST: INSERT ALL inserts each source row into every INTO clause regardless of conditions. INSERT FIRST inserts each source row into the first INTO clause whose WHEN condition is satisfied, then stops. The exam tests the difference between these two forms.
-- INSERT FIRST: conditional multi-table insert
INSERT FIRST
    WHEN salary < 5000  THEN
        INTO low_sal_emp VALUES (employee_id, last_name, salary)
    WHEN salary < 10000 THEN
        INTO mid_sal_emp VALUES (employee_id, last_name, salary)
    ELSE
        INTO high_sal_emp VALUES (employee_id, last_name, salary)
SELECT employee_id, last_name, salary FROM employees;
-- Each employee goes into exactly one table — the first matching WHEN

9. DELETE using a subquery

DELETE can use a subquery in its WHERE clause — this was covered in Post 07. Chapter 17 adds the pattern of deleting through a subquery target, which follows the same key-preservation rules as UPDATE.

-- Standard DELETE with subquery in WHERE (from Chapter 10)
DELETE FROM employees
WHERE  department_id = (SELECT department_id
                        FROM   departments
                        WHERE  department_name = 'Shipping');

-- DELETE through a subquery target (Chapter 17 pattern)
DELETE FROM (SELECT e.*
              FROM   employees e
              JOIN   departments d
                ON   e.department_id = d.department_id
              WHERE  d.department_name = 'Shipping');
-- Deletes the rows that satisfy the inline view's filter
-- Equivalent to the standard form above but written as target subquery

10. Quick reference

PatternKey rule
Scalar subquery in SELECT listMust return exactly one row — ORA-01427 if multiple rows; returns NULL if zero rows
Scalar subquery in ORDER BYValid — sorts by the single value returned per outer row
Multiple-column subqueryColumn count on left must match column count in subquery
Pairwise comparisonBoth columns must match in the same subquery row
Non-pairwise comparisonEach column checked independently — can return more rows than pairwise
WITH clauseDefines named query blocks — reusable within the same statement only
UPDATE through subqueryRequires key-preserved result set — ORA-01779 if not key-preserved
INSERT ALLEach source row inserted into ALL matching INTO clauses
INSERT FIRSTEach source row inserted into only the FIRST matching WHEN clause

11. Practice questions

Q1. A scalar subquery in the SELECT list returns zero rows for one particular outer row. What value appears in the result for that column?

Q2. A developer uses INSERT ALL with three INTO clauses and a SELECT that returns 10 rows. None of the INTO clauses have WHEN conditions. How many total rows are inserted across all three tables?

Q3. Which of these correctly uses the WITH clause?

Conclusion

Scalar subqueries, the WITH clause, and subqueries as DML targets are powerful patterns that appear on the 1Z0-071 exam and in real-world Oracle SQL development. Mastering where scalar subqueries can be placed, when to use WITH for readability, and the rules around key-preserved tables for DML operations will help you both pass the exam and write clearer, more maintainable queries.

Oracle SQL SELECT Fundamentals: Columns, Aliases, DISTINCT and Expressions

Oracle SQL SELECT Statement Fundamentals: Complete Guide

Oracle SQL SELECT Statement Fundamentals: Complete Guide

The SELECT statement is the foundation of every SQL query in Oracle. Whether you are retrieving data, performing calculations, or transforming results, understanding SELECT mechanics is essential for writing clear, efficient, and maintainable queries.

Learning Objectives
By the end of this guide you will master SELECT syntax, understand column aliases, DISTINCT behavior, arithmetic expressions, string concatenation, operator precedence, and best practices that professionals use every day.

1. SELECT Statement Structure and Mandatory Clauses

Only two clauses are mandatory. The remaining clauses are optional and must appear in a fixed order.

ClauseRequired?Purpose
SELECTYesColumns or expressions to retrieve
FROMYesTable(s) to retrieve from
WHERENoFilter rows before grouping
GROUP BYNoCollapse rows into groups
HAVINGNoFilter groups after grouping
ORDER BYNoSort the final result
-- Minimum valid SELECT statement
SELECT last_name, salary
FROM   employees;

-- Full clause order (must appear exactly in this sequence)
SELECT   department_id, AVG(salary)
FROM     employees
WHERE    salary > 5000
GROUP BY department_id
HAVING   AVG(salary) > 8000
ORDER BY department_id;
Important: Clause order is fixed. You cannot rearrange them (for example, putting ORDER BY before WHERE). This is one of the most common syntax mistakes.

2. Selecting All Columns vs Specific Columns

-- All columns
SELECT * FROM employees;

-- Specific columns in any order you prefer
SELECT last_name, employee_id, salary
FROM   employees;

-- Same column can appear multiple times
SELECT last_name, salary, salary * 12 AS annual_salary
FROM   employees;

3. Column Aliases — AS keyword is optional

-- With AS (recommended for clarity)
SELECT last_name        AS name,
       salary * 12      AS annual_salary
FROM   employees;

-- Without AS — space is enough
SELECT last_name        name,
       salary * 12      annual_salary
FROM   employees;
Key Rule: Column aliases defined in the SELECT clause cannot be used in WHERE, GROUP BY, or HAVING. They can only be referenced in ORDER BY.

4. Aliases with Spaces or Special Characters

-- Alias with space or special characters — use double quotes
SELECT salary * 12 AS "Annual Salary" FROM employees;

-- Preserving exact case or using special symbols
SELECT salary AS "Salary ($)" FROM employees;
Double quotes vs Single quotes
• Double quotes (" ") → for column aliases and identifiers
• Single quotes (' ') → for string literals only

5. Arithmetic Expressions and NULL Behavior

SELECT last_name,
       salary,
       salary * 12                          AS annual_sal,
       salary * 12 + NVL(commission_pct, 0) * salary * 12 AS total_annual
FROM   employees;
Important NULL Rule: Any arithmetic operation involving NULL returns NULL. Use NVL or COALESCE to provide default values when needed.

6. String Concatenation with ||

SELECT first_name || ' ' || last_name AS full_name
FROM   employees;

-- Oracle treats NULL as an empty string in concatenation
SELECT 'Hello' || NULL || ' World' FROM dual;  -- Returns: Hello World

7. DISTINCT — Removing Duplicate Rows

SELECT DISTINCT department_id FROM employees;

-- UNIQUE is a synonym for DISTINCT in Oracle
SELECT UNIQUE department_id FROM employees;

8. DISTINCT with Multiple Columns

SELECT DISTINCT department_id, job_id
FROM   employees;
Important Behavior: DISTINCT applies to the entire combination of selected columns, not to each column individually.

9. Operator Precedence

SELECT 2 + 3 * 4 FROM dual;     -- Returns 14  (multiplication first)
SELECT (2 + 3) * 4 FROM dual;   -- Returns 20  (parentheses override)

10. General SQL Statement Rules

  • SQL keywords and identifiers are case-insensitive
  • String literals inside single quotes are case-sensitive
  • Extra whitespace, tabs, and newlines are ignored
  • Use a semicolon to terminate statements in tools like SQL*Plus

11. Interactive Practice Quiz

Q1. What is wrong with this query?

Q2. How many rows does this return?
SELECT DISTINCT department_id, job_id FROM employees;

Q3. Which alias definition is invalid?

Conclusion

You now have a solid understanding of Oracle SQL SELECT statement fundamentals. These concepts form the foundation for writing powerful, readable, and efficient queries in any Oracle environment.

Practice these patterns regularly, pay attention to clause order, alias usage, and DISTINCT behavior, and you will write cleaner SQL with confidence.

Oracle SQL Data Dictionary Views: USER_, ALL_ and DBA_

Oracle SQL Data Dictionary Views: Complete Guide

Oracle SQL Data Dictionary Views: Complete Guide

The data dictionary is Oracle’s internal repository of metadata — information about every object in the database. It contains details about tables, columns, constraints, indexes, views, sequences, and much more. Querying the data dictionary is one of the most practical skills for any Oracle developer or DBA.

Learning Objectives
By the end of this guide you will understand the three main view families (USER_, ALL_, DBA_), know the most important dictionary views, master object naming rules, learn how to use the DUAL table, and explore dynamic performance views.

1. What the Data Dictionary Is

The data dictionary consists of read-only tables and views maintained automatically by Oracle. It stores metadata about all database objects. You query it using regular SELECT statements, but you cannot modify it directly — Oracle updates it whenever you run DDL statements.

-- Example: Query your own tables
SELECT table_name, num_rows
FROM   user_tables
ORDER BY table_name;
Read-only by design: The data dictionary is maintained exclusively by Oracle. Any DDL you run (CREATE, ALTER, DROP) automatically updates the dictionary.

2. The Three View Families — USER_, ALL_, DBA_

Oracle provides three families of data dictionary views. The prefix determines the scope of data you can see.

PrefixShowsOWNER column?Typical use
USER_Objects owned by the current userNoMost common for everyday work
ALL_Objects the current user can access (own + granted)YesWhen working with objects in other schemas
DBA_All objects in the entire databaseYesDBAs and users with high privileges
-- Your own objects only
SELECT table_name FROM user_tables;

-- Your objects plus granted objects in other schemas
SELECT owner, table_name 
FROM   all_tables
WHERE  owner != USER();

-- Everything in the database (requires privileges)
SELECT owner, table_name 
FROM   dba_tables
WHERE  owner = 'HR';
Important difference: USER_ views do not have an OWNER column (everything belongs to you). ALL_ and DBA_ views include the OWNER column.

3. Key Views for Tables and Columns

ViewWhat it showsKey columns
USER_TABLESTables owned by the current userTABLE_NAME, NUM_ROWS, LAST_ANALYZED
USER_TAB_COLUMNSColumns in the current user’s tablesTABLE_NAME, COLUMN_NAME, DATA_TYPE, DATA_LENGTH, NULLABLE
USER_OBJECTSAll schema objectsOBJECT_NAME, OBJECT_TYPE, STATUS, CREATED
-- List columns of a specific table
SELECT column_name, data_type, nullable
FROM   user_tab_columns
WHERE  table_name = 'EMPLOYEES'
ORDER BY column_id;

4. Key Views for Constraints

ViewWhat it showsKey columns
USER_CONSTRAINTSConstraints on your tablesCONSTRAINT_NAME, CONSTRAINT_TYPE, TABLE_NAME, STATUS
USER_CONS_COLUMNSColumns belonging to each constraintCONSTRAINT_NAME, COLUMN_NAME, POSITION
Constraint type codes:
P = Primary Key U = Unique R = Foreign Key C = Check (includes NOT NULL)

5. Key Views for Indexes, Views, and Sequences

ViewWhat it showsKey columns
USER_INDEXESIndexes on your tablesINDEX_NAME, INDEX_TYPE, UNIQUENESS
USER_VIEWSViews you ownVIEW_NAME, TEXT
USER_SEQUENCESSequences you ownSEQUENCE_NAME, INCREMENT_BY, LAST_NUMBER

6. Object Names Are Stored in UPPERCASE

Oracle stores all unquoted object names in the data dictionary in UPPERCASE.

-- Correct way to query
SELECT column_name 
FROM   user_tab_columns 
WHERE  table_name = 'EMPLOYEES';

-- This returns zero rows
WHERE  table_name = 'employees';
Rule to remember: Always use UPPERCASE when filtering data dictionary views by object names (unless the object was created with double quotes to preserve case).

7. DUAL — The One-Row Utility Table

DUAL is a special one-row, one-column table owned by SYS. It is used when you want to evaluate expressions or call functions without referencing a real table.

SELECT SYSDATE FROM dual;
SELECT USER FROM dual;
SELECT 2 * 3 FROM dual;
SELECT UPPER('hello') FROM dual;

8. Dynamic Performance Views (V$ Views)

In addition to the static data dictionary, Oracle provides dynamic performance views (prefixed with V$). These show real-time information about the running database instance.

ViewWhat it shows
V$SESSIONCurrently connected sessions
V$DATABASEDatabase-level information
V$SQLSQL statements in the shared pool

9. Interactive Practice Quiz

Q1. Why does this query return zero rows?
SELECT column_name FROM user_tab_columns WHERE table_name = 'employees';

Q2. In USER_CONSTRAINTS, you see a constraint with CONSTRAINT_TYPE = 'C' and SEARCH_CONDITION = '"LAST_NAME" IS NOT NULL'. What is this?

Q3. Which view shows tables in other schemas that you have been granted access to?

Conclusion

The Oracle data dictionary is an incredibly powerful tool for exploring and understanding your database. Mastering the USER_, ALL_, and DBA_ view families, along with the key views for tables, columns, constraints, and indexes, will make you far more effective when working with Oracle SQL.

Practice querying these views regularly — they are essential for troubleshooting, documentation, and day-to-day database work.

Non-Equijoins and Self-Joins in Oracle SQL

Non-Equijoins and Self-Joins in Oracle SQL Non-Equijoins and Self-Joins in Oracle SQL: Complete Guide Most joins in SQL use the e...