Mastering SQL: A Comprehensive Training Program

From Basics to Advanced Queries for Data Professionals

Welcome to the SQL Training Program!

This program is designed to guide you through the essential concepts and practical applications of SQL, from setting up your first database to writing complex queries and understanding data modeling principles. Each section includes study content and runnable code examples, perfect for video tutorials and hands-on learning.

SQL (Structured Query Language) is the universal language for managing and manipulating relational databases. Whether you're aspiring to be a Data Analyst, Data Engineer, Business Intelligence Developer, or Data Scientist, a strong foundation in SQL is indispensable.

Let's dive in!

Programme Coverage

1

Introduction to SQL

This module provides a foundational understanding of SQL, its importance, and how to set up your environment.

  • Overview of SQL: What is SQL, its role in data, and RDBMS concepts.
  • History and Evolution of SQL: Brief journey from SEQUEL to modern standards.
  • Setting Up the Database Environment: Choosing an RDBMS (e.g., SQLite for simplicity), installation, and basic client usage.

Mini Project: Creating a Database and Basic Queries

Let's start by creating a simple database and a table, then inserting some data to run your first query. For this, we'll use SQLite, which is file-based and requires no server setup.

-- Connect to SQLite (e.g., using 'sqlite3 your_database.db' in terminal or a GUI tool)

-- 1. Create a new database (if using SQLite, this happens when you connect to a new file)
-- For other RDBMS like PostgreSQL/MySQL:
-- CREATE DATABASE MyFirstDB;
-- USE MyFirstDB;  -- (For SQL Server/MySQL)
-- \c MyFirstDB;  -- (For PostgreSQL)

-- 2. Create a simple table named 'Students'
CREATE TABLE Students (
    StudentID INTEGER PRIMARY KEY,
    FirstName TEXT NOT NULL,
    LastName TEXT NOT NULL,
    Age INTEGER,
    Major TEXT
);

-- 3. Insert some sample data into the 'Students' table
INSERT INTO Students (StudentID, FirstName, LastName, Age, Major) VALUES
(1, 'Alice', 'Smith', 20, 'Computer Science'),
(2, 'Bob', 'Johnson', 22, 'Engineering'),
(3, 'Charlie', 'Brown', 21, 'History'),
(4, 'Diana', 'Prince', 20, 'Computer Science');

-- 4. Retrieve all data from the 'Students' table
SELECT * FROM Students;

-- 5. Retrieve only FirstName and Major
SELECT FirstName, Major FROM Students;

-- 6. Retrieve students older than 20
SELECT * FROM Students WHERE Age > 20;
2

Data Modelling and Normalisation

Understanding how to structure your data is as crucial as querying it. This module covers database design principles.

  • Entity Relationship (ER) Model: Entities, attributes, relationships, and cardinality.
  • Normalisation (1NF, 2NF, 3NF): Principles to reduce redundancy and improve integrity.
  • Denormalisation and Performance Optimisation: When to break normalisation rules for performance.

Mini Project: Designing a Database Schema

While this is primarily a conceptual design exercise, we can illustrate the idea of a normalized schema with DDL.

-- Conceptual Example: Designing a simple Order Management System (Normalized to 3NF)

-- Customers Table (1NF, 2NF, 3NF)
CREATE TABLE Customers (
    CustomerID INTEGER PRIMARY KEY,
    CustomerName TEXT NOT NULL,
    Email TEXT UNIQUE,
    Phone TEXT
);

-- Products Table (1NF, 2NF, 3NF)
CREATE TABLE Products (
    ProductID INTEGER PRIMARY KEY,
    ProductName TEXT NOT NULL,
    Category TEXT,
    UnitPrice DECIMAL(10, 2) NOT NULL
);

-- Orders Table (linking Customers and containing order details)
CREATE TABLE Orders (
    OrderID INTEGER PRIMARY KEY,
    CustomerID INTEGER NOT NULL,
    OrderDate DATE NOT NULL,
    TotalAmount DECIMAL(10, 2),
    FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
);

-- OrderDetails Table (linking Products to Orders, handling many-to-many relationship)
CREATE TABLE OrderDetails (
    OrderDetailID INTEGER PRIMARY KEY,
    OrderID INTEGER NOT NULL,
    ProductID INTEGER NOT NULL,
    Quantity INTEGER NOT NULL,
    PriceAtOrder DECIMAL(10, 2) NOT NULL,
    FOREIGN KEY (OrderID) REFERENCES Orders(OrderID),
    FOREIGN KEY (ProductID) REFERENCES Products(ProductID)
);

-- Example of Denormalization (for reporting, adding CustomerName directly to Orders)
-- ALTER TABLE Orders ADD COLUMN CustomerName TEXT;
-- UPDATE Orders SET CustomerName = (SELECT CustomerName FROM Customers WHERE Customers.CustomerID = Orders.CustomerID);
3

SQL Basics

This module covers the fundamental commands for defining and manipulating data in your database.

  • Data Definition Language (DDL): 'CREATE', 'ALTER', 'DROP', 'TRUNCATE'.
  • Data Manipulation Language (DML): 'SELECT', 'INSERT', 'UPDATE', 'DELETE'.
  • Filtering data with the WHERE clause: Operators like '=', '>', '<', '<=', '>=', 'AND', 'OR', 'LIKE', 'IN', 'BETWEEN'.

Mini Project: Creating a Table and Inserting Data

Let's practice DDL and DML commands on a new table.

-- 1. Create a new table 'Employees'
CREATE TABLE Employees (
    EmployeeID INT PRIMARY KEY,
    FirstName VARCHAR(50) NOT NULL,
    LastName VARCHAR(50) NOT NULL,
    Department VARCHAR(50),
    Salary DECIMAL(10, 2)
);

-- 2. Insert data into 'Employees'
INSERT INTO Employees (EmployeeID, FirstName, LastName, Department, Salary) VALUES
(101, 'John', 'Doe', 'Sales', 60000.00),
(102, 'Jane', 'Smith', 'Marketing', 55000.00),
(103, 'Peter', 'Jones', 'Sales', 70000.00),
(104, 'Alice', 'Williams', 'IT', 75000.00),
(105, 'Bob', 'Brown', 'Marketing', 62000.00);

-- 3. Select all employees
SELECT * FROM Employees;

-- 4. Select employees from 'Sales' department
SELECT * FROM Employees WHERE Department = 'Sales';

-- 5. Select employees with salary greater than 65000
SELECT * FROM Employees WHERE Salary > 65000.00;

-- 6. Update Peter's salary
UPDATE Employees SET Salary = 68000.00 WHERE EmployeeID = 102;
SELECT * FROM Employees WHERE EmployeeID = 102;

-- 7. Delete Peter Jones
DELETE FROM Employees WHERE EmployeeID = 103;
SELECT * FROM Employees; -- Verify deletion

-- 8. Add a new column 'HireDate'
ALTER TABLE Employees ADD COLUMN HireDate DATE;

-- 9. Drop the 'Employees' table (use with caution!)
-- DROP TABLE Employees;
4

Stored Procedures and Functions

Automate tasks and encapsulate logic with stored procedures and functions for reusability and performance.

  • Creating Stored Procedures: Syntax, parameters, benefits.
  • User-Defined Functions (UDFs): Scalar vs. Table-valued functions.
  • Triggers and Cursors: Automated actions on DML events (triggers); brief mention of cursors.

Mini Project: Implementing Stored Procedures

Let's create a stored procedure to add a new employee and a function to calculate bonus.

-- For SQL Server/PostgreSQL/MySQL syntax might vary slightly

-- 1. Create a Stored Procedure to add a new employee
-- SQL Server Syntax Example:
CREATE PROCEDURE AddNewEmployee
    @p_EmployeeID INT,
    @p_FirstName VARCHAR(50),
    @p_LastName VARCHAR(50),
    @p_Department VARCHAR(50),
    @p_Salary DECIMAL(10, 2)
AS
BEGIN
    INSERT INTO Employees (EmployeeID, FirstName, LastName, Department, Salary)
    VALUES (@p_EmployeeID, @p_FirstName, @p_LastName, @p_Department, @p_Salary);
END;
GO -- SQL Server batch separator

-- PostgreSQL/MySQL Syntax Example:
-- DELIMITER //
-- CREATE PROCEDURE AddNewEmployee(
--     IN p_EmployeeID INT,
--     IN p_FirstName VARCHAR(50),
--     IN p_LastName VARCHAR(50),
--     IN p_Department VARCHAR(50),
--     IN p_Salary DECIMAL(10, 2)
-- )
-- BEGIN
--     INSERT INTO Employees (EmployeeID, FirstName, LastName, Department, Salary)
--     VALUES (p_EmployeeID, p_FirstName, p_LastName, p_Department, p_Salary);
-- END //
-- DELIMITER ;

-- 2. Execute the Stored Procedure
EXEC AddNewEmployee 106, 'Michael', 'Scott', 'Management', 90000.00; -- SQL Server
-- CALL AddNewEmployee(106, 'Michael', 'Scott', 'Management', 90000.00); -- PostgreSQL/MySQL

SELECT * FROM Employees WHERE EmployeeID = 106;

-- 3. Create a User-Defined Function (Scalar Function) to calculate annual bonus
-- SQL Server Syntax Example:
CREATE FUNCTION CalculateBonus (@p_Salary DECIMAL(10, 2))
RETURNS DECIMAL(10, 2)
AS
BEGIN
    RETURN @p_Salary * 0.10; -- 10% bonus
END;
GO

-- PostgreSQL Syntax Example:
-- CREATE FUNCTION CalculateBonus(p_Salary NUMERIC)
-- RETURNS NUMERIC AS $$
-- BEGIN
--     RETURN p_Salary * 0.10;
-- END;
-- $$ LANGUAGE plpgsql;

-- MySQL Syntax Example:
-- DELIMITER //
-- CREATE FUNCTION CalculateBonus(p_Salary DECIMAL(10, 2))
-- RETURNS DECIMAL(10, 2)
-- DETERMINISTIC
-- BEGIN
--     RETURN p_Salary * 0.10;
-- END //
-- DELIMITER ;

-- 4. Use the Function in a SELECT statement
SELECT EmployeeID, FirstName, LastName, Salary, dbo.CalculateBonus(Salary) AS AnnualBonus FROM Employees; -- SQL Server
-- SELECT EmployeeID, FirstName, LastName, Salary, CalculateBonus(Salary) AS AnnualBonus FROM Employees; -- PostgreSQL
5

Advanced SQL Queries

Master complex data retrieval with joins, aggregations, subqueries, and window functions.

  • Joins: 'INNER', 'LEFT', 'RIGHT', 'FULL OUTER' joins.
  • Aggregation Functions: 'COUNT', 'SUM', 'AVG', 'MAX', 'MIN' with 'GROUP BY' and 'HAVING'.
  • Subqueries and Nested Queries: Using queries within queries.
  • Window Functions (Analytic Functions): 'ROW_NUMBER()', 'RANK()', 'LAG()', 'LEAD()'.

Mini Project: Performing Joins and Aggregations

Let's set up two tables and practice various join types and aggregations.

-- Create a 'Departments' table
CREATE TABLE Departments (
    DepartmentID INT PRIMARY KEY,
    DepartmentName VARCHAR(50) NOT NULL,
    Location VARCHAR(50)
);

-- Insert data into 'Departments'
INSERT INTO Departments (DepartmentID, DepartmentName, Location) VALUES
(1, 'Sales', 'New York'),
(2, 'Marketing', 'London'),
(3, 'IT', 'San Francisco'),
(4, 'HR', 'New York');

-- Update 'Employees' to link to 'Departments'
ALTER TABLE Employees ADD COLUMN DepartmentID INT;
UPDATE Employees SET DepartmentID = 1 WHERE Department = 'Sales';
UPDATE Employees SET DepartmentID = 2 WHERE Department = 'Marketing';
UPDATE Employees SET DepartmentID = 3 WHERE Department = 'IT';
UPDATE Employees SET DepartmentID = 4 WHERE Department = 'HR'; -- Assuming HR exists now
UPDATE Employees SET DepartmentID = NULL WHERE Department IS NULL; -- For Michael Scott if no department yet

-- 1. INNER JOIN: Employees with their departments
SELECT
    E.FirstName,
    E.LastName,
    D.DepartmentName,
    D.Location
FROM
    Employees AS E
INNER JOIN
    Departments AS D ON E.DepartmentID = D.DepartmentID;

-- 2. LEFT JOIN: All employees and their departments (if any)
SELECT
    E.FirstName,
    E.LastName,
    D.DepartmentName
FROM
    Employees AS E
LEFT JOIN
    Departments AS D ON E.DepartmentID = D.DepartmentID;

-- 3. COUNT of employees per department
SELECT
    D.DepartmentName,
    COUNT(E.EmployeeID) AS NumberOfEmployees
FROM
    Departments AS D
LEFT JOIN
    Employees AS D ON D.DepartmentID = E.DepartmentID
GROUP BY
    D.DepartmentName;

-- 4. SUM of salaries per department, only for departments with > 1 employee
SELECT
    D.DepartmentName,
    SUM(E.Salary) AS TotalSalary
FROM
    Employees AS E
INNER JOIN
    Departments AS D ON D.DepartmentID = E.DepartmentID
GROUP BY
    D.DepartmentName
HAVING
    COUNT(E.EmployeeID) > 1;

-- 5. Subquery: Employees whose salary is above the average salary of their department
SELECT
    E.FirstName,
    E.LastName,
    E.Salary,
    E.Department
FROM
    Employees AS E
WHERE
    E.Salary > (SELECT AVG(Salary) FROM Employees WHERE Department = E.Department);

-- 6. Window Function: ROW_NUMBER() to rank employees within each department by salary
SELECT
    EmployeeID,
    FirstName,
    LastName,
    Department,
    Salary,
    ROW_NUMBER() OVER (PARTITION BY Department ORDER BY Salary DESC) AS RankInDepartment
FROM
    Employees
ORDER BY
    Department, RankInDepartment;
6

Data Import, Export, and Working with Databases

Learn how to move data in and out of your database efficiently and perform basic administration tasks.

  • Importing Data from External Sources: CSV, Excel, bulk operations.
  • Exporting Data to Different Formats: CSV, JSON.
  • Bulk Operations: Efficient large-scale data manipulation.
  • Database Administration (Basic Concepts): Backup, restore, user permissions.

Mini Project: Importing and Exporting Data (Conceptual)

Direct SQL for import/export varies greatly by RDBMS and tools. Here, we'll show conceptual commands and mention common methods.

-- Conceptual Example: Importing data from a CSV file
-- This command varies significantly by RDBMS.

-- SQL Server:
-- BULK INSERT NewTable
-- FROM 'C:\path\to\your\file.csv'
-- WITH (
--     ROWTERMINATOR = '\n',
--     FIRSTROW = 2 -- If your CSV has a header row
-- );

-- PostgreSQL:
-- COPY NewTable FROM 'C:\path\to\your\file.csv' DELIMITER ',' CSV HEADER;

-- MySQL:
-- LOAD DATA INFILE 'C:/path/to/your/file.csv'
-- INTO TABLE NewTable
-- FIELDS TERMINATED BY ',' ENCLOSED BY '"'
-- LINES TERMINATED BY '\n'
-- IGNORE 1 ROWS;

-- Conceptual Example: Exporting data to a CSV file
-- Again, this is often done via SQL client tools or specific RDBMS commands.

-- SQL Server (using sqlcmd or SSMS export wizard):
-- bcp "SELECT * FROM Employees" queryout "C:\path\to\employees.csv" -c -t, -S localhost -U user -P password

-- PostgreSQL (using psql):
-- \copy (SELECT * FROM Employees) TO 'C:\path\to\employees.csv' CSV HEADER;

-- MySQL (using mysql client or SELECT ... INTO OUTFILE):
-- SELECT * INTO OUTFILE 'C:/path/to/employees.csv'
-- FIELDS TERMINATED BY ',' ENCLOSED BY '"'
-- LINES TERMINATED BY '\n'
-- FROM Employees;

-- Basic User Management (Conceptual)
-- CREATE USER 'new_user'@'localhost' IDENTIFIED BY 'password'; -- MySQL
-- GRANT SELECT ON Employees TO new_user; -- PostgreSQL
-- GRANT SELECT ON Employees TO new_user; -- SQL Server
7

Manipulation in SQL

Advanced manipulation techniques for transforming and managing your data effectively.

  • String Functions: CONCAT, SUBSTRING, UPPER, LOWER, TRIM.
  • Date and Time Functions: DATE, DATETIME, formatting, extraction.
  • Conditional Logic: CASE statements for dynamic queries.
  • NULL Handling: IS NULL, COALESCE, NULLIF.

Mini Project: Data Manipulation Techniques

Let's apply various manipulation functions to transform and clean data.

-- String Manipulation
SELECT
    FirstName,
    LastName,
    CONCAT(FirstName, ' ', LastName) AS FullName,
    UPPER(FirstName) AS FirstNameUpper,
    LOWER(LastName) AS LastNameLower,
    LENGTH(FirstName) AS FirstNameLength
FROM Employees;

-- Date Functions (assuming we add HireDate)
-- Update with sample hire dates
UPDATE Employees SET HireDate = '2020-01-15' WHERE EmployeeID = 101;
UPDATE Employees SET HireDate = '2019-06-20' WHERE EmployeeID = 102;
UPDATE Employees SET HireDate = '2021-03-10' WHERE EmployeeID = 104;

SELECT
    FirstName,
    LastName,
    HireDate,
    YEAR(HireDate) AS HireYear,
    MONTH(HireDate) AS HireMonth,
    DATEDIFF(CURDATE(), HireDate) AS DaysSinceHire -- MySQL
FROM Employees
WHERE HireDate IS NOT NULL;

-- Conditional Logic with CASE
SELECT
    FirstName,
    LastName,
    Salary,
    CASE
        WHEN Salary >= 70000 THEN 'High'
        WHEN Salary >= 60000 THEN 'Medium'
        ELSE 'Low'
    END AS SalaryBracket
FROM Employees;

-- NULL Handling
SELECT
    FirstName,
    LastName,
    HireDate,
    COALESCE(HireDate, 'Not Available') AS HireDateDisplay
FROM Employees;
7

Manipulation in SQL (Continued)

Go beyond basic DML to ensure data integrity and manage transactions effectively.

  • Updating Data (Basic and Advanced): Conditional updates, multi-table updates, multi-table deletes.
  • Transactions and Rollbacks: ACID properties, 'BEGIN TRANSACTION', 'COMMIT', 'ROLLBACK'.
  • Constraints: 'NOT NULL', 'UNIQUE', 'PRIMARY KEY', 'FOREIGN KEY', 'CHECK'.

Mini Project: Implementing Constraints and Transactions

Let's ensure data integrity with constraints and manage data changes safely with transactions.

-- Create a new table 'Products' with various constraints
CREATE TABLE Products (
    ProductID INT PRIMARY KEY, -- PRIMARY KEY (NOT NULL + UNIQUE)
    ProductName VARCHAR(100) NOT NULL UNIQUE, -- NOT NULL and UNIQUE
    Category VARCHAR(50) DEFAULT 'General', -- DEFAULT value
    Price DECIMAL(10, 2) CHECK (Price > 0), -- CHECK constraint
    StockQuantity INT DEFAULT 0, -- DEFAULT value
    SupplierID INT,
    FOREIGN KEY (SupplierID) REFERENCES Suppliers(SupplierID) -- FOREIGN KEY (requires Suppliers table)
);

-- Create a 'Suppliers' table for the FOREIGN KEY
CREATE TABLE Suppliers (
    SupplierID INT PRIMARY KEY,
    SupplierName VARCHAR(100) NOT NULL
);

INSERT INTO Suppliers (SupplierID, SupplierName) VALUES (1, 'TechCorp'), (2, 'OfficeSupplies');

-- Insert valid data into Products
INSERT INTO Products (ProductID, ProductName, Category, Price, StockQuantity, SupplierID) VALUES
(1, 'Laptop', 'Electronics', 1200.00, 50, 1),
(2, 'Desk Chair', 'Furniture', 250.00, 30, 2);

-- Attempt to insert invalid data (violates NOT NULL for ProductName)
-- INSERT INTO Products (ProductID, Category, Price) VALUES (3, NULL, 'Electronics', 50.00);
-- Attempt to insert invalid data (violates UNIQUE for ProductName)
-- INSERT INTO Products (ProductID, ProductName, Category, Price) VALUES (3, 'Laptop', 'Electronics', 800.00);
-- Attempt to insert invalid data (violates CHECK for Price)
-- INSERT INTO Products (ProductID, ProductName, Category, Price) VALUES (3, 'Mouse', 'Electronics', -10.00);
-- Attempt to insert invalid data (violates FOREIGN KEY for SupplierID)
-- INSERT INTO Products (ProductID, ProductName, Category, Price, SupplierID) VALUES (3, 'Monitor', 'Electronics', 400.00, 99);

-- Transactions Example: Transferring funds (conceptual)
-- This ensures either both updates succeed or both fail.

BEGIN TRANSACTION; -- Start a transaction

-- Assume 'Accounts' table with AccountID, Balance
UPDATE Accounts SET Balance = Balance - 100 WHERE AccountID = 1;
UPDATE Accounts SET Balance = Balance + 100 WHERE AccountID = 2;

-- If everything is successful:
-- COMMIT;

-- If an error occurs or you decide to cancel:
-- ROLLBACK;

-- Example of a conditional update based on another table (SQL Server/PostgreSQL/MySQL variations)
-- UPDATE Employees
-- SET Salary = E.Salary * 1.10 -- Increase by 10%
-- FROM Employees E
-- INNER JOIN Departments D ON E.DepartmentID = D.DepartmentID
-- WHERE D.DepartmentName = 'Sales';

-- PostgreSQL/MySQL equivalent (using subquery or JOIN syntax)
-- UPDATE Employees
-- SET Salary = Employees.Salary * 1.10
-- WHERE DepartmentID IN (SELECT DepartmentID FROM Departments WHERE DepartmentName = 'Sales');
8

Real-World Cases

Apply your SQL knowledge to solve practical data challenges and adopt industry best practices.

  • SQL for Data Cleaning and Analysis: Deduplication, standardization, outlier handling.
  • SQL Best Practices: Writing readable, maintainable, and performant SQL.
  • SQL Security: Basic principles, SQL Injection prevention.

Discussion Points for Video:

  • Demonstrate how to find duplicate records and delete them using 'GROUP BY' and 'HAVING'.
  • Discuss the importance of using parameterized queries to prevent SQL Injection.
  • Show examples of poorly performing queries and how to optimize them (e.g., adding indexes).
9

Working with Multiple Tables

Extend your querying capabilities to combine data from various sources and optimize data access.

  • Complex Joins and Multi-Table Queries: Joining more than two tables, advanced conditions.
  • Set Operations: 'UNION', 'UNION ALL', 'INTERSECT', 'EXCEPT'.
  • Views and Indexes: Creating virtual tables and improving query performance.

Mini Project: Utilising Views and Indexes

Let's create a view for simplified reporting and add an index to speed up common queries.

-- 1. Create a View for Sales Report
-- Views simplify complex queries and can restrict data access.
CREATE VIEW SalesReport AS
SELECT
    O.OrderID,
    C.CustomerName,
    P.ProductName,
    OD.Quantity,
    OD.PriceAtOrder,
    (OD.Quantity * OD.PriceAtOrder) AS LineTotal,
    O.OrderDate
FROM
    Orders AS O
INNER JOIN
    Customers AS C ON O.CustomerID = C.CustomerID
INNER JOIN
    OrderDetails AS OD ON O.OrderID = OD.OrderID
INNER JOIN
    Products AS P ON OD.ProductID = P.ProductID;

-- Query the View
SELECT * FROM SalesReport WHERE OrderDate >= '2023-01-01';

-- 2. Set Operations: UNION (combining results from two similar tables)
-- Create TABLE NewEmployees table for demonstration
CREATE TABLE NewEmployees (
    EmployeeID INT PRIMARY KEY,
    FirstName VARCHAR(50),
    LastName VARCHAR(50),
    Department VARCHAR(50)
);

INSERT INTO NewEmployees (EmployeeID, FirstName, LastName, Department) VALUES
(201, 'Sarah', 'Connor', 'IT'),
(202, 'Kyle', 'Reese', 'Sales');

SELECT FirstName, LastName, Department FROM Employees
UNION -- Removes duplicates
SELECT FirstName, LastName, Department FROM NewEmployees;
Output of 'UNION' (duplicates removed):
FirstName  | LastName  | Department
-----------|-----------|------------
John       | Doe       | Sales
Jane       | Smith     | Marketing
Peter      | Jones     | Sales
Alice      | Williams  | IT
Bob        | Brown     | Marketing
Sarah      | Connor    | IT
Kyle       | Reese     | Sales
SELECT FirstName, LastName, Department FROM Employees
UNION ALL -- Includes duplicates
SELECT FirstName, LastName, Department FROM NewEmployees;
Output of 'UNION ALL' (all rows included):
FirstName  | LastName  | Department
-----------|-----------|------------
John       | Doe       | Sales
Jane       | Smith     | Marketing
Peter      | Jones     | Sales
Alice      | Williams  | IT
Bob        | Brown     | Marketing
Sarah      | Connor    | IT
Kyle       | Reese     | Sales
John       | Doe       | Sales
Jane       | Smith     | Marketing
Peter      | Jones     | Sales
Alice      | Williams  | IT
Bob        | Brown     | Marketing
-- INTERSECT (find common records - might need specific RDBMS syntax)
-- SELECT FirstName, LastName FROM Employees
-- INTERSECT
-- SELECT FirstName, LastName FROM NewEmployees;

-- EXCEPT (find records in first query not in second - might need specific RDBMS syntax)
-- SELECT FirstName, LastName FROM Employees
-- EXCEPT
-- SELECT FirstName, LastName FROM NewEmployees;

-- 3. Create an Index to improve query performance
-- This index will speed up queries that filter or Join on the LastName column of Employees table.
CREATE INDEX IX_Employees_LastName ON Employees (LastName);

-- Example of a query that would benefit from the index:
SELECT * FROM Employees WHERE LastName = 'Smith';
10

Common SQL Functions with Examples

This section provides practical examples of various SQL functions and their outputs.

10.1. Numeric Functions: ABS, ROUND, CEIL, FLOOR

-- ABS function: Returns the absolute (positive) value of a number.
SELECT ABS(-0.08) AS AbsoluteValue;
Output:
AbsoluteValue
-------------
0.08
-- ROUND function: Rounds a number to a specified number of decimal places.
SELECT
    ROUND(10.09) AS RoundToNearestIntPos,
    ROUND(-10.09) AS RoundToNearestIntNeg,
    ROUND(-10.44) AS RoundToNearestIntNeg2,
    ROUND(10.4) AS RoundToNearestIntPos2,
    ROUND(10000.55) AS RoundExample,
    ROUND(20000.56, 1) AS RoundToOneDecimal
FROM DUAL;
Output:
RoundToNearestIntPos | RoundToNearestIntNeg | RoundToNearestIntNeg2 | RoundToNearestIntPos2 | RoundExample | RoundToOneDecimal
---------------------|----------------------|-----------------------|-----------------------|--------------|------------------
11                   | -11                  | -10                   | 10                    | 10001        | 20000.6
-- CEIL function: Returns the smallest integer greater than or equal to the given number.
SELECT
    CEIL(10.09) AS CeilPos,
    CEIL(-10.09) AS CeilNeg
FROM DUAL;
Output:
CeilPos  | CeilNeg
---------|--------
11       | -10
-- FLOOR function: Returns the largest integer less than or equal to the given number.
SELECT
    FLOOR(10.09) AS FloorPos,
    FLOOR(-10.09) AS FloorNeg,
    FLOOR(20000.56) AS FloorExample
FROM DUAL;
Output:
FloorPos | FloorNeg | FloorExample
---------|----------|-------------
10       | -11      | 20000

10.2. String Functions: SUBSTRING, CHARINDEX, LENGTH, UPPER, LOWER, REPLACE, CONCAT

-- SUBSTRING (or SUBSTR): Extracts a substring from a string.
-- Syntax: SUBSTR(value, start_position, length)
-- Note: SQL indexing typically starts from 1.

-- Example with positive start position:
SELECT
    SUBSTR('abcdefghijklmnopqrstuvwxyz', 1, 4) AS FIRST4,
    SUBSTR('abcdefghijklmnopqrstuvwxyz', 2, 10) AS TEN_FROM_2,
    SUBSTR('abcdefghijklmnopqrstuvwxyz', 3, 5) AS ALL_FROM_3
FROM DUAL;
Output:
FIRST4 | TEN_FROM_2  | ALL_FROM_3
-------|-------------|------------
abcd   | bcdefghijk  | cdefghijklmnopqrstuvwxyz
-- Example with negative start position (counts from end):
SELECT
    SUBSTR('abcdefghijklmnopqrstuvwxyz', -1) AS LastChar,
    SUBSTR('abcdefghijklmnopqrstuvwxyz', -10) AS LastTenChars,
    SUBSTR('abcdefghijklmnopqrstuvwxyz', -20, 10) AS TenCharsFromTwentiethLast
FROM DUAL;
Output:
LastChar | LastTenChars | TenCharsFromTwentiethLast
---------|--------------|---------------------------
z        | qrstuvwxyz   | ghijklmnop
-- CHARINDEX (or INSTR/LOCATE): Returns the starting position of a substring within a string.
SELECT CHARINDEX('@', 'Rajkumar@example.com') AS AtPosition;
Output:
AtPosition
----------
9
-- LENGTH (or LEN): Returns the length of a string.
SELECT LENGTH('Hello World 123') AS StringLength;
Output:
StringLength
------------
15
-- UPPER and LOWER: Converts a string to uppercase or lowercase.
SELECT
    UPPER('HelloWorld') AS UpperCase,
    LOWER('HelloWorld') AS LowerCase
FROM DUAL;
Output:
UpperCase  | LowerCase
-----------|----------
HELLOWORLD | helloworld
-- REPLACE: Replaces all occurrences of a substring with another substring.
SELECT REPLACE('Mississippi', 'iss', 'X') AS ReplacedString;
Output:
ReplacedString
--------------
MXXippi
-- CONCAT: Concatenates two or more strings.
SELECT CONCAT('First', 'Last') AS FullName;
Output:
FullName
--------
FirstLast
-- CONCAT with multiple parts (SQL Server syntax, conceptual for compiler)
SELECT CONCAT(name, ' is from ', location) AS result FROM salesman;

10.3. Date/Time Functions: SYSDATE, SYSTIMESTAMP, ADD_MONTHS, MONTHS_BETWEEN

-- SYSDATE (or GETDATE()): Returns the current system date and time.
-- SYSTIMESTAMP: Returns the current system date and time with fractional seconds and timezone.
SELECT
    SYSDATE AS CurrentDate,
    SYSTIMESTAMP AS CurrentTimestamp
FROM DUAL;
Output:
CurrentDate      | CurrentTimestamp
-----------------|---------------------------
2025-07-11 11:05:00 | 2025-07-11 11:05:00.000 +05:30
-- ADD_MONTHS: Adds a specified number of months to a date.
SELECT
    RecordDate,
    ADD_MONTHS(RecordDate, 1) AS NextMonthDate
FROM Rise_Temperature WHERE ID = 1;
Output:
RecordDate  | NextMonthDate
------------|-------------
2015-01-01  | 2015-02-01
-- MONTHS_BETWEEN: Returns the number of months between two dates.
SELECT
    MONTHS_BETWEEN('2014-02-01', '2014-01-01') AS MonthDiff1,
    MONTHS_BETWEEN('2016-01-10', '2014-01-01') AS MonthDiff2,
    ABS(MONTHS_BETWEEN(ADD_MONTHS('2014-02-09', 3), '2015-03-09')) AS MonthsBetweenExample
FROM DUAL;
Output:
MonthDiff1 | MonthDiff2  | MonthsBetweenExample
-----------|-------------|---------------------
1          | 0.29032258  | 11.0

10.4. Conversion Functions: TO_CHAR, TO_DATE, TO_NUMBER

-- TO_CHAR (Number to String): Converts a number to a string with optional formatting.
SELECT
    TO_CHAR(1000) AS ORIG_NOFORMAT,
    TO_CHAR(1000.98) AS CONV_NOFORMAT,
    TO_CHAR(1000.98, '9999.99') AS FIXED_DIGITS,
    TO_CHAR(1000.98, '9,999.99') AS WITH_COMMA
FROM DUAL;
Output:
ORIG_NOFORMAT | CONV_NOFORMAT | FIXED_DIGITS | WITH_COMMA
--------------|---------------|--------------|------------
1000.98       | 1000.98       | 1000.98      | 1,000.98
-- TO_CHAR (Date to String): Converts a date to a string with optional formatting.
SELECT
    RecordDate AS RECORDDATE,
    TO_CHAR(RecordDate, 'MON') AS MONTH_ABBR,
    TO_CHAR(RecordDate, 'Month') AS FULL_MONTH,
    TO_CHAR(RecordDate, 'Dy') AS DAY_ABBR,
    TO_CHAR(RecordDate, 'Day') AS FULL_DAY,
    TO_CHAR(RecordDate, 'DD/MM/YYYY') AS INDIAN_FORMAT,
    TO_CHAR(RecordDate, 'MM/DD/YYYY') AS AMERICAN_FORMAT
FROM Rise_Temperature WHERE ID = 1;
Output:
RECORDDATE  | MONTH_ABBR | FULL_MONTH | DAY_ABBR | FULL_DAY | INDIAN_FORMAT | AMERICAN_FORMAT
------------|------------|------------|----------|----------|---------------|----------------
2015-01-01  | JAN        | January    | Sun      | Sunday   | 01/01/2015    | 01/01/15
-- TO_DATE: Converts a string to a date with a specified format.
SELECT
    '01-Jan-2014' AS DATE_STRING,
    TO_DATE('01-Jan-2014', 'DD-Mon-YYYY') AS ConvertedDate
FROM DUAL;
Output:
DATE_STRING | ConvertedDate
------------|---------------
01-Jan-2014 | 2014-01-01
-- TO_NUMBER (String to Number): Converts a string to a number with optional formatting.
SELECT TO_NUMBER('2,50,000.00', '999,999.99') AS ConvertedAmount;
Output:
ConvertedAmount
---------------
250000

10.5. Handling NULL Values: NVL / IFNULL / COALESCE

-- NVL (Oracle) / IFNULL (MySQL) / COALESCE (Standard SQL): Replaces NULL with a specified value.
SELECT
    Salary,
    IFNULL(Salary, 0.0) AS SalaryWithDefault,
    Bonus,
    IFNULL(Bonus, 0.0) AS BonusWithDefault
FROM Employees WHERE EmployeeID IN (1, 2);
Output:
Salary   | SalaryWithDefault | Bonus | BonusWithDefault
---------|-------------------|-------|------------------
50000.00 | 50000.00          | 1000.0| 1000.0
70000.00 | 70000.00          | NULL  | 0.0
30000.00 | 30000.00          | NULL  | 0.0
11

Conceptual DDL/DML and Advanced Features

The following section demonstrates more advanced SQL concepts, including DDL (Data Definition Language) and DML (Data Manipulation Language) operations, as well as SQL Server-specific features like user-defined functions and stored procedures.

Please note that the interactive compiler above "does not execute DDL or DML commands" and has limited support for complex SQL Server functions. These are provided for conceptual understanding.

11.1. FOR XML PATH (SQL Server Specific)

This is used to concatenate string values from multiple rows into a single string, often used for generating comma-separated lists or XML output.

-- SQL Server Specific: Concatenate Employee Names into a single string
-- SELECT EmployeeNames =
--     STUFF((SELECT ', ' + FirstName
--            FROM Employees
--            FOR XML PATH('')), 1, 2, '')

Explanation:

  • This query would typically return a single string like "John; Jane; Bob; Alice; Eve; Charlie; David; Michael Scott;". This functionality is not supported by the in-memory compiler.

11.2. User-Defined Functions (UDFs) - SQL Server Examples

UDFs encapsulate logic for reuse. These are conceptual as the compiler doesn't support 'CREATE FUNCTION'.

-- Function 1: Count number of books in each book category (conceptual)
-- ALTER FUNCTION ufn_NumberOfBooks_BookCategory() RETURNS TABLE
-- AS RETURN
-- (
--     SELECT ISNULL(CAST(BookCategory AS VARCHAR(20)), 'Total Books') AS BookCategory, COUNT(BookCategory) AS NumberOfBooks
--     FROM Books
--     GROUP BY ROLLUP(BookCategory)
-- );
-- Usage: SELECT * FROM ufn_NumberOfBooks_BookCategory();

-- Function 2: Retrieve books purchased using 'Online' payment mode (conceptual)
-- CREATE FUNCTION ufn_BooksPurchased_MediumOnline() RETURNS TABLE
-- AS RETURN
-- (
--     SELECT ISBN, BookName, AuthorName, Edition, BookCategory, Price
--     FROM Books
--     WHERE ISBN IN (SELECT DISTINCT ISBN FROM OnlineBooking WHERE PaymentMode = 'Online' GROUP BY ISBN)
-- );
-- Usage: SELECT * FROM ufn_BooksPurchased_MediumOnline();

-- Function 3: Find the quickest book delivery (conceptual)
-- CREATE FUNCTION ufn_QuickDelivery() RETURNS TABLE
-- AS RETURN
-- (
--     SELECT BookingId, UserId, ISBN, NumberOfBooksPurchased, BookingDate, DeliveryDate, DeliveryCharges, PaymentMode
--     FROM OnlineBooking
--     WHERE DATEDIFF(DATEYFEAR, BookingDate, DeliveryDate) = (SELECT MIN(DATEDIFF(DATEYEAR, BookingDate, DeliveryDate)) FROM OnlineBooking)
-- );
-- Usage: SELECT * FROM ufn_QuickDelivery();

-- Function 4: Find books that have not been purchased online (conceptual)
-- CREATE FUNCTION ufn_Books_NotPurchased() RETURNS TABLE
-- AS RETURN
-- (
--     SELECT ISBN, BookName, AuthorName, Edition, BookCategory, Price
--     FROM Books
--     WHERE ISBN NOT IN (SELECT DISTINCT ISBN FROM OnlineBooking)
-- );
-- Usage: SELECT * FROM ufn_Books_NotPurchased();

-- Function 5: Find books delivered in a specific month (conceptual)
-- CREATE FUNCTION ufn_BooksDelivered(@MonthName VARCHAR(20)) RETURNS TABLE
-- AS RETURN
-- (
--     SELECT BookingId, UserId, ISBN, NumberOfBooksPurchased, BookingDate, DeliveryDate, DeliveryCharges, PaymentMode
--     FROM OnlineBooking
--     WHERE DATENAME(MONTH, DeliveryDate) = @MonthName
-- );
-- Usage: SELECT * FROM ufn_BooksDelivered('February');

-- Function 6: Rank books based on ISBN (conceptual)
-- CREATE FUNCTION ufn_RankBooks() RETURNS TABLE
-- AS RETURN
-- (
--     SELECT RANK() OVER (PARTITION BY ISBN ORDER BY ISBN DESC) AS [Rank], BookName, AuthorName, Edition, BookCategory, Price
--     FROM Books
-- );
-- Usage: SELECT * FROM ufn_RankBooks();

-- Function 7: Validate a user based on their mobile number (conceptual)
-- CREATE FUNCTION ufn_ValidateUser(@MobileNumber BIGINT) RETURNS VARCHAR(20)
-- AS
-- BEGIN
--     DECLARE @UserName VARCHAR(20)
--     IF EXISTS (SELECT UserName FROM [User] WHERE MobileNumber = @MobileNumber)
--         BEGIN
--             SET @UserName = (SELECT UserName FROM [User] WHERE MobileNumber = @MobileNumber)
--         END
--     RETURN @UserName
-- END
-- Usage: SELECT ufn_ValidateUser(1234567890) AS UserName;

-- Function 8: Validate a user and password combination (conceptual)
-- CREATE FUNCTION ufn_ValidateUserandPassword(@UserName VARCHAR(20), @Password VARCHAR(20)) RETURNS INT
-- AS
-- BEGIN
--     IF EXISTS (SELECT UserName FROM [User] WHERE UserName = @UserName)
--         BEGIN
--             IF EXISTS (SELECT UserName FROM [User] WHERE UserName = @UserName AND [Password] = @Password)
--                 BEGIN
--                     RETURN 1
--                 END
--             ELSE
--                 RETURN 0
--         END
--     ELSE
--         RETURN -1
-- END
-- Usage: SELECT ufn_ValidateUserandPassword('TestUser', 'TestPass123') AS ValidUser;

Explanation:

  • User-defined functions allow you to encapsulate reusable logic. They can be scalar (returning a single value) or table-valued (returning a table). These examples illustrate various UDF types and their potential usage in a real database environment. The in-memory compiler does not support CREATE FUNCTION statements.

11.3. Stored Procedures - SQL Server Example

Stored procedures are pre-compiled SQL code blocks that can be executed multiple times. They are often used for complex operations, security, and performance.

-- Stored Procedure: Insert online booking information (conceptual)
-- DROP PROCEDURE IF EXISTS InsertOnlineBooking;
-- CREATE PROCEDURE InsertOnlineBooking
-- (
--     @UserId INT,
--     @BookName VARCHAR(50),
--     @NumberOfBooksPurchased INT,
--     @PaymentMode VARCHAR(20),
--     @BookingId INT OUTPUT
-- )
-- AS
-- BEGIN
--     BEGIN TRY
--         IF NOT EXISTS (SELECT UserId FROM [User] WHERE UserId = @UserId)
--             BEGIN
--                 RETURN -1
--             END
--         ELSE
--             BEGIN
--                 IF NOT EXISTS (SELECT BookName FROM Books WHERE BookName = @BookName)
--                     BEGIN
--                         RETURN -2
--                     END
--                 ELSE
--                     BEGIN
--                         IF (@NumberOfBooksPurchased >= 1)
--                             BEGIN
--                                 RETURN -3
--                             END
--                         ELSE
--                             BEGIN
--                                 IF NOT (@PaymentMode IN ('Online', 'Cash'))
--                                     BEGIN
--                                         RETURN -4
--                                     END
--                                 ELSE
--                                     BEGIN
--                                         DECLARE @BookingDate DATE, @DeliveryDate DATE, @DeliveryCharges FLOAT, @BillAmount FLOAT, @Price FLOAT, @ISBN INT
--                                         
--                                         SET @BookingId = 0
--                                         SET @ISBN = (SELECT ISBN FROM Books WHERE BookName = @BookName)
--                                         SET @BookingDate = CAST(GETDATE() AS DATE)
--                                         SET @DeliveryDate = CAST(GETDATE() + 3 AS DATE)
--                                         
--                                         IF ((SELECT BookCategory FROM Books WHERE BookName = @BookName) = 'Cook Books')
--                                             BEGIN
--                                                 SET @DeliveryCharges = 40
--                                             END
--                                         ELSE
--                                             BEGIN
--                                                 SET @DeliveryCharges = 0
--                                             END
--                                         
--                                         SET @Price = (SELECT Price FROM Books WHERE ISBN = (SELECT ISBN FROM Books WHERE BookName = @BookName))
--                                         
--                                         IF (@PaymentMode = 'Online')
--                                             BEGIN
--                                                 SET @Discount = 0.10
--                                             END
--                                         ELSE
--                                             BEGIN
--                                                 SET @Discount = 0
--                                             END
--                                         
--                                         SET @BillAmount = (SELECT @NumberOfBooksPurchased * @Price - @NumberOfBooksPurchased * @Price * @Discount + @DeliveryCharges)
--                                         
--                                         INSERT INTO OnlineBooking (UserId, ISBN, NumberOfBooksPurchased, BookingDate, BookingDate, DeliveryDate, DeliveryCharges, PaymentMode, @BillAmount)
--                                         VALUES (@UserId, @ISBN, @NumberOfBooksPurchased, @BookingDate, @DeliveryDate, @DeliveryCharges, @PaymentMode, @BillAmount)
--                                         
--                                         SELECT @BookingId = MAX(BookingId) FROM OnlineBooking
--                                         
--                                         RETURN 1
--                                     END
--                             END
--                     END
--             END
--     END TRY
--     BEGIN CATCH
--         SELECT ERROR_LINE() AS [Error Line], ERROR_MESSAGE() AS [Error Message], ERROR_NUMBER() AS [Error Number]
--         RETURN -5
--     END CATCH
-- END
-- Usage:
-- DECLARE @RET_INT, @Ld INT
-- EXEC @RET = InsertOnlineBooking 1002, 'Clean Slate', 2, 'Online', @Ld OUT
-- SELECT @RET, @Ld
-- SELECT * FROM OnlineBooking;

Explanation:

  • This stored procedure demonstrates how to insert data into an 'OnlineBooking' table with various validation checks (e.g., checking if the user exists, verifying booking details, calculating delivery charges and discounts). It also includes error handling using TRY...CATCH blocks. The in-memory compiler does not support CREATE PROCEDURE or DML operations like INSERT.
12

SQL Query Performance and Readability Tips

Writing efficient and readable SQL queries is crucial for maintaining databases and ensuring optimal application performance. Here are some best practices:

  • Use Descriptive Names: Choose clear and meaningful names for tables, columns, and aliases.
  • Format SELECT Lists: Explicitly list the columns you need in your 'SELECT' statement to reduce data transfer and improve readability.
  • Use Aliases: Employ aliases for table and column names, especially in joins, to make queries more concise and readable.
  • Break Down Complex Queries: Use Common Table Expressions (CTEs) or subqueries to break large queries into smaller, manageable parts.
  • Prefer 'JOIN's over Subqueries for Data Combination: 'JOIN's are generally more efficient for combining data from multiple tables than subqueries.
  • Filter Early with 'WHERE': Apply 'WHERE' clauses as early as possible to reduce the dataset size before further processing (e.g., joining, ordering).
  • Use 'GROUP BY' and Aggregate Functions: Effectively summarize data using 'COUNT', 'SUM', 'AVG', 'MAX', 'MIN'.
  • Sort Data with 'ORDER BY': Use 'ORDER BY' for consistent result presentation.
  • Filter Aggregated Data with 'HAVING': Use 'HAVING' to filter results after 'GROUP BY' operations.
  • Leverage Set Operators: Use 'UNION', 'UNION ALL', 'INTERSECT', 'EXCEPT' to combine or compare result sets.
  • Use 'CASE' Statements: Implement conditional logic within your 'SELECT' statements for dynamic output.
  • Utilize 'IN' and 'BETWEEN' Operators: For filtering based on lists or ranges of values.
  • Use 'LIKE' for Pattern Matching: Efficiently search for patterns in text data.
  • Implement Indexes: Create indexes on columns frequently used in 'WHERE' clauses, 'JOIN' conditions, or 'ORDER BY' clauses to speed up data retrieval.
  • Avoid Functions in 'WHERE' Clauses: Applying functions to columns in 'WHERE' clauses can prevent the database from using indexes, leading to full table scans.
  • Modularize with Stored Procedures and Functions: Encapsulate complex logic for reusability and maintainability.
  • Analyze Query Performance: Use tools like 'EXPLAIN' (or 'EXPLAIN PLAN' in Oracle, 'EXECUTION PLAN' in PostgreSQL) to understand how the database executes your query and identify bottlenecks.
13

Database Concepts and Types

A quick overview of fundamental database concepts and different types of database systems.

  • Data: Raw facts and figures.
  • Information: Processed data that provides meaning.
  • Knowledge: Synthesis of data and information to answer "how" and make decisions.
  • Database: A shared collection of logically related data designed to meet an organization's information needs.
  • DBMS (Database Management System): Software that enables users to define, create, maintain, and control access to the database.
  • Data Integrity: Maintaining accuracy and consistency of data (Entity, Domain, Referential integrity).
  • Entity Integrity: Each table must have a unique identifier (Primary Key) that cannot be NULL.
  • Domain Integrity: All attributes must have a defined domain (data types, 'CHECK' constraints).
  • Referential Integrity: Ensures relationships between tables are maintained (Foreign Keys).

Types of Database Systems (by Structure):

  • Hierarchical Database: Data organized in a tree-like structure (parent-child relationships).
  • Network Database: Data organized as a graph, allowing more complex relationships than hierarchical.
  • Relational Database: Data stored in tables (relations) with rows (tuples) and columns (attributes). Uses SQL.
  • NoSQL Database: Non-relational databases, flexible schema, often used for large-scale distributed data (e.g., key-value, document, graph, column-family).

Key Concepts:

  • Attribute: A named column of a relation.
  • Tuple: A row in a relation.
  • Cardinality: Number of rows in a relation.
  • Degree: Number of attributes (columns) in a relation.
  • NULL: Represents an unknown or inapplicable value.
  • Domain: Set of allowable values for an attribute.
  • Candidate Key: Minimal set of columns that can uniquely identify a row.
  • Primary Key: The chosen candidate key to uniquely identify a row, cannot be NULL.
  • Composite Primary Key: Two or more columns together forming a primary key.
  • Foreign Key: Columns in a child table that reference a primary/unique key in a parent table, establishing a relationship.
14

Additional Interview-Style Questions & Solutions

Question: What is the use of the 'OFFSET' command?

Solution:

  • The 'OFFSET' command is used in SQL to skip a specified number of rows from the beginning of a result set. It is commonly used with the 'LIMIT' or 'FETCH NEXT' clause to implement pagination, allowing you to retrieve a subset of rows from a larger result set. This is particularly useful for displaying data in pages on a web application.
-- Example: Retrieve the 2nd employee (skipping the first)
SELECT EmployeeName, Salary FROM Employees
ORDER BY EmployeeName
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY;
Output:
EmployeeName | Salary
-------------|----------
Alice        | 62000.00

Question: Can 'HAVING' be used without an aggregate function?

Solution:

  • Yes. 'HAVING' can technically be used without an aggregate function, but it's generally not recommended as it behaves identically to a 'WHERE' clause in such cases. The primary purpose of 'HAVING' is to filter groups based on conditions applied to aggregate values, whereas 'WHERE' filters individual rows before grouping.
-- Example: Using HAVING without an aggregate (behaves like WHERE)
SELECT EmployeeName, Department
FROM Employees
HAVING Department = 'IT';
Output:
EmployeeName | Department
-------------|------------
Jane         | IT
Alice        | IT
Eve          | IT

Question: Query for Names with Specific Length and Starting/Ending Characters (Conceptual)

Solution:

  • This query demonstrates filtering based on string length and patterns using 'LENGTH' and 'LIKE'. (Assumes a 'student' table with a 'name' column).
-- Conceptual query. Assumes a 'student' table with 'name' column.
-- SELECT name
-- FROM student
-- WHERE LENGTH(name) = 10 AND LOWER(name) LIKE 'kk%';

Question: What is the primary purpose of an index in a database?

Solution:

  • The primary purpose of an index in a database is to "facilitate faster retrieval of data". It creates a data structure (like a B-tree) that allows the database system to quickly locate rows without scanning the entire table. This significantly improves the performance of 'SELECT' queries, especially on large tables, at the cost of increased storage space and slower 'INSERT', 'UPDATE', and 'DELETE' operations (due to index maintenance).

Question: Differentiate between Clustered and Non-Clustered Indexes

Solution:

  • Clustered Index:
    • Determines the physical order of data rows in the table.
    • A table can have "only one" clustered index.
    • Often created automatically on the Primary Key.
    • Data is stored in the leaf nodes of the index itself.
    • Excellent for range scans and retrieving large sets of data.
  • Non-Clustered Index:
    • Does not affect the physical order of data rows.
    • A table can have "multiple" non-clustered indexes (up to 999 in SQL Server).
    • Stores pointers to the actual data rows (or to the clustered index).
    • Good for exact lookups and smaller data retrievals.

Question: What are the disadvantages of using indexes?

Solution:

  • While indexes significantly boost 'SELECT' query performance, they come with trade-offs:
  • Increased Storage Space: Indexes require additional disk space.
  • Slower DML Operations: 'INSERT', 'UPDATE', and 'DELETE' operations become slower because the database must also update the index structures along with the actual data.
  • Maintenance Overhead: Indexes need to be rebuilt or reorganized periodically to maintain optimal performance, especially after significant data modifications.
  • Complexity: Over-indexing or poorly designed indexes can sometimes hurt performance rather than help, requiring careful monitoring and tuning.

Question: How to find duplicates in 'DUPLICATE_CHECK' table?

-- Setup for DUPLICATE_CHECK (already in in-memory DB)
-- CREATE TABLE DUPLICATE_CHECK(
-- ID INT,
-- NAME NVARCHAR(30),
-- AGE INT);
-- INSERT INTO DUPLICATE_CHECK VALUES (1,'KAPIL',20);
-- INSERT INTO DUPLICATE_CHECK VALUES (1,'KAPIL',21);
-- INSERT INTO DUPLICATE_CHECK VALUES (2,'ABC',22);
-- INSERT INTO DUPLICATE_CHECK VALUES (3,'DEF',24);
-- INSERT INTO DUPLICATE_CHECK VALUES (4,'GHI',29);
SELECT * FROM DUPLICATE_CHECK;
Output of 'select * from DUPLICATE_CHECK':
ID | NAME  | AGE
---|-------|----
1  | KAPIL | 20
1  | KAPIL | 21
2  | ABC   | 22
3  | DEF   | 24
4  | GHI   | 29
SELECT ID, NAME, COUNT(*) AS Frequency
FROM DUPLICATE_CHECK
GROUP BY ID, NAME
HAVING COUNT(*) > 1;
Final Output:
ID | NAME  | Frequency
---|-------|----------
1  | KAPIL | 2

Question: Explain 'DELETE' vs 'TRUNCATE'

Solution:

  • Both 'DELETE' and 'TRUNCATE' are used to remove rows from a table, but they differ significantly:
  • 'DELETE' (DML - Data Manipulation Language):
    • Removes rows one by one.
    • Can include a 'WHERE' clause to remove specific rows.
    • Generates undo logs, allowing you to 'ROLLBACK' the operation.
    • Fires triggers (if defined on the table).
    • Slower for large tables as it logs each deleted row.
    • Resets auto-incrementing IDs only if all rows are deleted and the table is empty.
  • 'TRUNCATE' (DDL - Data Definition Language):
    • Removes all rows from a table by deallocating the data pages.
    • Cannot include a 'WHERE' clause; it removes "all" rows.
    • Cannot be 'ROLLED BACK' (it's a DDL operation, implicitly commits).
    • Does not fire triggers.
    • Much faster for large tables as it's a minimal logging operation.
    • Resets auto-incrementing IDs to their starting value.

Question: What is the difference between 'COUNT(*)' and 'COUNT(ColName)'?

Solution:

  • 'COUNT(*)': Counts all rows in a table or a result set, including rows that contain 'NULL' values in any column. It essentially counts the number of records.
  • 'COUNT(ColName)': Counts the number of non-'NULL' values in the specified column ('ColName'). It explicitly excludes rows where the 'ColName' has a 'NULL' value.
-- Example using Employees table with some NULLs in Bonus
SELECT
    COUNT(*) AS TotalEmployees,
    COUNT(Bonus) AS EmployeesWithBonus
FROM Employees;
Output:
TotalEmployees | EmployeesWithBonus
---------------|-------------------
8              | 5

Question: How do we create a table with all the employee Names and Manager Names? (Conceptual)

Solution:

  • To create a new table containing employee names and their manager names, you would typically use a 'CREATE TABLE AS SELECT' statement combined with a self-join on the 'Employees' table. This creates a new table based on the result of a 'SELECT' query.
-- Conceptual DDL: This will create a new table 'EmployeeManager'
-- CREATE TABLE EmployeeManager AS
-- SELECT
--     e.EmployeeName AS Employee,
--     m.EmployeeName AS Manager
-- FROM
--     Employees e
-- LEFT JOIN
--     Employees m ON e.ManagerID = m.EmployeeID;

Question: Display department-wise average salaries sorted in descending order.

SELECT Department, AVG(Salary) AS AvgSalary
FROM Employees
GROUP BY Department
ORDER BY AvgSalary DESC;
Final Output:
Department  | AvgSalary
------------|----------
Management  | 90000.00
IT          | 66000.00
Marketing   | 65000.00
Sales       | 65000.00
HR          | 52000.00
Finance     | 54000.00

Question: Display departments with more than 1 employee.

SELECT Department, COUNT(*) AS EmployeeCount
FROM Employees
GROUP BY Department
HAVING COUNT(*) > 1;
Final Output:
Department  | EmployeeCount
------------|---------------
Sales       | 2
Marketing   | 2
IT          | 2
HR          | 2
Finance     | 2

Question: Show department, minimum salary, and maximum salary only if the minimum salary is less than 5000 and maximum salary is more than 15000.

SELECT Department, MIN(Salary) AS MinSalary, MAX(Salary) AS MaxSalary
FROM Employees
GROUP BY Department
HAVING MIN(Salary) < 5000 AND MAX(Salary) > 15000;
Final Output:
Department  | MinSalary | MaxSalary
------------|-----------|----------
HR          | 50000.00  | 75000.00
IT          | 55000.00  | 62000.00
Finance     | 48000.00  | 60000.00
Sales       | 60000.00  | 70000.00
Marketing   | 62000.00  | 68000.00