SQL — Structured Query Language

Exam Relevance
FA Round 1: 5 MCQs on SQL
PRA: SQL queries and database concepts
Sprints: Sprint 2 (database integration)
SQL appears in almost every exam. Easy marks once you know the patterns.

SQL Basics & Terminology

Imagine you have thousands of customer records. You could store them in a giant Excel file — but what happens when 50 people need to read and update that file at the same time? Chaos. Data gets overwritten, duplicated, corrupted.

That is exactly why databases exist. A database is like a super-powered Excel that can handle millions of rows, lets hundreds of people access it simultaneously, and ensures data never gets corrupted. SQL (Structured Query Language) is the language you use to talk to this database — to ask questions, insert data, update records, or delete rows.

Think of it this way
A database is a warehouse full of organized filing cabinets. SQL is the language you use to tell the warehouse manager: "Get me all customer files from Mumbai" or "Add this new employee file." You never touch the cabinets yourself — you give SQL instructions and the database engine does the work.
TermMeaningReal-World Analogy
DatabaseOrganized collection of structured dataThe entire warehouse of filing cabinets
TableCollection of rows and columns (like a spreadsheet)One spreadsheet/filing cabinet for "employees"
Row (Record/Tuple)A single entry in a tableOne employee's complete file
Column (Field/Attribute)A property of the dataOne piece of info — name, salary, department
SchemaStructure/blueprint of the databaseThe blueprint that says "employees table has columns: id, name, salary"
Primary KeyUniquely identifies each rowLike an Aadhaar number — no two people share one
Foreign KeyLinks one table to anotherYour department ID on your employee file — it points to the departments table
RDBMSRelational Database Management System (Oracle, MySQL, PostgreSQL)The warehouse manager software that runs everything

SQL Command Categories

SQL commands are grouped by what they do. This is one of the most commonly tested concepts — expect at least one MCQ on this.

CategoryCommandsPurposeMemory Trick
DDL (Data Definition)CREATE, ALTER, DROP, TRUNCATEDefine/modify table structure"Building the filing cabinet itself"
DML (Data Manipulation)INSERT, UPDATE, DELETE, SELECTManipulate data in tables"Working with the files inside the cabinet"
DCL (Data Control)GRANT, REVOKEControl access/permissions"Giving/taking away keys to the cabinet"
TCL (Transaction Control)COMMIT, ROLLBACK, SAVEPOINTManage transactions"Save game / load last checkpoint"
FA Favorite
"Which category does X command belong to?" — This is a guaranteed MCQ. Memorize the table above. Remember: TRUNCATE is DDL (not DML!), and SELECT is DML.
Question

Which SQL command category does TRUNCATE belong to?

  1. DML
  2. DDL
  3. DCL
  4. TCL
TRUNCATE is DDL (Data Definition Language), not DML. This is a common exam trap because TRUNCATE removes data like DELETE, but it operates on the table structure level. Key difference: DDL commands auto-commit and cannot be rolled back.

Data Types

Before you store data, the database needs to know what kind of data each column will hold. You would not store someone's name in a number field, right? Data types are like labels on filing cabinet drawers — "this drawer only holds numbers," "this one holds text up to 50 characters."

Data TypeDescriptionExample
NUMBER(p,s)Numeric — p = precision (total digits), s = scale (decimal digits)NUMBER(8,2) → 123456.78
VARCHAR2(n)Variable-length string (Oracle)VARCHAR2(50)
VARCHAR(n)Variable-length string (MySQL)VARCHAR(100)
CHAR(n)Fixed-length string, padded with spacesCHAR(10)
DATEDate value'2026-03-22'
INT / INTEGERWhole number42
FLOATFloating-point number3.14
CLOBLarge text (Character Large Object)Long articles
BLOBBinary data (Binary Large Object)Images, files
VARCHAR vs CHAR — When to use which?
Imagine you have a column for Indian state codes (always 2 characters: "MH", "KA", "TN"). Use CHAR(2) — it is always exactly 2 characters, so fixed-length is perfect and slightly faster.

Now imagine a column for employee names — "Raj" is 3 characters, "Darshanakrishnamurthy" is 21 characters. Use VARCHAR(50) — it only stores what you give it. CHAR(50) would waste space by padding "Raj" with 47 spaces.
Question

If you define a column as CHAR(10) and store the value 'Hi', how many bytes does it occupy?

  1. 2 bytes
  2. 10 bytes
  3. 8 bytes
  4. Depends on the database
CHAR(10) always stores exactly 10 bytes. The value 'Hi' gets padded with 8 spaces to fill the remaining space. This is why VARCHAR is preferred for variable-length data — it only uses the bytes it needs.

DDL — CREATE, ALTER, DROP

DDL is about building and modifying the structure — the table itself, not the data inside it. Think of it as construction work: you are building the filing cabinet (CREATE), adding a new drawer to it (ALTER), or demolishing the entire cabinet (DROP).

CREATE TABLE

CREATE TABLE employees (
    emp_id    NUMBER(6)     PRIMARY KEY,
    emp_name  VARCHAR2(50) NOT NULL,
    salary    NUMBER(10,2) DEFAULT 0,
    dept_id   NUMBER(4),
    hire_date DATE,
    FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
);

ALTER TABLE

Your table is already live with data in it, but you realize you forgot to add an email column. You cannot DROP and recreate — you'd lose all data. ALTER lets you modify a live table.

-- Add a column
ALTER TABLE employees ADD email VARCHAR2(100);

-- Modify a column
ALTER TABLE employees MODIFY emp_name VARCHAR2(100);

-- Drop a column
ALTER TABLE employees DROP COLUMN email;

-- Rename a column (Oracle)
ALTER TABLE employees RENAME COLUMN emp_name TO full_name;

-- Add a constraint
ALTER TABLE employees ADD CONSTRAINT chk_sal CHECK (salary > 0);

DROP & TRUNCATE

-- Drop table entirely (structure + data gone)
DROP TABLE employees;

-- Remove all rows but keep structure (cannot rollback)
TRUNCATE TABLE employees;
DROP vs TRUNCATE vs DELETE — Know the difference cold
DROP = demolish the entire filing cabinet. Structure + data gone. Cannot be undone.
TRUNCATE = empty every file from the cabinet, but the cabinet itself stays. Cannot be rolled back because it is DDL.
DELETE = remove specific files (or all files) from the cabinet. Can be rolled back because it is DML. Can use WHERE to pick which rows to remove.

Speed: TRUNCATE is much faster than DELETE for large tables because it does not log individual row deletions.
Question

You accidentally ran TRUNCATE TABLE employees; on production. Can you ROLLBACK to undo it?

  1. Yes, ROLLBACK undoes any data changes
  2. No, TRUNCATE is DDL and auto-commits — it cannot be rolled back
  3. Yes, but only if you use SAVEPOINT first
  4. No, but DELETE FROM employees can also not be rolled back
TRUNCATE is a DDL command. In Oracle, all DDL commands issue an automatic COMMIT. Once committed, there is no going back with ROLLBACK. This is why TRUNCATE is dangerous on production. DELETE (DML) can be rolled back because it does not auto-commit.

DML — INSERT, UPDATE, DELETE

If DDL builds the cabinet, DML is what you do with the files inside it every day — adding new files (INSERT), updating information on existing files (UPDATE), and removing files you no longer need (DELETE).

INSERT

-- Insert single row
INSERT INTO employees (emp_id, emp_name, salary, dept_id)
VALUES (101, 'Darshan', 50000, 10);

-- Insert multiple rows (MySQL)
INSERT INTO employees (emp_id, emp_name, salary)
VALUES (102, 'Ankit', 45000),
       (103, 'Priya', 55000);

-- Insert from another table
INSERT INTO emp_backup
SELECT * FROM employees WHERE dept_id = 10;

UPDATE

-- Update specific rows
UPDATE employees
SET salary = salary * 1.10
WHERE dept_id = 10;

-- Update multiple columns
UPDATE employees
SET salary = 60000, dept_id = 20
WHERE emp_id = 101;
Dangerous: UPDATE without WHERE
UPDATE employees SET salary = 0; — This updates EVERY row in the table. Always double-check your WHERE clause before running UPDATE or DELETE.

DELETE

-- Delete specific rows
DELETE FROM employees WHERE emp_id = 103;

-- Delete all rows (can be rolled back)
DELETE FROM employees;
Question

What happens if you run UPDATE employees SET salary = salary * 2; without a WHERE clause?

  1. Error — WHERE is required for UPDATE
  2. Only the first row gets updated
  3. Every employee's salary gets doubled
  4. Nothing happens without COMMIT
Without a WHERE clause, UPDATE affects ALL rows in the table. Every employee's salary gets doubled. This is why WHERE is critical — always specify which rows you want to change. The good news: since UPDATE is DML, you can ROLLBACK if you catch the mistake before COMMIT.

SELECT & Filtering

SELECT is the most important SQL command — it is how you ask questions to your database. Think of it like Google Search for your data. Want to know which employees earn more than 50,000? SELECT. Want a list of all departments? SELECT. You will use this in literally every exam and every real project.

The mental model
Reading a SELECT statement in English: SELECT emp_name, salary FROM employees WHERE dept_id = 10 reads as: "Get me the name and salary FROM the employees table WHERE the department is 10." SQL reads almost like English — that was the whole point when it was designed.

Basic SELECT

-- Select all columns (the * means "everything")
SELECT * FROM employees;

-- Select specific columns (always better — don't fetch what you don't need)
SELECT emp_name, salary FROM employees;

-- Alias — give a column a friendly display name
SELECT emp_name AS "Employee Name", salary * 12 AS annual_salary
FROM employees;

-- DISTINCT — remove duplicates
SELECT DISTINCT dept_id FROM employees;

WHERE Clause — Filtering Rows

Without WHERE, SELECT returns every row. WHERE is your filter — like telling Excel "show me only rows where salary > 50000." The database scans through all rows and only returns the ones that match your condition.

SELECT * FROM employees WHERE salary > 50000;
SELECT * FROM employees WHERE dept_id = 10 AND salary >= 40000;
SELECT * FROM employees WHERE dept_id = 10 OR dept_id = 20;
SELECT * FROM employees WHERE NOT dept_id = 30;

ORDER BY

By default, SQL does not guarantee any order of results. If you want sorted results — highest salary first, alphabetical names, etc. — you must explicitly ask with ORDER BY.

-- Ascending (default) — lowest to highest
SELECT * FROM employees ORDER BY salary ASC;

-- Descending — highest to lowest
SELECT * FROM employees ORDER BY salary DESC;

-- Multiple columns: first sort by dept, then within each dept sort by salary descending
SELECT * FROM employees ORDER BY dept_id ASC, salary DESC;

LIMIT / ROWNUM / FETCH

-- MySQL: LIMIT
SELECT * FROM employees ORDER BY salary DESC LIMIT 5;

-- Oracle: ROWNUM (old style)
SELECT * FROM employees WHERE ROWNUM <= 5;

-- Oracle 12c+: FETCH
SELECT * FROM employees ORDER BY salary DESC
FETCH FIRST 5 ROWS ONLY;
Question

What does SELECT DISTINCT dept_id FROM employees; return?

  1. All dept_id values including duplicates
  2. Only unique dept_id values (no repeats)
  3. The first dept_id value only
  4. Error — DISTINCT cannot be used with SELECT
DISTINCT removes duplicate values from the result. If employees table has dept_ids: 10, 10, 20, 20, 30, the result will be just: 10, 20, 30. Useful when you want to know "which departments exist" without seeing repeats.
Question

Which query correctly finds employees whose name starts with 'D' and salary is above 40000?

  1. SELECT * FROM employees WHERE name LIKE 'D%' OR salary > 40000;
  2. SELECT * FROM employees WHERE name LIKE 'D%' AND salary > 40000;
  3. SELECT * FROM employees WHERE name = 'D%' AND salary > 40000;
  4. SELECT * FROM employees WHERE name LIKE '%D' AND salary > 40000;
B is correct. AND means BOTH conditions must be true. OR would return employees whose name starts with D OR salary > 40000 (too many results). Option C uses = instead of LIKE — the = operator does not support wildcards. Option D uses '%D' which means "ends with D", not "starts with D".

Operators & Conditions

Operators are the building blocks of your WHERE clause. They let you express conditions like "between these dates," "in this list," or "matching this pattern." Master these and you can filter anything.

OperatorUsageExample
=Equal toWHERE dept_id = 10
!= or <>Not equalWHERE dept_id != 10
>, <, >=, <=ComparisonWHERE salary > 50000
BETWEENRange (inclusive on BOTH ends)WHERE salary BETWEEN 30000 AND 60000
INMatch any in listWHERE dept_id IN (10, 20, 30)
NOT INNot in listWHERE dept_id NOT IN (40, 50)
LIKEPattern matchingWHERE name LIKE 'D%'
IS NULLCheck for NULLWHERE email IS NULL
IS NOT NULLCheck not NULLWHERE email IS NOT NULL
BETWEEN is inclusive
WHERE salary BETWEEN 30000 AND 60000 is the same as WHERE salary >= 30000 AND salary <= 60000. Both endpoints are included. This is a common exam trap — they will ask if BETWEEN includes the boundary values. Answer: YES.

LIKE Wildcards

LIKE is SQL's version of "search with wildcards." Two special characters: % means "any number of characters" (including zero), and _ means "exactly one character."

PatternMeaningMatches
'D%'Starts with DDarshan, Deepak, Dhruv
'%an'Ends with "an"Darshan, Rohan
'%ar%'Contains "ar"Darshan, Karan
'_a%'Second letter is "a"Darshan, Karan
'___'Exactly 3 charactersRaj, Ram
Exam Trap — NULL comparisons
NULL is not a value — it means "unknown." You cannot compare it with = or !=. Think of it this way: is an unknown value equal to 10? We don't know! So the comparison returns neither true nor false — it returns UNKNOWN, and the row is excluded.

WHERE salary = NULL → always returns nothing (WRONG).
WHERE salary IS NULL → correct way to check for NULL.
Question

SELECT * FROM employees WHERE salary BETWEEN 30000 AND 50000; — Does this include employees with salary exactly 30000 and exactly 50000?

  1. No, BETWEEN excludes both boundaries
  2. Yes, BETWEEN is inclusive on both ends
  3. It includes 30000 but excludes 50000
  4. It excludes 30000 but includes 50000
BETWEEN is inclusive on BOTH ends. BETWEEN 30000 AND 50000 is equivalent to >= 30000 AND <= 50000. Employees earning exactly 30000 or exactly 50000 will be included.

SQL Functions

Functions in SQL are pre-built tools that transform data. Instead of doing calculations in your application code, SQL lets you do it right inside the query. There are two types:

Single-Row Functions (work on each row)

String Functions:

FunctionResult
UPPER('hello')'HELLO'
LOWER('HELLO')'hello'
INITCAP('hello world')'Hello World'
LENGTH('Darshan')7
SUBSTR('Darshan', 1, 3)'Dar'
CONCAT('Hello', ' World')'Hello World'
REPLACE('Hello', 'l', 'r')'Herro'
TRIM(' hi ')'hi'
LPAD('42', 5, '0')'00042'
RPAD('Hi', 5, '*')'Hi***'
INSTR('Darshan', 'sh')4

Number Functions:

FunctionResult
ROUND(15.678, 2)15.68
ROUND(15.678, 0)16
TRUNC(15.678, 2)15.67
CEIL(15.1)16
FLOOR(15.9)15
MOD(10, 3)1
ABS(-42)42
POWER(2, 3)8
SQRT(144)12
ROUND vs TRUNC — they look similar but behave differently
ROUND(15.678, 2) = 15.68 (rounds UP the last digit)
TRUNC(15.678, 2) = 15.67 (just CHOPS off — no rounding)
Think of TRUNC as cutting with scissors — it does not care what comes after.

Date Functions (Oracle):

SELECT SYSDATE FROM dual;                     -- Current date
SELECT MONTHS_BETWEEN('01-MAR-26', '01-JAN-26') FROM dual;  -- 2
SELECT ADD_MONTHS(SYSDATE, 3) FROM dual;       -- 3 months later
SELECT NEXT_DAY(SYSDATE, 'FRIDAY') FROM dual;  -- Next Friday
SELECT LAST_DAY(SYSDATE) FROM dual;            -- Last day of month
SELECT EXTRACT(YEAR FROM SYSDATE) FROM dual;  -- 2026

Conversion Functions:

TO_CHAR(SYSDATE, 'DD-MON-YYYY')   -- '22-MAR-2026'
TO_CHAR(salary, '$99,999.00')     -- '$50,000.00'
TO_DATE('22-03-2026', 'DD-MM-YYYY') -- date value
TO_NUMBER('12345')                 -- 12345

NULL-handling Functions:

NULL is the trickiest part of SQL. Any operation with NULL returns NULL: 5 + NULL = NULL, 'hello' || NULL = NULL. These functions help you handle NULLs gracefully.

NVL(commission, 0)          -- If NULL, return 0
NVL2(comm, 'Has', 'None')  -- If NOT NULL → 'Has', else 'None'
NULLIF(10, 10)              -- Returns NULL (both equal)
COALESCE(a, b, c, 0)       -- First non-NULL value
COALESCE vs NVL
NVL(a, b) takes exactly 2 args. COALESCE(a, b, c, ...) takes any number — returns first non-NULL. COALESCE is ANSI standard (works everywhere), NVL is Oracle-only.

Aggregate Functions (work on groups of rows)

Aggregate functions crunch multiple rows into a single result. Think of them like Excel's SUM, AVERAGE, COUNT functions at the bottom of a column.

FunctionDescriptionExample
COUNT(*)Count all rowsSELECT COUNT(*) FROM employees
COUNT(col)Count non-NULL valuesSELECT COUNT(email) FROM employees
SUM(col)TotalSELECT SUM(salary) FROM employees
AVG(col)AverageSELECT AVG(salary) FROM employees
MIN(col)Minimum valueSELECT MIN(salary) FROM employees
MAX(col)Maximum valueSELECT MAX(salary) FROM employees
Exam Trap — COUNT(*) vs COUNT(col)
COUNT(*) counts ALL rows including those with NULLs.
COUNT(column_name) counts only NON-NULL values in that column.

If you have 10 employees but 3 have NULL email, COUNT(*) = 10 but COUNT(email) = 7.
Question

Table has 10 rows. Column "commission" has NULL in 4 rows. What does SELECT COUNT(commission) FROM employees; return?

  1. 10
  2. 4
  3. 6
  4. NULL
COUNT(column_name) counts only NON-NULL values. Out of 10 rows, 4 have NULL commission, so 6 rows have non-NULL values. COUNT(commission) = 6. If you wanted all 10, use COUNT(*).

GROUP BY & HAVING

Why does GROUP BY exist? Imagine your manager asks: "What is the average salary in each department?" You cannot just run AVG(salary) — that gives you ONE number for the entire company. You need to first group employees by department, and THEN calculate the average within each group.

The Excel analogy
GROUP BY is like creating a Pivot Table in Excel. You drag "Department" into the Row area and "Salary" into the Values area with "Average." Excel groups all rows by department and calculates the average for each group. That is exactly what GROUP BY does in SQL.
-- Count employees per department
SELECT dept_id, COUNT(*) AS emp_count
FROM employees
GROUP BY dept_id;

-- Average salary per department
SELECT dept_id, AVG(salary) AS avg_sal
FROM employees
GROUP BY dept_id
ORDER BY avg_sal DESC;
The Golden Rule of GROUP BY
Every column in your SELECT must either be (a) in the GROUP BY clause, or (b) inside an aggregate function. You cannot SELECT emp_name if you are grouping by dept_id — which employee name would SQL show for a group of 50 people?

Wrong: SELECT dept_id, emp_name, AVG(salary) FROM employees GROUP BY dept_id;
Right: SELECT dept_id, AVG(salary) FROM employees GROUP BY dept_id;

HAVING (filter groups)

Why can't we just use WHERE? Because WHERE runs before grouping happens. If you want to say "show me only departments that have more than 5 employees," you need a filter that runs after the groups are formed. That is what HAVING does.

-- Departments with more than 5 employees
SELECT dept_id, COUNT(*) AS emp_count
FROM employees
GROUP BY dept_id
HAVING COUNT(*) > 5;

-- Departments where average salary exceeds 50000
SELECT dept_id, AVG(salary) AS avg_sal
FROM employees
WHERE salary > 10000
GROUP BY dept_id
HAVING AVG(salary) > 50000;
WHERE vs HAVING — The exam WILL test this
WHERE filters individual rows BEFORE grouping. Like removing bad apples before putting them into baskets.
HAVING filters groups AFTER grouping. Like removing baskets that have fewer than 5 apples.
You cannot use aggregate functions in WHERE. WHERE COUNT(*) > 5 is an error. Use HAVING instead.

SQL Execution Order

SQL does NOT execute in the order you write it. Understanding this order is the key to understanding why WHERE cannot use aliases and HAVING can use aggregates.

OrderClausePurposeAnalogy
1FROMChoose tableOpen the filing cabinet
2WHEREFilter rowsRemove files that don't match
3GROUP BYGroup rowsSort remaining files into piles by department
4HAVINGFilter groupsRemove piles that are too small
5SELECTChoose columnsPick which info to read from each pile
6ORDER BYSort resultsArrange the final output
Question

Which query correctly finds departments where the average salary exceeds 60000?

  1. SELECT dept_id, AVG(salary) FROM employees WHERE AVG(salary) > 60000 GROUP BY dept_id;
  2. SELECT dept_id, AVG(salary) FROM employees GROUP BY dept_id HAVING AVG(salary) > 60000;
  3. SELECT dept_id, AVG(salary) FROM employees GROUP BY dept_id WHERE AVG(salary) > 60000;
  4. SELECT dept_id FROM employees HAVING AVG(salary) > 60000;
B is correct. Aggregate conditions (like AVG(salary) > 60000) must go in HAVING, not WHERE. WHERE runs before grouping, so it has no idea what the average is yet. Option A puts the aggregate in WHERE (error). Option C has WHERE after GROUP BY (wrong syntax order). Option D is missing GROUP BY entirely.
Question

In the SQL execution order, which runs first — SELECT or WHERE?

  1. SELECT, because it's written first
  2. WHERE, because it runs at step 2 while SELECT runs at step 5
  3. They run simultaneously
  4. It depends on the database engine
WHERE runs at step 2, long before SELECT at step 5. This is why you cannot use column aliases (defined in SELECT) in your WHERE clause — WHERE has already finished running by the time SELECT defines the alias. The execution order is: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.

JOINs

Why do JOINs exist? In a well-designed database, data is split across multiple tables to avoid repetition. Employees are in one table, departments in another. But when your manager asks "show me each employee with their department name," that data lives in TWO tables. A JOIN combines them.

The Excel analogy
Imagine you have two Excel sheets. Sheet 1 has employee data with a "dept_id" column. Sheet 2 has department data with "dept_id" and "dept_name." A JOIN is like using VLOOKUP to pull the department name into the employee sheet by matching on dept_id. That is ALL a JOIN does — it matches rows from two tables using a common column.
JOIN TypeReturnsWhen to use
INNER JOINOnly matching rows from both tablesYou want only employees who HAVE a department
LEFT JOIN (LEFT OUTER)All rows from left table + matching from rightYou want ALL employees, even those without a department
RIGHT JOIN (RIGHT OUTER)All rows from right table + matching from leftYou want ALL departments, even empty ones
FULL OUTER JOINAll rows from both tablesYou want everything — unmatched rows from both sides
CROSS JOINCartesian product (every row x every row)Rarely used. 10 employees x 5 depts = 50 rows
SELF JOINTable joined with itselfFinding relationships within the same table (e.g., employee → manager)

INNER JOIN

Only returns rows where there is a match in BOTH tables. If an employee has no department (dept_id is NULL), that employee is excluded from the results.

SELECT e.emp_name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;
INNER JOIN step by step
employees table: Darshan (dept 10), Priya (dept 20), Raj (dept NULL)
departments table: 10=Finance, 20=IT, 30=HR

INNER JOIN result: Darshan-Finance, Priya-IT
Raj is excluded (no matching dept). HR is excluded (no employees). Only the overlap survives.

LEFT JOIN

Returns ALL rows from the left table (employees), even if there is no match in the right table (departments). Unmatched right-side columns show NULL.

-- All employees, even those without a department
SELECT e.emp_name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id;
LEFT JOIN result (same data as above)
Darshan-Finance, Priya-IT, Raj-NULL
Raj appears now! His dept_name is NULL because he has no department. The LEFT table (employees) keeps ALL its rows.

RIGHT JOIN

The mirror of LEFT JOIN. Returns ALL rows from the right table, even if there is no match in the left table.

-- All departments, even those with no employees
SELECT e.emp_name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON e.dept_id = d.dept_id;
RIGHT JOIN result (same data)
Darshan-Finance, Priya-IT, NULL-HR
HR appears now! No employee is in HR, so emp_name is NULL. The RIGHT table (departments) keeps ALL its rows.

FULL OUTER JOIN

Returns EVERYTHING from both tables. No row is left behind — unmatched rows from both sides appear with NULLs.

SELECT e.emp_name, d.dept_name
FROM employees e
FULL OUTER JOIN departments d ON e.dept_id = d.dept_id;
FULL OUTER JOIN result (same data)
Darshan-Finance, Priya-IT, Raj-NULL, NULL-HR
Everyone shows up — even Raj (no dept) and HR (no employees).

CROSS JOIN

-- Every employee × every department (rarely useful)
SELECT e.emp_name, d.dept_name
FROM employees e
CROSS JOIN departments d;
CROSS JOIN = explosion of rows
If employees has 100 rows and departments has 10 rows, CROSS JOIN produces 100 x 10 = 1,000 rows. Every possible combination. This is called a Cartesian Product. Almost never what you want — usually the result of accidentally forgetting the ON clause.

SELF JOIN

A table joined with itself. The classic use case: an employees table where each employee has a manager_id that points to another employee in the SAME table.

-- Find each employee's manager
SELECT e.emp_name AS employee, m.emp_name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.emp_id;
JOIN diagram trick
Think of it as Venn diagrams:
INNER = only the overlap
LEFT = entire left circle + overlap
RIGHT = entire right circle + overlap
FULL OUTER = both entire circles
FA MCQ Pattern
"Which JOIN returns all rows from the left table?" → LEFT JOIN
"What is a Cartesian product?" → CROSS JOIN (no ON condition)
Question

Employees table has 10 rows, Departments table has 5 rows. How many rows does SELECT * FROM employees CROSS JOIN departments; produce?

  1. 15
  2. 10
  3. 50
  4. 5
CROSS JOIN produces the Cartesian product — every row from the first table combined with every row from the second table. 10 x 5 = 50 rows. This is why CROSS JOIN is rarely used intentionally and why you should always specify an ON condition with other JOINs.
Question

You want ALL employees listed, including those not assigned to any department. Their department name should show NULL. Which JOIN do you use?

  1. INNER JOIN
  2. LEFT JOIN (employees LEFT JOIN departments)
  3. RIGHT JOIN (employees RIGHT JOIN departments)
  4. CROSS JOIN
LEFT JOIN keeps ALL rows from the left table (employees) and fills in NULL for unmatched rows from the right table (departments). INNER JOIN would exclude employees without a department. RIGHT JOIN would keep all departments, not all employees.

Subqueries

Why do subqueries exist? Sometimes the answer to your question depends on another question. Example: "Show me employees who earn more than the average salary." You cannot write WHERE salary > AVG(salary) — that is illegal in SQL (aggregate functions are not allowed in WHERE). So you need a subquery to first calculate the average, and then the outer query uses that result.

Think of it like this
A subquery is a question inside a question. Like asking: "Who scored higher than the class average?" You first need to calculate the average (inner query), and then check who is above it (outer query). The database runs the inner query first, gets a result, and plugs that result into the outer query.

Single-Row Subquery

The inner query returns exactly ONE value. You can use =, >, <, >=, <= with it.

-- Employees earning more than the average salary
SELECT emp_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
How this runs step by step
1. Inner query runs: SELECT AVG(salary) FROM employees → returns 52000
2. Outer query becomes: SELECT emp_name, salary FROM employees WHERE salary > 52000
3. Result: all employees earning more than 52000

Multi-Row Subquery (use IN, ANY, ALL)

When the inner query returns MULTIPLE values, you cannot use =. You need IN (matches any value in the list), ANY, or ALL.

-- Employees in departments located in Mumbai
SELECT emp_name
FROM employees
WHERE dept_id IN (SELECT dept_id FROM departments WHERE location = 'Mumbai');

-- Salary greater than ALL in dept 20 (greater than the maximum)
SELECT emp_name, salary
FROM employees
WHERE salary > ALL (SELECT salary FROM employees WHERE dept_id = 20);

-- Salary greater than ANY in dept 20 (greater than the minimum)
SELECT emp_name, salary
FROM employees
WHERE salary > ANY (SELECT salary FROM employees WHERE dept_id = 20);

Correlated Subquery

In a normal subquery, the inner query runs once and its result is reused. In a correlated subquery, the inner query runs once for EACH row of the outer query — because it references a value from the outer query. This is slower but more powerful.

-- Employees earning more than the average of THEIR OWN department
SELECT emp_name, salary, dept_id
FROM employees e
WHERE salary > (SELECT AVG(salary) FROM employees WHERE dept_id = e.dept_id);
How a correlated subquery differs
For Darshan (dept 10): inner query calculates AVG salary of dept 10 → checks if Darshan's salary exceeds it.
For Priya (dept 20): inner query calculates AVG salary of dept 20 → checks if Priya's salary exceeds it.
The inner query re-runs for every row with a different dept_id reference. That is what "correlated" means — the inner query is linked to the outer query.

EXISTS

EXISTS checks if the subquery returns ANY rows at all. It does not care about the actual values — just whether rows exist. It is often faster than IN for large datasets.

-- Departments that have at least one employee
SELECT dept_name
FROM departments d
WHERE EXISTS (SELECT 1 FROM employees WHERE dept_id = d.dept_id);
ANY vs ALL — Memorize this
> ALL (subquery) = greater than the maximum value returned. You must beat EVERYONE.
> ANY (subquery) = greater than the minimum value returned. You just need to beat ONE person.
< ALL = less than the minimum. < ANY = less than the maximum.
Question

Dept 20 has salaries: 40000, 50000, 60000. Which employees are returned by WHERE salary > ALL (SELECT salary FROM employees WHERE dept_id = 20)?

  1. Employees earning more than 40000
  2. Employees earning more than 50000
  3. Employees earning more than 60000
  4. All employees in dept 20
> ALL means "greater than the MAXIMUM value in the list." The maximum salary in dept 20 is 60000, so only employees earning more than 60000 are returned. Think of ALL as "you must beat ALL of them" — which means beating the highest one.
Question

What is the key difference between a regular subquery and a correlated subquery?

  1. A correlated subquery can return multiple rows; a regular subquery cannot
  2. A regular subquery runs once; a correlated subquery re-runs for each outer row
  3. A correlated subquery uses JOIN; a regular subquery uses WHERE
  4. There is no difference — they are the same thing
A regular subquery is independent — it runs once, produces a result, and the outer query uses that result. A correlated subquery references a column from the outer query (like e.dept_id), so it must re-execute for each row of the outer query. This makes correlated subqueries slower but capable of row-specific comparisons.

Set Operations

Set operations let you combine the results of two separate SELECT queries. Think of them like math operations on sets: union (combine), intersection (overlap), and difference (subtract).

OperationDescriptionAnalogy
UNIONCombine results, remove duplicatesMerge two guest lists, removing duplicate names
UNION ALLCombine results, keep duplicatesJust staple the two lists together
INTERSECTOnly rows in BOTH queriesPeople who appear on BOTH guest lists
MINUS (Oracle) / EXCEPT (MySQL)Rows in first query but NOT in secondPeople on list A who are NOT on list B
-- All cities where we have employees or departments
SELECT city FROM employees
UNION
SELECT city FROM departments;

-- Employees who are also managers
SELECT emp_id FROM employees
INTERSECT
SELECT manager_id FROM employees;
Set Operation Rules
Both queries must have the same number of columns and compatible data types. You cannot UNION a query with 3 columns and another with 5 columns — SQL won't know how to combine them.
Question

What is the difference between UNION and UNION ALL?

  1. UNION sorts results; UNION ALL does not
  2. UNION removes duplicates; UNION ALL keeps all rows including duplicates
  3. UNION ALL is faster because it removes duplicates
  4. There is no difference
UNION removes duplicate rows from the combined result (which requires extra work to check for duplicates). UNION ALL keeps everything as-is, including duplicates. UNION ALL is actually faster because it skips the deduplication step. Use UNION ALL when you know there won't be duplicates or when you want to keep them.

Constraints & Keys

Why do constraints exist? Without constraints, anyone could insert garbage data: an employee with a negative salary, two employees with the same ID, an employee assigned to a department that does not exist. Constraints are the database's bouncers — they enforce rules so your data stays clean and consistent.

Real-world analogy
Think of constraints like rules on a form. PRIMARY KEY = "this field is mandatory and must be unique" (like Aadhaar number). NOT NULL = "you must fill this in." CHECK = "age must be 18 or above." FOREIGN KEY = "the department you list here must actually exist in the departments table." If you violate any rule, the form (INSERT/UPDATE) gets rejected.
ConstraintDescriptionWhat it prevents
PRIMARY KEYUnique + NOT NULL. Only one per table.Duplicate or empty IDs
FOREIGN KEYReferences PRIMARY KEY of another tableOrphan records (referencing non-existent data)
UNIQUEAll values must be different (allows one NULL)Duplicate emails, duplicate phone numbers
NOT NULLColumn cannot have NULL valueMissing required fields
CHECKValues must satisfy a conditionInvalid data (negative salary, age below 0)
DEFAULTDefault value if none providedNothing — just fills in a value automatically
CREATE TABLE students (
    student_id NUMBER PRIMARY KEY,
    name       VARCHAR2(50) NOT NULL,
    email      VARCHAR2(100) UNIQUE,
    age        NUMBER CHECK (age >= 18),
    status     VARCHAR2(10) DEFAULT 'active',
    dept_id    NUMBER REFERENCES departments(dept_id)
);

Composite Primary Key

Sometimes a single column cannot uniquely identify a row. In an "enrollments" table, neither student_id alone nor course_id alone is unique (a student can enroll in many courses, a course can have many students). But the COMBINATION of both is unique — a student can enroll in a specific course only once.

CREATE TABLE enrollments (
    student_id NUMBER,
    course_id  NUMBER,
    grade      CHAR(2),
    PRIMARY KEY (student_id, course_id)
);
PRIMARY KEY vs UNIQUE — Know the difference
PRIMARY KEY = UNIQUE + NOT NULL. Only ONE per table. It is the main identifier for each row.
UNIQUE = values must be different, but allows ONE NULL. Multiple UNIQUE constraints per table allowed.

Example: A student has one student_id (PRIMARY KEY) but also a unique email and unique phone number (both UNIQUE constraints on the same table).

ON DELETE actions (Foreign Key)

What happens when you delete a department that still has employees assigned to it? The ON DELETE action decides.

ActionWhat happens when parent row is deletedExample
ON DELETE CASCADEDelete child rows tooDelete department 10 → all employees in dept 10 are also deleted
ON DELETE SET NULLSet foreign key to NULL in child rowsDelete department 10 → employees in dept 10 get dept_id = NULL
ON DELETE RESTRICTPrevent deletion if child rows exist (default)Cannot delete department 10 while it has employees — error is thrown
Question

A table has a PRIMARY KEY and three UNIQUE constraints. How many total unique identifier columns does it have?

  1. 1 — only PRIMARY KEY provides uniqueness
  2. 3 — only UNIQUE constraints count
  3. 4 — PRIMARY KEY is also a unique identifier
  4. Error — a table cannot have both PRIMARY KEY and UNIQUE
The table has 4 unique identifier columns: 1 PRIMARY KEY + 3 UNIQUE constraints. PRIMARY KEY itself enforces uniqueness (it is UNIQUE + NOT NULL). A table can absolutely have both — one PRIMARY KEY and multiple UNIQUE constraints. Example: student_id (PK), email (UNIQUE), phone (UNIQUE), aadhaar (UNIQUE).
Question

If a FOREIGN KEY is defined with ON DELETE CASCADE, what happens when the parent row is deleted?

  1. Nothing — the child rows remain unchanged
  2. The child rows' foreign key column is set to NULL
  3. All child rows referencing that parent are also deleted
  4. The deletion is blocked with an error
CASCADE means the delete "cascades" down to child rows. If you delete department 10, all employees with dept_id = 10 are automatically deleted too. This is powerful but dangerous — use with caution. SET NULL would just set their dept_id to NULL. RESTRICT (default) would block the deletion entirely.

Normalization

Why does normalization matter? Imagine a table where every employee row stores the department name, department location, and department manager. Now the HR department moves to a new office. You have to update the location in 200 employee rows. Miss even one? Your data is now inconsistent — some rows say "Mumbai," others say "Pune" for the same department.

Normalization is the process of organizing your tables so that each piece of information is stored in exactly ONE place. Update it once, and it is correct everywhere. It eliminates redundancy and prevents the kind of update anomalies described above.

The analogy
Unnormalized data is like writing your home address on every form at school — attendance register, library card, exam form, fee receipt. If you move, you have to update ALL of them. Normalized data stores your address in ONE place (student record), and every other form just references your student ID.
Normal FormRuleIn Simple TermsExample Violation
1NFAtomic values, no repeating groupsEach cell has ONE value. No comma-separated lists.courses = "Math, Physics, Chemistry" in one cell
2NF1NF + no partial dependencyEvery non-key column depends on the WHOLE primary key (not just part of it).In (student_id, course_id) → student_name depends only on student_id, not on the full key
3NF2NF + no transitive dependencyNon-key columns depend ONLY on the primary key, not on other non-key columns.emp table has dept_id AND dept_name — dept_name depends on dept_id, not on emp_id
BCNF3NF + every determinant is a candidate keyStricter version of 3NF.Rare edge cases where 3NF still has redundancy
Step-by-step normalization
Unnormalized: Student(id, name, courses: "Math, Physics, Chem") — courses is a comma-separated mess

1NF: Split into separate rows — one row per student-course combination. Now each cell has ONE atomic value.

2NF: If the primary key is (student_id, course_id), then student_name depends only on student_id (partial dependency). Fix: move student info to a separate Students table.

3NF: If the Students table has dept_id AND dept_name, the dept_name depends on dept_id (not on student_id). This is a transitive dependency. Fix: move dept_name to a separate Departments table.
FA MCQ Pattern
"A table with no repeating groups is in which normal form?" → 1NF
"Removing transitive dependency achieves?" → 3NF
"Removing partial dependency achieves?" → 2NF
Question

A table has columns: (student_id PK, student_name, dept_id, dept_name). Which normal form is violated and why?

  1. 1NF — because values are not atomic
  2. 2NF — because of partial dependency
  3. 3NF — because dept_name depends on dept_id, not on the primary key
  4. No violation — the table is fully normalized
This violates 3NF. The dept_name column depends on dept_id (a non-key column), not directly on student_id (the primary key). This is called a transitive dependency: student_id → dept_id → dept_name. Fix: move dept_name to a separate departments table with dept_id as the primary key.
Question

A cell in a table contains "Java, Python, SQL" as a single value. Which normal form rule is violated?

  1. 1NF — values must be atomic (one value per cell)
  2. 2NF — partial dependency
  3. 3NF — transitive dependency
  4. BCNF — determinant is not a candidate key
1NF requires atomic values — each cell must contain exactly ONE value. A comma-separated list like "Java, Python, SQL" violates 1NF. The fix: create a separate skills table with one row per skill (student_id, skill).

Views

Why do views exist? Imagine you have a complex query with 5 JOINs that you run 10 times a day. Instead of writing that monster query every time, you save it as a view — a virtual table that runs the query behind the scenes whenever you access it. Views also let you control what data different users can see.

Think of it this way
A view is like a saved filter in a spreadsheet. The underlying data does not change — the view just shows you a specific slice of it. Every time you open the view, it re-runs the query and shows you the latest data.
-- Create a view
CREATE VIEW high_earners AS
SELECT emp_name, salary, dept_id
FROM employees
WHERE salary > 50000;

-- Use the view like a table
SELECT * FROM high_earners;

-- Replace a view
CREATE OR REPLACE VIEW high_earners AS
SELECT emp_name, salary FROM employees WHERE salary > 60000;

-- Drop a view
DROP VIEW high_earners;
Why use Views?
  • Security: Give interns access to a view that only shows name and department — not salary. They never see the base table.
  • Simplicity: A 50-line JOIN query becomes SELECT * FROM quarterly_report.
  • Consistency: Everyone uses the same view definition — no one writes a slightly different version of the query.
Question

Does a view store data physically in the database?

  1. Yes — it creates a copy of the data
  2. No — it stores only the query definition and runs it each time
  3. Yes — but only for the first access, then it caches
  4. It depends on the database engine
A regular view does NOT store data — it stores only the SELECT query definition. Every time you query the view, it re-executes the underlying query against the base tables. This means the view always shows the latest data. (Note: Materialized Views DO store data physically, but they are a separate concept.)

Indexes

Why do indexes exist? Without an index, searching for an employee named "Darshan" in a table of 1 million rows means the database scans every single row — like reading a 500-page book from page 1 to find one topic. An index is like the book's index at the back — you look up "Darshan," find it points to row 47892, and jump straight there.

The book index analogy
A book without an index: to find "polymorphism," you flip through every page (full table scan).
A book with an index: you check the back, see "polymorphism — page 234," and jump directly there.

A database index works the same way. It creates a sorted lookup structure (usually a B-tree) that lets the database find your data in milliseconds instead of scanning millions of rows.
-- Create an index
CREATE INDEX idx_emp_name ON employees(emp_name);

-- Create a unique index
CREATE UNIQUE INDEX idx_emp_email ON employees(email);

-- Composite index (useful when you often search by both columns together)
CREATE INDEX idx_dept_sal ON employees(dept_id, salary);

-- Drop an index
DROP INDEX idx_emp_name;
Index Trade-off — This is an exam favorite
Indexes speed up SELECT (reads) but slow down INSERT/UPDATE/DELETE (writes). Why? Every time you add, change, or remove a row, the database must also update all relevant indexes. It is like maintaining a book index — every time you add a new chapter, you have to update the index at the back.

Rule of thumb: Index columns that appear frequently in WHERE, JOIN, and ORDER BY. Do NOT index every column — the maintenance overhead is not worth it for rarely-searched columns.
Automatic Indexes
The database automatically creates an index on PRIMARY KEY and UNIQUE columns. You never need to manually index these.
Question

Which statement about indexes is FALSE?

  1. Indexes speed up SELECT queries
  2. Indexes slow down INSERT, UPDATE, DELETE operations
  3. You should create indexes on every column for maximum performance
  4. PRIMARY KEY columns are automatically indexed
Indexing every column is a terrible idea. Each index must be maintained on every INSERT/UPDATE/DELETE, which adds overhead. Only index columns that are frequently used in WHERE, JOIN, or ORDER BY clauses. Over-indexing can actually make your database SLOWER overall because writes become expensive.
Question

You have a table with 10 million rows. Queries filtering by WHERE city = 'Mumbai' are slow. What is the best solution?

  1. Add more RAM to the server
  2. Create an index on the city column
  3. Use TRUNCATE to remove unnecessary rows
  4. Change the column data type to CHAR
Creating an index on the city column lets the database quickly locate all rows with city = 'Mumbai' without scanning all 10 million rows. This is the textbook use case for indexes — a column frequently used in WHERE conditions on a large table.

Transactions & TCL

Why do transactions exist? Imagine transferring Rs. 1000 from your account to a friend's account. This involves TWO operations: (1) subtract 1000 from your balance, (2) add 1000 to friend's balance. What if the system crashes after step 1 but before step 2? Your money vanishes into thin air. Transactions prevent this by treating both operations as ONE atomic unit — either BOTH succeed, or BOTH are undone.

The video game analogy
A transaction is like a checkpoint in a video game. You make a bunch of moves, and if things go wrong, you can "load last checkpoint" (ROLLBACK). If everything goes well, you "save game" (COMMIT). SAVEPOINT is like creating a manual save in the middle of a level.

ACID Properties

Every transaction follows four rules, remembered as ACID. This is a guaranteed exam question.

PropertyMeaningReal-World Example
AtomicityAll or nothing — entire transaction succeeds or failsBank transfer: both debit AND credit happen, or neither does
ConsistencyDatabase moves from one valid state to anotherTotal money in the system remains the same after transfer
IsolationConcurrent transactions don't interfereTwo people transferring money simultaneously don't see each other's half-done work
DurabilityOnce committed, changes survive crashesAfter bank confirms transfer, even if the server crashes, your money is safe
-- Bank transfer: a classic transaction example
UPDATE accounts SET balance = balance - 1000 WHERE acc_id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE acc_id = 2;
COMMIT;  -- Save changes permanently — cannot be undone after this

-- Something went wrong? Undo everything since last COMMIT
ROLLBACK;

-- Savepoints — partial rollback
SAVEPOINT sp1;
UPDATE employees SET salary = 70000 WHERE emp_id = 101;
SAVEPOINT sp2;
DELETE FROM employees WHERE emp_id = 103;
ROLLBACK TO sp2;  -- Undo DELETE but keep the UPDATE
DDL auto-commits
In Oracle, DDL statements (CREATE, ALTER, DROP, TRUNCATE) automatically issue a COMMIT. You cannot rollback a TRUNCATE or DROP. This also means if you had uncommitted DML changes, running a DDL statement will commit those too!
Question

Which ACID property ensures that a bank transfer either fully completes or fully rolls back?

  1. Consistency
  2. Isolation
  3. Durability
  4. Atomicity
Atomicity means "all or nothing." Either the entire transaction (debit + credit) completes successfully, or the entire thing is rolled back. No half-done states. The word "atomic" comes from Greek "atomos" meaning "indivisible."
Question

You run an UPDATE, then a CREATE TABLE, then a ROLLBACK. What happens?

  1. Both the UPDATE and CREATE TABLE are rolled back
  2. Only the CREATE TABLE is rolled back
  3. Nothing is rolled back — CREATE TABLE auto-committed everything
  4. Error — ROLLBACK cannot follow CREATE TABLE
In Oracle, CREATE TABLE is DDL, which triggers an automatic COMMIT. This commits both the CREATE TABLE AND any uncommitted changes before it (including your UPDATE). When you then run ROLLBACK, there is nothing to roll back — everything was already committed by the DDL statement.

DCL — GRANT & REVOKE

Why does DCL exist? In a company, not everyone should have the same access. An intern should not be able to DELETE employee records. The CEO's assistant might need to read salary data but never modify it. DCL controls who can do what.

-- Grant permissions
GRANT SELECT, INSERT ON employees TO user1;
GRANT ALL ON employees TO admin_user;

-- Revoke permissions
REVOKE INSERT ON employees FROM user1;

-- Grant with pass-along ability
GRANT SELECT ON employees TO user1 WITH GRANT OPTION;
WITH GRANT OPTION
This gives user1 the ability to grant the same permission to OTHER users. Like giving someone a master key AND the ability to make copies. Use carefully — it can lead to uncontrolled permission spreading.
Question

What does GRANT SELECT ON employees TO user1 WITH GRANT OPTION do?

  1. Gives user1 SELECT access only
  2. Gives user1 SELECT access and the ability to grant SELECT to others
  3. Gives user1 all permissions on employees
  4. Creates a view for user1
WITH GRANT OPTION allows user1 to further grant the same privilege (SELECT on employees) to other users. Without this option, user1 can use SELECT but cannot pass the permission along.

Miscellaneous Concepts

CASE Expression

CASE is SQL's version of if-else. It lets you create calculated columns based on conditions — like adding a "level" label based on salary ranges.

SELECT emp_name, salary,
  CASE
    WHEN salary > 80000 THEN 'Senior'
    WHEN salary > 50000 THEN 'Mid'
    ELSE 'Junior'
  END AS level
FROM employees;

CREATE TABLE AS SELECT (CTAS)

-- Create a backup table from existing data
CREATE TABLE emp_backup AS
SELECT * FROM employees WHERE dept_id = 10;

RENAME & COMMENT

-- Rename a table
RENAME employees TO staff;

-- Add a comment on table
COMMENT ON TABLE employees IS 'Main employee table';

Pseudo-columns (Oracle)

Pseudo-columnDescription
ROWNUMRow number in result set
ROWIDPhysical address of the row
SYSDATECurrent date and time
USERCurrent logged-in user

DECODE (Oracle-specific IF-THEN)

SELECT emp_name,
  DECODE(dept_id,
    10, 'Finance',
    20, 'IT',
    30, 'HR',
    'Other') AS dept_name
FROM employees;
DECODE vs CASE
DECODE is Oracle-only, works for simple equality checks only.
CASE is ANSI standard, works everywhere, supports complex conditions (ranges, LIKE, IS NULL). Prefer CASE.

Sequences (Oracle — auto-increment)

-- Create a sequence
CREATE SEQUENCE emp_seq START WITH 1 INCREMENT BY 1;

-- Use in INSERT
INSERT INTO employees (emp_id, emp_name)
VALUES (emp_seq.NEXTVAL, 'Darshan');

-- Get current value
SELECT emp_seq.CURRVAL FROM dual;

Synonyms (Oracle)

-- Create a synonym (alias for a table)
CREATE SYNONYM emp FOR hr.employees;

-- Now use the short name
SELECT * FROM emp;

Practice Questions

Question 1

Which SQL command is used to remove all rows from a table without logging individual row deletions?

  1. DELETE
  2. DROP
  3. TRUNCATE
  4. REMOVE
C) TRUNCATE — removes all rows, keeps table structure, cannot be rolled back (DDL). DELETE logs each row and can be rolled back (DML).
Question 2

What is the output of: SELECT COUNT(*) FROM employees WHERE commission IS NULL; if 3 out of 10 employees have NULL commission?

  1. 7
  2. 3
  3. 10
  4. 0
B) 3 — COUNT(*) counts all rows that match the WHERE condition. 3 employees have NULL commission.
Question 3

Which JOIN returns all rows from both tables, including unmatched rows?

  1. INNER JOIN
  2. LEFT JOIN
  3. FULL OUTER JOIN
  4. CROSS JOIN
C) FULL OUTER JOIN — returns all rows from both tables. Unmatched rows get NULL for the other table's columns.
Question 4

Which clause is used to filter groups after GROUP BY?

  1. WHERE
  2. HAVING
  3. FILTER
  4. GROUP FILTER
B) HAVING — filters groups after GROUP BY. WHERE filters individual rows before grouping.
Question 5

A table with no repeating groups and only atomic values in each cell satisfies which normal form?

  1. 2NF
  2. BCNF
  3. 1NF
  4. 3NF
C) 1NF (First Normal Form) — requires atomic values (no repeating groups, no comma-separated lists).
Question 6

What does GRANT SELECT ON employees TO user1 WITH GRANT OPTION do?

  1. Gives user1 SELECT access only
  2. Gives user1 SELECT access and the ability to grant SELECT to others
  3. Gives user1 all permissions on employees
  4. Creates a view for user1
B) WITH GRANT OPTION allows user1 to further grant the same privilege to other users.
Question 7

Which function returns the first non-NULL value from a list?

  1. NVL
  2. IFNULL
  3. COALESCE
  4. NULLIF
C) COALESCE — returns the first non-NULL value from any number of arguments. NVL only takes 2 arguments (Oracle-specific).
Question 8

What does SELECT emp_name FROM employees WHERE salary > ALL (SELECT salary FROM employees WHERE dept_id = 20); return?

  1. Employees earning more than any employee in dept 20
  2. Employees earning more than every employee in dept 20
  3. Employees earning less than all in dept 20
  4. Error — ALL cannot be used with subqueries
B) > ALL means greater than the MAXIMUM value returned by the subquery. So it returns employees earning more than every employee in dept 20.
Question 9

The ACID property that ensures a transaction is "all or nothing" is:

  1. Consistency
  2. Isolation
  3. Durability
  4. Atomicity
D) Atomicity — the transaction either completes entirely or not at all. If any part fails, the entire transaction is rolled back.
Question 10

What is the difference between DELETE FROM employees; and TRUNCATE TABLE employees;?

  1. No difference — both do the same thing
  2. DELETE is DDL, TRUNCATE is DML
  3. DELETE can be rolled back, TRUNCATE cannot
  4. TRUNCATE can use WHERE clause, DELETE cannot
C) DELETE is DML (can be rolled back, logs each row deletion, can use WHERE). TRUNCATE is DDL (cannot be rolled back, removes all rows instantly, no WHERE clause).