InterviewPitch
SQL interview questions

SQL Interview Questions with Answers

Most Asked SQL Interview Questions for Database Engineers

100+ QuestionsDetailed AnswersCode ExamplesUpdated for 2026

Introduction

SQL is the backbone of data management – a powerful language for querying, updating, and administering relational databases. This page brings together the most frequently asked SQL interview questions, from basic SELECT statements and joins to advanced window functions, CTEs, performance tuning, and JSON handling – essential for any backend, data, or full‑stack developer.

Why SQL?

  • Universal standard for relational databases
  • Essential for back‑end and full‑stack development
  • Data manipulation, definition, and control in one language
  • Powerful analytical capabilities with window functions and aggregations
  • Critical for data engineering and business intelligence
  • High demand in every technology company

Most Asked SQL Interview Questions

Beginner
1. What is SQL?

SQL (Structured Query Language) is a domain-specific language used for managing and manipulating relational databases.

  • Data definition: CREATE, ALTER, DROP
  • Data manipulation: SELECT, INSERT, UPDATE, DELETE
  • Data control: GRANT, REVOKE
  • Transaction control: COMMIT, ROLLBACK, SAVEPOINT
  • Relational: Tables, relationships, constraints
sql
-- Hello World in SQL
SELECT 'Hello, World!' AS greeting;
Beginner
2. How to declare variables in SQL?

SQL variables can be user-defined, system, or local variables within stored procedures.

  • User variables: @variable_name
  • System variables: @@variable_name
  • Local variables: DECLARE var_name
  • Assignment: SET @var = value
  • SELECT INTO: SELECT column INTO @var
sql
-- Variables in SQL
-- User-defined variables
SET @mutableVar = 'Hello';
SET @immutableVar = 'World';

-- System variables
SELECT @@version;
SELECT @@autocommit;

-- Local variables in stored procedures
DELIMITER //
CREATE PROCEDURE demoVariables()
BEGIN
    DECLARE localVar VARCHAR(20) DEFAULT 'Local';
    SELECT localVar;
END//
DELIMITER ;

-- Display
SELECT @mutableVar;
SELECT @immutableVar;
Beginner
3. What are the data types in SQL?

SQL provides various data types including numeric, string, date/time, JSON, and spatial types.

  • Numeric: INT, TINYINT, DECIMAL, FLOAT, DOUBLE
  • String: CHAR, VARCHAR, TEXT, BLOB
  • Date/Time: DATE, DATETIME, TIMESTAMP, TIME, YEAR
  • JSON: JSON data type (5.7+)
  • Spatial: POINT, LINESTRING, POLYGON
  • Enum/Set: ENUM, SET
sql
-- Data Types in SQL
-- Numeric types
CREATE TABLE data_types (
    int_col INT,
    tinyint_col TINYINT,
    smallint_col SMALLINT,
    mediumint_col MEDIUMINT,
    bigint_col BIGINT,
    decimal_col DECIMAL(10,2),
    float_col FLOAT,
    double_col DOUBLE,
    
    -- String types
    char_col CHAR(10),
    varchar_col VARCHAR(100),
    text_col TEXT,
    blob_col BLOB,
    
    -- Date and time
    date_col DATE,
    datetime_col DATETIME,
    timestamp_col TIMESTAMP,
    time_col TIME,
    year_col YEAR,
    
    -- Boolean (TINYINT)
    is_active BOOLEAN,
    
    -- JSON
    json_col JSON,
    
    -- Enum
    status ENUM('active', 'inactive', 'pending')
);

-- Type checking
SELECT 
    COLUMN_NAME,
    DATA_TYPE,
    CHARACTER_MAXIMUM_LENGTH
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'data_types';
Beginner
4. How to define functions in SQL?

SQL functions are stored routines that return a single value and can be used in SQL statements.

  • CREATE FUNCTION: CREATE FUNCTION name(params) RETURNS type
  • DETERMINISTIC: Returns same result for same inputs
  • READS SQL DATA: Indicates data reading
  • Return value: Must return a value
  • Usage: SELECT function_name()
sql
-- Functions in SQL
-- Basic function
DELIMITER //
CREATE FUNCTION add_numbers(a INT, b INT)
RETURNS INT
DETERMINISTIC
BEGIN
    RETURN a + b;
END//
DELIMITER ;

-- Function with default parameters
DELIMITER //
CREATE FUNCTION greet(name VARCHAR(100))
RETURNS VARCHAR(200)
DETERMINISTIC
BEGIN
    IF name IS NULL THEN
        SET name = 'Guest';
    END IF;
    RETURN CONCAT('Hello, ', name, '!');
END//
DELIMITER ;

-- Function with multiple statements
DELIMITER //
CREATE FUNCTION divide_numbers(a INT, b INT)
RETURNS VARCHAR(100)
DETERMINISTIC
BEGIN
    DECLARE result VARCHAR(100);
    IF b = 0 THEN
        SET result = 'Division by zero';
    ELSE
        SET result = CONCAT('Quotient: ', a DIV b, ', Remainder: ', a MOD b);
    END IF;
    RETURN result;
END//
DELIMITER ;

-- Usage
SELECT add_numbers(5, 3);
SELECT greet('Alice');
SELECT divide_numbers(10, 3);
Beginner
5. What are arrays in SQL?

SQL doesn't have built-in arrays. Alternatives include JSON arrays, temporary tables, or multiple columns.

  • JSON arrays: JSON_ARRAY(), JSON_EXTRACT()
  • Temporary tables: Session-specific tables
  • Separate tables: Normalized relationships
  • JSON functions: JSON_LENGTH(), JSON_CONTAINS()
  • Full-text search: For text arrays
sql
-- Arrays in SQL
-- SQL doesn't have arrays, but we can use JSON or temporary tables

-- Using JSON arrays
CREATE TABLE json_demo (
    id INT PRIMARY KEY,
    numbers JSON
);

INSERT INTO json_demo VALUES (1, '[1, 2, 3, 4, 5]');
INSERT INTO json_demo VALUES (2, '[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]');

-- Access array elements
SELECT 
    id,
    JSON_EXTRACT(numbers, '$[2]') AS third_element,
    JSON_LENGTH(numbers) AS array_length
FROM json_demo;

-- Using temporary table as array
CREATE TEMPORARY TABLE temp_array (
    id INT AUTO_INCREMENT PRIMARY KEY,
    value INT
);

INSERT INTO temp_array (value) VALUES (1), (2), (3), (4), (5);

-- Iterate through array
SELECT value FROM temp_array ORDER BY id;

-- JSON array functions
SELECT 
    JSON_ARRAY(1, 2, 3, 4, 5) AS numbers,
    JSON_ARRAY_APPEND('[1,2,3]', '$', 4) AS appended,
    JSON_ARRAY_INSERT('[1,2,3]', '$[1]', 99) AS inserted,
    JSON_REMOVE('[1,2,3,4]', '$[2]') AS removed;
Beginner
6. What are collections in SQL?

SQL uses tables as collections. Rows are documents/records, and columns are fields.

  • Tables: Collection of rows
  • Rows: Individual records
  • Columns: Fields/attributes
  • JSON collections: JSON data type for flexible schemas
  • Views: Virtual collections
sql
-- Collections in SQL
-- Tables as collections
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    age INT,
    city VARCHAR(100)
);

-- Insert documents (rows)
INSERT INTO users (name, age, city) VALUES 
    ('Alice', 25, 'NYC'),
    ('Bob', 30, 'LA'),
    ('Charlie', 35, 'Chicago');

-- Query all
SELECT * FROM users;

-- Query with filter
SELECT * FROM users WHERE age > 25;

-- Update
UPDATE users SET age = 26 WHERE name = 'Alice';

-- Delete
DELETE FROM users WHERE name = 'Bob';

-- Count
SELECT COUNT(*) FROM users WHERE age > 25;

-- JSON collections
CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    customer_id INT,
    items JSON,
    total DECIMAL(10,2)
);

INSERT INTO orders (customer_id, items, total) VALUES 
    (1, '[{"product": "A", "qty": 2}, {"product": "B", "qty": 1}]', 30.00);

SELECT 
    id,
    JSON_EXTRACT(items, '$[0].product') AS first_product
FROM orders;
Beginner
7. What are data classes in SQL?

Tables serve as data classes in SQL, defining the structure of records with columns and constraints.

  • Table definition: CREATE TABLE
  • Constraints: PRIMARY KEY, FOREIGN KEY, UNIQUE, CHECK
  • Default values: DEFAULT clause
  • Auto-increment: AUTO_INCREMENT
  • Views: Virtual tables
sql
-- Data Classes (Tables as Objects)
-- Creating a table as a data class
CREATE TABLE person (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    age INT CHECK (age >= 0),
    city VARCHAR(100) DEFAULT 'Unknown',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Insert data
INSERT INTO person (name, age, city) VALUES 
    ('Alice', 25, 'NYC'),
    ('Bob', 30, 'LA');

-- Query
SELECT * FROM person WHERE id = 1;

-- Update
UPDATE person SET age = 26 WHERE id = 1;

-- Delete
DELETE FROM person WHERE id = 2;

-- Copy
CREATE TABLE person_backup AS SELECT * FROM person;

-- Struct-like views
CREATE VIEW person_view AS 
SELECT 
    id,
    name,
    age,
    city,
    CONCAT(name, ' (', age, ')') AS display_name
FROM person;
Beginner
8. What is schema validation in SQL?

Schema validation enforces data integrity through constraints and data types. SQL 8.0+ supports JSON schema validation.

  • Constraints: NOT NULL, UNIQUE, CHECK, FOREIGN KEY
  • Data types: Define allowed data formats
  • JSON validation: JSON_SCHEMA_VALID()
  • Triggers: Custom validation logic
  • Stored procedures: Complex validation
sql
-- Schema Validation in SQL
-- MySQL 8.0+ supports JSON schema validation

-- Create table with JSON validation
CREATE TABLE validated_users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255) NOT NULL,
    age INT CHECK (age >= 0 AND age <= 150),
    status ENUM('active', 'inactive', 'pending') DEFAULT 'pending',
    metadata JSON,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    -- Unique constraint
    CONSTRAINT unique_email UNIQUE (email)
);

-- Check constraints
ALTER TABLE validated_users 
ADD CONSTRAINT check_age_positive 
CHECK (age >= 0);

-- JSON schema validation (MySQL 8.0+)
ALTER TABLE validated_users
ADD CONSTRAINT valid_metadata
CHECK (JSON_SCHEMA_VALID(
    '{
        "type": "object",
        "properties": {
            "department": {"type": "string"},
            "role": {"type": "string"}
        },
        "required": ["department"]
    }',
    metadata
));

-- Test validation
INSERT INTO validated_users (name, email, age, metadata) 
VALUES ('Alice', 'alice@example.com', 25, '{"department": "IT"}');

-- This will fail validation
INSERT INTO validated_users (name, email, age, metadata) 
VALUES ('Bob', 'bob@example.com', 30, '{"role": "admin"}');
Beginner
9. What is null safety in SQL?

SQL uses NULL to represent missing data. Various functions and operators handle NULL values safely.

  • IS NULL: Check for NULL values
  • COALESCE: First non-NULL value
  • IFNULL: SQL-specific NULL handling
  • NULLIF: Returns NULL if values equal
  • NOT NULL: Constraint for non-null columns
sql
-- Null Safety in SQL
-- Handling NULL values

-- NULL vs NOT NULL
CREATE TABLE null_demo (
    id INT PRIMARY KEY,
    nullable_field VARCHAR(100) NULL,
    non_nullable_field VARCHAR(100) NOT NULL
);

-- Insert NULL
INSERT INTO null_demo (id, nullable_field, non_nullable_field) 
VALUES (1, NULL, 'value');

-- Query NULL
SELECT * FROM null_demo WHERE nullable_field IS NULL;
SELECT * FROM null_demo WHERE nullable_field IS NOT NULL;

-- COALESCE - first non-NULL
SELECT 
    COALESCE(nullable_field, 'default') AS with_default
FROM null_demo;

-- IFNULL - MySQL specific
SELECT IFNULL(nullable_field, 'default') AS with_default FROM null_demo;

-- NULLIF - returns NULL if equal
SELECT NULLIF(1, 1); -- Returns NULL
SELECT NULLIF(1, 2); -- Returns 1

-- ISNULL function
SELECT ISNULL(nullable_field) FROM null_demo;

-- Handling NULL in aggregates
SELECT 
    COUNT(*),          -- Counts all rows
    COUNT(column),     -- Counts non-NULL values
    AVG(column),       -- Ignores NULL values
    SUM(column)        -- Ignores NULL values
FROM null_demo;

-- Using DEFAULT
INSERT INTO null_demo (id, nullable_field) 
VALUES (2, DEFAULT(non_nullable_field));
Beginner
10. What are control flow statements in SQL?

SQL provides IF, CASE, WHILE, REPEAT, and LOOP statements for control flow in stored procedures.

  • IF: Conditional execution
  • CASE: Switch-like conditional
  • WHILE: Loop with condition
  • REPEAT: Loop with until condition
  • LOOP: Infinite loop with LEAVE
sql
-- Control Flow in SQL
-- IF statement in stored procedures
DELIMITER //
CREATE PROCEDURE check_age(IN age INT)
BEGIN
    IF age < 18 THEN
        SELECT 'Minor' AS status;
    ELSE
        SELECT 'Adult' AS status;
    END IF;
END//
DELIMITER ;

-- IF function (in SELECT)
SELECT 
    name,
    age,
    IF(age < 18, 'Minor', 'Adult') AS status
FROM users;

-- CASE expression
SELECT 
    name,
    age,
    CASE 
        WHEN age < 18 THEN 'Minor'
        WHEN age < 65 THEN 'Adult'
        ELSE 'Senior'
    END AS category
FROM users;

-- CASE with simple values
SELECT 
    name,
    status,
    CASE status
        WHEN 'active' THEN 'Active'
        WHEN 'inactive' THEN 'Inactive'
        ELSE 'Unknown'
    END AS status_description
FROM users;

-- WHILE loop
DELIMITER //
CREATE PROCEDURE while_demo()
BEGIN
    DECLARE i INT DEFAULT 1;
    WHILE i <= 5 DO
        SELECT i;
        SET i = i + 1;
    END WHILE;
END//
DELIMITER ;

-- REPEAT loop
DELIMITER //
CREATE PROCEDURE repeat_demo()
BEGIN
    DECLARE i INT DEFAULT 1;
    REPEAT
        SELECT i;
        SET i = i + 1;
    UNTIL i > 5
    END REPEAT;
END//
DELIMITER ;

-- LOOP with LEAVE
DELIMITER //
CREATE PROCEDURE loop_demo()
BEGIN
    DECLARE i INT DEFAULT 1;
    loop_label: LOOP
        SELECT i;
        SET i = i + 1;
        IF i > 5 THEN
            LEAVE loop_label;
        END IF;
    END LOOP;
END//
DELIMITER ;
Beginner
11. What is inheritance in SQL?

SQL doesn't support inheritance directly. Patterns like Single Table Inheritance, Class Table Inheritance, and Polymorphic Associations are used.

  • Single Table Inheritance: One table with type column
  • Class Table Inheritance: Separate tables with foreign keys
  • Concrete Table Inheritance: Separate tables for each type
  • Polymorphic Associations: Type and ID columns
  • Views: Combine inherited data
sql
-- Inheritance in SQL
-- SQL doesn't support inheritance, but patterns exist

-- Single Table Inheritance
CREATE TABLE animals (
    id INT PRIMARY KEY AUTO_INCREMENT,
    type VARCHAR(50),
    name VARCHAR(100),
    sound VARCHAR(100),
    breed VARCHAR(100),  -- For dogs
    color VARCHAR(50)    -- For cats
);

INSERT INTO animals (type, name, sound, breed) VALUES 
    ('Dog', 'Rex', 'Woof!', 'German Shepherd');

INSERT INTO animals (type, name, sound, color) VALUES 
    ('Cat', 'Whiskers', 'Meow!', 'Black');

-- Class Table Inheritance
CREATE TABLE persons (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    email VARCHAR(255)
);

CREATE TABLE employees (
    person_id INT PRIMARY KEY,
    employee_id VARCHAR(50),
    department VARCHAR(100),
    FOREIGN KEY (person_id) REFERENCES persons(id)
);

CREATE TABLE customers (
    person_id INT PRIMARY KEY,
    customer_id VARCHAR(50),
    loyalty_points INT,
    FOREIGN KEY (person_id) REFERENCES persons(id)
);

-- Concrete Table Inheritance
CREATE TABLE employees_detail (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    employee_id VARCHAR(50),
    department VARCHAR(100)
);

CREATE TABLE customers_detail (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    customer_id VARCHAR(50),
    loyalty_points INT
);

-- Polymorphic associations
CREATE TABLE comments (
    id INT PRIMARY KEY AUTO_INCREMENT,
    content TEXT,
    commentable_type VARCHAR(50),
    commentable_id INT
);
Beginner
12. What are properties (columns) in SQL?

Columns define the properties of records in a table. They have data types, constraints, and attributes.

  • Data types: Define what data can be stored
  • Constraints: PRIMARY KEY, NOT NULL, UNIQUE, CHECK
  • Default values: DEFAULT clause
  • Generated columns: Computed from other columns
  • Indexes: Improve query performance
sql
-- Properties (Columns) in SQL
-- Table with various column properties
CREATE TABLE products (
    -- Primary key
    id INT PRIMARY KEY AUTO_INCREMENT,
    
    -- NOT NULL constraint
    name VARCHAR(200) NOT NULL,
    
    -- UNIQUE constraint
    sku VARCHAR(50) UNIQUE NOT NULL,
    
    -- Default value
    price DECIMAL(10,2) DEFAULT 0.00,
    
    -- Check constraint
    quantity INT CHECK (quantity >= 0),
    
    -- Foreign key
    category_id INT,
    
    -- Timestamps with automatic updates
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    
    -- Index
    INDEX idx_name (name),
    
    -- Composite index
    INDEX idx_category_price (category_id, price),
    
    -- Full-text index
    FULLTEXT INDEX ft_description (description),
    
    -- Foreign key constraint
    FOREIGN KEY (category_id) REFERENCES categories(id)
        ON DELETE SET NULL
        ON UPDATE CASCADE
);

-- Computed columns (generated columns)
CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    quantity INT NOT NULL,
    unit_price DECIMAL(10,2) NOT NULL,
    total_price DECIMAL(10,2) GENERATED ALWAYS AS (quantity * unit_price) STORED
);

-- Virtual generated column
CREATE TABLE sales (
    id INT PRIMARY KEY AUTO_INCREMENT,
    amount DECIMAL(10,2) NOT NULL,
    tax_rate DECIMAL(5,2) NOT NULL,
    tax_amount DECIMAL(10,2) GENERATED ALWAYS AS (amount * tax_rate / 100) VIRTUAL
);
Intermediate
13. What are stored procedures in SQL?

Stored procedures are saved SQL code that can be called multiple times. They can have parameters and return result sets.

  • CREATE PROCEDURE: Define procedure
  • Parameters: IN, OUT, INOUT
  • Transaction support: COMMIT, ROLLBACK
  • Error handling: DECLARE ... HANDLER
  • CALL: Execute procedure
sql
-- Stored Procedures in SQL
-- Basic stored procedure
DELIMITER //
CREATE PROCEDURE get_users(IN city_param VARCHAR(100))
BEGIN
    SELECT * FROM users WHERE city = city_param;
END//
DELIMITER ;

-- Stored procedure with multiple parameters
DELIMITER //
CREATE PROCEDURE get_users_by_age(
    IN min_age INT,
    IN max_age INT
)
BEGIN
    SELECT * FROM users WHERE age BETWEEN min_age AND max_age;
END//
DELIMITER ;

-- Stored procedure with OUT parameters
DELIMITER //
CREATE PROCEDURE get_user_count(
    IN city_param VARCHAR(100),
    OUT user_count INT
)
BEGIN
    SELECT COUNT(*) INTO user_count 
    FROM users 
    WHERE city = city_param;
END//
DELIMITER ;

-- Stored procedure with INOUT parameters
DELIMITER //
CREATE PROCEDURE increment_age(
    INOUT age_param INT,
    IN increment INT
)
BEGIN
    SET age_param = age_param + increment;
END//
DELIMITER ;

-- Stored procedure with transaction
DELIMITER //
CREATE PROCEDURE transfer_funds(
    IN from_account INT,
    IN to_account INT,
    IN amount DECIMAL(10,2)
)
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        SELECT 'Transaction failed' AS message;
    END;
    
    START TRANSACTION;
    
    UPDATE accounts SET balance = balance - amount WHERE id = from_account;
    UPDATE accounts SET balance = balance + amount WHERE id = to_account;
    
    COMMIT;
    SELECT 'Transaction successful' AS message;
END//
DELIMITER ;

-- Call procedures
CALL get_users('NYC');
CALL get_users_by_age(18, 30);
CALL get_user_count('NYC', @count);
SELECT @count;
Intermediate
14. How to handle exceptions in SQL?

SQL handles exceptions using DECLARE ... HANDLER statements, SIGNAL for custom errors, and GET DIAGNOSTICS for error details.

  • DECLARE HANDLER: Handle specific errors
  • SIGNAL: Raise custom errors
  • GET DIAGNOSTICS: Get error details
  • EXIT HANDLER: Exit on error
  • CONTINUE HANDLER: Continue after error
sql
-- Exception Handling in SQL
-- MySQL 5.5+: DECLARE ... HANDLER

-- Basic exception handling
DELIMITER //
CREATE PROCEDURE safe_divide(
    IN numerator INT,
    IN denominator INT
)
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        SELECT 'Error occurred' AS result;
    END;
    
    SELECT numerator / denominator AS result;
END//
DELIMITER ;

-- Specific error handling
DELIMITER //
CREATE PROCEDURE safe_insert(
    IN name VARCHAR(100),
    IN email VARCHAR(255)
)
BEGIN
    DECLARE EXIT HANDLER FOR 1062  -- Duplicate entry error
    BEGIN
        SELECT 'Email already exists' AS error;
    END;
    
    INSERT INTO users (name, email) VALUES (name, email);
    SELECT 'User inserted successfully' AS result;
END//
DELIMITER ;

-- Custom error messages
DELIMITER //
CREATE PROCEDURE validate_age(
    IN age INT
)
BEGIN
    IF age < 0 OR age > 150 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Invalid age: Age must be between 0 and 150';
    END IF;
    
    SELECT 'Age is valid' AS result;
END//
DELIMITER ;

-- Using GET DIAGNOSTICS (MySQL 5.6+)
DELIMITER //
CREATE PROCEDURE get_error_info()
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        GET DIAGNOSTICS CONDITION 1
            @sqlstate = RETURNED_SQLSTATE,
            @errno = MYSQL_ERRNO,
            @text = MESSAGE_TEXT;
        SELECT @sqlstate, @errno, @text;
    END;
    
    -- This will cause an error
    INSERT INTO nonexistent_table VALUES (1);
END//
DELIMITER ;
Intermediate
15. What are functions in SQL?

SQL functions are stored routines that return a single value. They can be used in SELECT, WHERE, and other SQL clauses.

  • CREATE FUNCTION: Define function
  • RETURNS: Specify return type
  • DETERMINISTIC: Same inputs, same output
  • READS SQL DATA: Indicates data reading
  • Usage: SELECT function_name()
sql
-- Functions in SQL (UDF)
-- User-defined functions

-- Simple function
DELIMITER //
CREATE FUNCTION square(x INT)
RETURNS INT
DETERMINISTIC
BEGIN
    RETURN x * x;
END//
DELIMITER ;

-- Function with multiple parameters
DELIMITER //
CREATE FUNCTION multiply(a INT, b INT)
RETURNS INT
DETERMINISTIC
BEGIN
    RETURN a * b;
END//
DELIMITER ;

-- Function with default value
DELIMITER //
CREATE FUNCTION greet_user(name VARCHAR(100))
RETURNS VARCHAR(200)
DETERMINISTIC
BEGIN
    IF name IS NULL THEN
        RETURN 'Hello, Guest!';
    END IF;
    RETURN CONCAT('Hello, ', name, '!');
END//
DELIMITER ;

-- Function with validation
DELIMITER //
CREATE FUNCTION calculate_bonus(
    salary DECIMAL(10,2),
    performance_rating INT
)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
    DECLARE bonus DECIMAL(10,2);
    
    CASE performance_rating
        WHEN 5 THEN SET bonus = salary * 0.20;
        WHEN 4 THEN SET bonus = salary * 0.15;
        WHEN 3 THEN SET bonus = salary * 0.10;
        WHEN 2 THEN SET bonus = salary * 0.05;
        ELSE SET bonus = 0;
    END CASE;
    
    RETURN bonus;
END//
DELIMITER ;

-- Usage
SELECT 
    square(5),
    multiply(3, 4),
    greet_user('Alice'),
    calculate_bonus(50000, 4);
Intermediate
16. What are window functions in SQL?

Window functions perform calculations across a set of rows related to the current row. Available in SQL 8.0+.

  • ROW_NUMBER: Sequential row number
  • RANK: Rank with gaps
  • DENSE_RANK: Rank without gaps
  • LAG/LEAD: Previous/next row values
  • SUM/AVG: Aggregate with window
sql
-- Window Functions in SQL (8.0+)
-- Window functions for advanced analytics

-- ROW_NUMBER
SELECT 
    name,
    age,
    city,
    ROW_NUMBER() OVER (PARTITION BY city ORDER BY age) AS row_num
FROM users;

-- RANK and DENSE_RANK
SELECT 
    name,
    salary,
    RANK() OVER (ORDER BY salary DESC) AS rank_position,
    DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank_position
FROM employees;

-- LAG and LEAD
SELECT 
    date,
    amount,
    LAG(amount, 1) OVER (ORDER BY date) AS previous_amount,
    LEAD(amount, 1) OVER (ORDER BY date) AS next_amount
FROM sales;

-- NTILE
SELECT 
    name,
    salary,
    NTILE(4) OVER (ORDER BY salary DESC) AS quartile
FROM employees;

-- SUM with window
SELECT 
    name,
    salary,
    SUM(salary) OVER (ORDER BY salary) AS cumulative_salary
FROM employees;

-- Moving average
SELECT 
    date,
    amount,
    AVG(amount) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg_3
FROM sales;

-- FIRST_VALUE and LAST_VALUE
SELECT 
    name,
    department,
    salary,
    FIRST_VALUE(name) OVER (PARTITION BY department ORDER BY salary DESC) AS highest_paid,
    LAST_VALUE(name) OVER (PARTITION BY department ORDER BY salary DESC 
        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS lowest_paid
FROM employees;
Intermediate
17. What are CTEs in SQL?

Common Table Expressions (CTEs) are temporary result sets that can be referenced within a query. Available in SQL 8.0+.

  • WITH: Define CTE
  • Recursive CTE: Self-referencing CTE
  • Multiple CTEs: Define multiple in one query
  • Reference: Use CTE name in query
  • Hierarchical queries: Recursive for tree structures
sql
-- Common Table Expressions (CTE) in SQL
-- CTE for complex queries

-- Simple CTE
WITH user_stats AS (
    SELECT 
        city,
        COUNT(*) AS user_count,
        AVG(age) AS avg_age
    FROM users
    GROUP BY city
)
SELECT * FROM user_stats WHERE user_count > 5;

-- Recursive CTE (MySQL 8.0+)
WITH RECURSIVE numbers (n) AS (
    SELECT 1  -- Anchor
    UNION ALL
    SELECT n + 1  -- Recursive
    FROM numbers
    WHERE n < 10
)
SELECT * FROM numbers;

-- Recursive CTE for hierarchical data
CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    manager_id INT
);

INSERT INTO employees VALUES 
    (1, 'CEO', NULL),
    (2, 'VP', 1),
    (3, 'Manager', 2),
    (4, 'Developer', 3),
    (5, 'Developer', 3);

WITH RECURSIVE org_chart AS (
    SELECT 
        id,
        name,
        manager_id,
        0 AS level
    FROM employees
    WHERE manager_id IS NULL
    
    UNION ALL
    
    SELECT 
        e.id,
        e.name,
        e.manager_id,
        oc.level + 1
    FROM employees e
    INNER JOIN org_chart oc ON e.manager_id = oc.id
)
SELECT 
    CONCAT(REPEAT('  ', level), name) AS org_chart
FROM org_chart
ORDER BY level, id;

-- Multiple CTEs
WITH 
stats AS (
    SELECT 
        city,
        COUNT(*) AS count,
        AVG(age) AS avg_age
    FROM users
    GROUP BY city
),
ranked AS (
    SELECT 
        city,
        count,
        avg_age,
        RANK() OVER (ORDER BY count DESC) AS rank_position
    FROM stats
)
SELECT * FROM ranked WHERE rank_position <= 5;
Intermediate
18. What are views in SQL?

Views are virtual tables based on a SELECT query. They provide a way to simplify complex queries and enforce security.

  • CREATE VIEW: Define view
  • Updatable views: Views that allow DML operations
  • WITH CHECK OPTION: Enforce view conditions
  • Algorithm: MERGE, TEMPTABLE, UNDEFINED
  • Drop view: DROP VIEW
sql
-- Views in SQL
-- Views are virtual tables

-- Create simple view
CREATE VIEW active_users AS 
SELECT id, name, email, age
FROM users
WHERE status = 'active';

-- Create view with JOIN
CREATE VIEW user_orders AS 
SELECT 
    u.id AS user_id,
    u.name AS user_name,
    o.id AS order_id,
    o.total AS order_total,
    o.created_at AS order_date
FROM users u
INNER JOIN orders o ON u.id = o.user_id;

-- Create view with aggregation
CREATE VIEW city_stats AS 
SELECT 
    city,
    COUNT(*) AS user_count,
    AVG(age) AS avg_age,
    MIN(age) AS min_age,
    MAX(age) AS max_age
FROM users
GROUP BY city;

-- Create view with algorithm
CREATE ALGORITHM = MERGE VIEW user_names AS 
SELECT id, CONCAT(first_name, ' ', last_name) AS full_name
FROM users;

-- Create view with check option
CREATE VIEW ny_users AS 
SELECT * FROM users WHERE city = 'NYC'
WITH CHECK OPTION;

-- Update data through view
UPDATE active_users SET age = 26 WHERE id = 1;

-- Drop view
DROP VIEW IF EXISTS active_users;

-- Show create view
SHOW CREATE VIEW user_orders;

-- Information about views
SELECT * FROM INFORMATION_SCHEMA.VIEWS 
WHERE TABLE_SCHEMA = 'database_name';
Intermediate
19. What are indexes in SQL?

Indexes improve query performance by allowing faster data retrieval. They are created on columns used in WHERE, JOIN, and ORDER BY clauses.

  • CREATE INDEX: Create index
  • UNIQUE INDEX: Enforce uniqueness
  • Composite index: Multiple columns
  • FULLTEXT index: Full-text search
  • SPATIAL index: Geospatial data
sql
-- Indexes in SQL
-- Index types and usage

-- CREATE INDEX
CREATE INDEX idx_users_name ON users(name);

-- CREATE UNIQUE INDEX
CREATE UNIQUE INDEX idx_users_email ON users(email);

-- CREATE COMPOSITE INDEX
CREATE INDEX idx_users_city_age ON users(city, age);

-- CREATE FULLTEXT INDEX
CREATE FULLTEXT INDEX idx_posts_content ON posts(content);

-- CREATE SPATIAL INDEX
CREATE SPATIAL INDEX idx_locations_coords ON locations(coordinates);

-- CREATE INDEX WITH DESC
CREATE INDEX idx_users_name_desc ON users(name DESC);

-- Index on prefix
CREATE INDEX idx_users_name_prefix ON users(name(10));

-- DROP INDEX
DROP INDEX idx_users_name ON users;

-- Show indexes
SHOW INDEX FROM users;

-- Analyze table for index usage
ANALYZE TABLE users;

-- Optimize table
OPTIMIZE TABLE users;

-- Index usage with EXPLAIN
EXPLAIN SELECT * FROM users WHERE name = 'Alice';

-- Invisible index (MySQL 8.0+)
CREATE INDEX idx_invisible ON users(name) INVISIBLE;

-- Visible/invisible toggle
ALTER TABLE users ALTER INDEX idx_invisible VISIBLE;
ALTER TABLE users ALTER INDEX idx_invisible INVISIBLE;
Intermediate
20. What are triggers in SQL?

Triggers are stored programs that automatically execute in response to DML events (INSERT, UPDATE, DELETE) on a table.

  • BEFORE/AFTER: Timing of execution
  • INSERT/UPDATE/DELETE: Triggering event
  • NEW/OLD: Access new and old row values
  • Validation: Enforce business rules
  • Audit logging: Track changes
sql
-- Triggers in SQL
-- Triggers for automatic actions

-- BEFORE INSERT trigger
DELIMITER //
CREATE TRIGGER before_user_insert
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
    SET NEW.created_at = NOW();
    SET NEW.updated_at = NOW();
END//
DELIMITER ;

-- BEFORE UPDATE trigger
DELIMITER //
CREATE TRIGGER before_user_update
BEFORE UPDATE ON users
FOR EACH ROW
BEGIN
    SET NEW.updated_at = NOW();
END//
DELIMITER ;

-- AFTER INSERT trigger for logging
DELIMITER //
CREATE TRIGGER after_user_insert
AFTER INSERT ON users
FOR EACH ROW
BEGIN
    INSERT INTO audit_log (table_name, action, record_id, user_name, timestamp)
    VALUES ('users', 'INSERT', NEW.id, NEW.name, NOW());
END//
DELIMITER ;

-- BEFORE DELETE trigger
DELIMITER //
CREATE TRIGGER before_user_delete
BEFORE DELETE ON users
FOR EACH ROW
BEGIN
    INSERT INTO deleted_users (id, name, email, deleted_at)
    VALUES (OLD.id, OLD.name, OLD.email, NOW());
END//
DELIMITER ;

-- Trigger with validation
DELIMITER //
CREATE TRIGGER validate_user_age
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
    IF NEW.age < 0 OR NEW.age > 150 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Invalid age';
    END IF;
END//
DELIMITER ;

-- Show triggers
SHOW TRIGGERS;
SHOW TRIGGERS LIKE 'users%';

-- Drop trigger
DROP TRIGGER IF EXISTS after_user_insert;
Advanced
21. What is the difference between procedures and functions?

Stored procedures and functions are both stored routines, but they have different purposes and characteristics.

  • Procedures: Can modify data, multiple parameters
  • Functions: Return single value, called in SELECT
  • Procedures: Can have OUT/INOUT parameters
  • Functions: Must be deterministic for replication
  • Procedures: Called with CALL, not in expressions
sql
-- Stored Procedures vs Functions
-- Comparison and examples

-- Stored Procedure (can modify data)
DELIMITER //
CREATE PROCEDURE update_user_age(
    IN user_id INT,
    IN new_age INT
)
BEGIN
    UPDATE users SET age = new_age WHERE id = user_id;
    SELECT ROW_COUNT() AS rows_affected;
END//
DELIMITER ;

-- Function (must be deterministic, cannot modify data)
DELIMITER //
CREATE FUNCTION get_user_age(user_id INT)
RETURNS INT
DETERMINISTIC
READS SQL DATA
BEGIN
    DECLARE user_age INT;
    SELECT age INTO user_age FROM users WHERE id = user_id;
    RETURN user_age;
END//
DELIMITER ;

-- Procedure with multiple outputs
DELIMITER //
CREATE PROCEDURE get_user_stats(
    IN user_id INT,
    OUT user_name VARCHAR(100),
    OUT user_age INT,
    OUT user_city VARCHAR(100)
)
BEGIN
    SELECT name, age, city 
    INTO user_name, user_age, user_city
    FROM users 
    WHERE id = user_id;
END//
DELIMITER ;

-- Calling procedures
CALL update_user_age(1, 26);
CALL get_user_stats(1, @name, @age, @city);
SELECT @name, @age, @city;

-- Using functions
SELECT get_user_age(1) AS age;
Advanced
22. What are transactions in SQL?

Transactions ensure atomicity of database operations. They group multiple statements into a single unit of work.

  • START TRANSACTION: Begin transaction
  • COMMIT: Save changes permanently
  • ROLLBACK: Undo changes
  • SAVEPOINT: Partial rollback
  • Isolation levels: Control concurrency
sql
-- Transactions in SQL
-- ACID properties and transaction control

-- Basic transaction
START TRANSACTION;

UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

COMMIT;

-- Transaction with rollback
START TRANSACTION;

UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- Check balance
SELECT balance FROM accounts WHERE id = 1;

IF balance < 0 THEN
    ROLLBACK;
    SELECT 'Insufficient balance' AS result;
ELSE
    UPDATE accounts SET balance = balance + 100 WHERE id = 2;
    COMMIT;
    SELECT 'Transfer successful' AS result;
END IF;

-- SAVEPOINT
START TRANSACTION;

INSERT INTO orders (user_id, total) VALUES (1, 100);
SAVEPOINT order_inserted;

INSERT INTO order_items (order_id, product_id, quantity) 
VALUES (LAST_INSERT_ID(), 1, 2);

-- If order item fails, rollback to savepoint
ROLLBACK TO order_inserted;

COMMIT;

-- Transaction isolation levels
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- Locking reads
START TRANSACTION;
SELECT * FROM users WHERE id = 1 FOR UPDATE;
UPDATE users SET balance = balance - 100 WHERE id = 1;
COMMIT;

-- Shared lock
SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE;
Advanced
23. What are user-defined variables in SQL?

User-defined variables are session-specific variables that can store values for use in statements and queries.

  • @variable: Session scope
  • SET: Assign value
  • SELECT INTO: Assign from query
  • SQL statements: Use in any statement
  • Limitations: Session only, no persistence
sql
-- User-Defined Variables in SQL
-- Session-level variables

-- Set variables
SET @var1 = 10;
SET @var2 := 20;  -- Alternative syntax
SELECT @var3 := 30;  -- Set from SELECT

-- Use variables in queries
SET @min_age = 18;
SET @max_age = 30;

SELECT * FROM users WHERE age BETWEEN @min_age AND @max_age;

-- Variables from SELECT
SELECT COUNT(*) INTO @user_count FROM users;
SELECT @user_count;

-- Multiple variables
SELECT name, age INTO @name, @age FROM users WHERE id = 1;
SELECT @name, @age;

-- Variables in LIMIT
SET @offset = 0;
SET @limit = 10;
PREPARE stmt FROM 'SELECT * FROM users LIMIT ?, ?';
EXECUTE stmt USING @offset, @limit;

-- Session vs global variables
SET SESSION sort_buffer_size = 1024;
SET GLOBAL max_connections = 1000;

-- System variables
SELECT @@global.max_connections;
SELECT @@session.autocommit;

-- Show all variables
SHOW VARIABLES;
SHOW SESSION VARIABLES;
SHOW GLOBAL VARIABLES;
Advanced
24. What are prepared statements in SQL?

Prepared statements allow parameterized queries for better performance and SQL injection prevention.

  • PREPARE: Prepare statement
  • EXECUTE: Execute with parameters
  • DEALLOCATE: Free resources
  • Dynamic SQL: Build queries at runtime
  • Performance: Reuse execution plan
sql
-- Prepared Statements in SQL
-- SQL injection prevention and performance

-- Prepare statement
PREPARE stmt1 FROM 'SELECT * FROM users WHERE id = ?';

SET @user_id = 1;
EXECUTE stmt1 USING @user_id;

DEALLOCATE PREPARE stmt1;

-- Multiple parameters
PREPARE stmt2 FROM 'SELECT * FROM users WHERE age BETWEEN ? AND ?';

SET @min_age = 18;
SET @max_age = 30;
EXECUTE stmt2 USING @min_age, @max_age;

DEALLOCATE PREPARE stmt2;

-- Dynamic table name (not directly possible, use CONCAT)
SET @table_name = 'users';
SET @query = CONCAT('SELECT * FROM ', @table_name, ' WHERE id = ?');
PREPARE stmt3 FROM @query;
SET @user_id = 1;
EXECUTE stmt3 USING @user_id;
DEALLOCATE PREPARE stmt3;

-- Dynamic ORDER BY
SET @order_by = 'name';
SET @direction = 'DESC';
SET @query = CONCAT('SELECT * FROM users ORDER BY ', @order_by, ' ', @direction);
PREPARE stmt4 FROM @query;
EXECUTE stmt4;
DEALLOCATE PREPARE stmt4;

-- Using with stored procedures
DELIMITER //
CREATE PROCEDURE dynamic_query(
    IN table_name VARCHAR(100),
    IN column_name VARCHAR(100)
)
BEGIN
    SET @query = CONCAT('SELECT ', column_name, ' FROM ', table_name);
    PREPARE stmt FROM @query;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END//
DELIMITER ;

CALL dynamic_query('users', 'name');
Advanced
25. What is partitioning in SQL?

Partitioning divides a table into smaller pieces for better performance and management. SQL supports RANGE, LIST, HASH, and KEY partitioning.

  • RANGE: Partition by value ranges
  • LIST: Partition by list of values
  • HASH: Partition by hash function
  • KEY: Partition by SQL hash function
  • Subpartitioning: Nested partitions
sql
-- Partitioning in SQL
-- Table partitioning for performance

-- Range partitioning
CREATE TABLE orders_partitioned (
    id INT,
    order_date DATE,
    customer_id INT,
    amount DECIMAL(10,2)
)
PARTITION BY RANGE (YEAR(order_date)) (
    PARTITION p2020 VALUES LESS THAN (2021),
    PARTITION p2021 VALUES LESS THAN (2022),
    PARTITION p2022 VALUES LESS THAN (2023),
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p_future VALUES LESS THAN MAXVALUE
);

-- List partitioning
CREATE TABLE users_by_region (
    id INT,
    name VARCHAR(100),
    region VARCHAR(50)
)
PARTITION BY LIST (region) (
    PARTITION p_north VALUES IN ('North', 'Northeast'),
    PARTITION p_south VALUES IN ('South', 'Southeast'),
    PARTITION p_west VALUES IN ('West', 'Southwest'),
    PARTITION p_east VALUES IN ('East', 'Midwest')
);

-- Hash partitioning
CREATE TABLE logs (
    id INT,
    log_data TEXT,
    created_at DATETIME
)
PARTITION BY HASH (id)
PARTITIONS 4;

-- Key partitioning (similar to hash but uses MySQL's hash function)
CREATE TABLE sessions (
    id INT,
    session_id VARCHAR(255),
    data TEXT
)
PARTITION BY KEY (id)
PARTITIONS 4;

-- Subpartitioning
CREATE TABLE sales (
    id INT,
    sale_date DATE,
    amount DECIMAL(10,2),
    region VARCHAR(50)
)
PARTITION BY RANGE (YEAR(sale_date))
SUBPARTITION BY HASH (id)
SUBPARTITIONS 2 (
    PARTITION p2020 VALUES LESS THAN (2021),
    PARTITION p2021 VALUES LESS THAN (2022)
);

-- Query partition information
SELECT * FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'orders_partitioned';

-- Partition pruning
EXPLAIN SELECT * FROM orders_partitioned 
WHERE order_date BETWEEN '2021-01-01' AND '2021-12-31';

-- Add partition
ALTER TABLE orders_partitioned 
ADD PARTITION (PARTITION p2024 VALUES LESS THAN (2025));

-- Drop partition
ALTER TABLE orders_partitioned DROP PARTITION p_future;

-- Reorganize partitions
ALTER TABLE orders_partitioned 
REORGANIZE PARTITION p_future INTO (
    PARTITION p2024 VALUES LESS THAN (2025),
    PARTITION p_future VALUES LESS THAN MAXVALUE
);
Advanced
26. What is replication in SQL?

Replication copies data from one SQL server to another. It provides high availability, read scaling, and backup capabilities.

  • Master-slave: One master, multiple slaves
  • Master-master: Bidirectional replication
  • Binary log: Records changes
  • GTID: Global transaction identifiers
  • Semi-sync: Acknowledgment from slaves
sql
-- Replication in SQL
-- Master-slave replication concepts

-- On Master server
-- Enable binary log
-- my.cnf:
-- server-id = 1
-- log-bin = mysql-bin
-- binlog-do-db = mydatabase

-- Create replication user
CREATE USER 'replication'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'replication'@'%';

-- Get master status
SHOW MASTER STATUS;

-- On Slave server
-- my.cnf:
-- server-id = 2
-- relay-log = mysql-relay-bin

-- Configure slave
CHANGE MASTER TO
    MASTER_HOST = 'master_host',
    MASTER_USER = 'replication',
    MASTER_PASSWORD = 'password',
    MASTER_LOG_FILE = 'mysql-bin.000001',
    MASTER_LOG_POS = 123;

-- Start slave
START SLAVE;

-- Check slave status
SHOW SLAVE STATUSG

-- Stop slave
STOP SLAVE;

-- Reset slave
RESET SLAVE ALL;

-- Multi-source replication (MySQL 5.7+)
CHANGE MASTER TO
    MASTER_HOST = 'master1_host',
    MASTER_USER = 'replication',
    MASTER_PASSWORD = 'password',
    MASTER_LOG_FILE = 'mysql-bin.000001',
    MASTER_LOG_POS = 123
FOR CHANNEL 'channel1';

CHANGE MASTER TO
    MASTER_HOST = 'master2_host',
    MASTER_USER = 'replication',
    MASTER_PASSWORD = 'password',
    MASTER_LOG_FILE = 'mysql-bin.000001',
    MASTER_LOG_POS = 456
FOR CHANNEL 'channel2';

START SLAVE FOR CHANNEL 'channel1';
START SLAVE FOR CHANNEL 'channel2';

-- Semi-synchronous replication
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
Advanced
27. How to optimize SQL performance?

Performance optimization involves query optimization, indexing, configuration tuning, and hardware considerations.

  • EXPLAIN: Analyze query execution
  • Indexes: Create appropriate indexes
  • Query cache: Cache query results
  • Slow query log: Identify slow queries
  • Configuration: Tune SQL variables
sql
-- Performance Tuning in SQL
-- Query optimization and tuning

-- Query cache (MySQL 5.7 and earlier)
SHOW VARIABLES LIKE 'query_cache%';
SET GLOBAL query_cache_size = 1000000;

-- SQL_NO_CACHE (for testing)
SELECT SQL_NO_CACHE * FROM users WHERE age > 18;

-- SQL_CACHE (force cache)
SELECT SQL_CACHE * FROM users WHERE age > 18;

-- Analyze slow query log
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 2;

-- Use EXPLAIN for query analysis
EXPLAIN SELECT * FROM users WHERE age > 18;

-- Use EXPLAIN FORMAT=JSON
EXPLAIN FORMAT=JSON SELECT * FROM users WHERE age > 18;

-- Query profiling
SET profiling = 1;
SELECT * FROM users WHERE age > 18;
SHOW PROFILES;
SHOW PROFILE FOR QUERY 1;

-- OPTIMIZE TABLE
OPTIMIZE TABLE users;

-- ANALYZE TABLE
ANALYZE TABLE users;

-- CHECK TABLE
CHECK TABLE users;

-- REPAIR TABLE
REPAIR TABLE users;

-- Innodb status
SHOW ENGINE INNODB STATUSG

-- Processlist
SHOW FULL PROCESSLIST;

-- Kill query
KILL QUERY 123;

-- Kill connection
KILL 123;
Advanced
28. How to backup and restore SQL?

SQL offers various backup methods including mysqldump, SQL Enterprise Backup, and Percona XtraBackup.

  • mysqldump: Logical backup
  • mysqlbackup: Physical backup (Enterprise)
  • XtraBackup: Physical backup (Percona)
  • Binary logs: Point-in-time recovery
  • CSV export: Data export/import
sql
-- Backup and Restore in SQL
-- Backup methods

-- mysqldump
-- mysqldump -u username -p database_name > backup.sql

-- mysqldump specific tables
-- mysqldump -u username -p database_name users orders > backup.sql

-- mysqldump with options
-- mysqldump -u username -p --add-drop-table --create-options database_name > backup.sql

-- mysqldump for all databases
-- mysqldump -u username -p --all-databases > all_backup.sql

-- mysqldump with compression
-- mysqldump -u username -p database_name | gzip > backup.sql.gz

-- mysqldump with --single-transaction (for InnoDB)
-- mysqldump -u username -p --single-transaction database_name > backup.sql

-- mysqldump with --master-data (for replication)
-- mysqldump -u username -p --master-data=2 database_name > backup.sql

-- Restore
-- mysql -u username -p database_name < backup.sql

-- Restore with compression
-- gunzip < backup.sql.gz | mysql -u username -p database_name

-- Restore without database creation
-- mysql -u username -p < backup.sql

-- MySQL Enterprise Backup
-- mysqlbackup --defaults-file=/etc/my.cnf --backup-dir=/backup backup

-- Percona XtraBackup
-- xtrabackup --backup --target-dir=/backup

-- Binary log backup
-- mysqlbinlog mysql-bin.000001 > binlog.sql

-- Export to CSV
SELECT * FROM users INTO OUTFILE '/tmp/users.csv'
FIELDS TERMINATED BY ',' 
ENCLOSED BY '"'
LINES TERMINATED BY '
';

-- Import from CSV
LOAD DATA INFILE '/tmp/users.csv'
INTO TABLE users
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '
'
IGNORE 1 LINES;
Advanced
29. How to manage users in SQL?

User management includes creating users, granting privileges, managing roles, and setting password policies.

  • CREATE USER: Create database users
  • GRANT: Assign privileges
  • REVOKE: Remove privileges
  • Roles: Groups of privileges (8.0+)
  • Password policies: Enforce security
sql
-- User Management in SQL
-- Creating and managing users

-- Create user
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'password';
CREATE USER 'app_user'@'%' IDENTIFIED BY 'password';

-- Drop user
DROP USER 'app_user'@'localhost';

-- Rename user
RENAME USER 'old_user'@'localhost' TO 'new_user'@'localhost';

-- Grant privileges
GRANT ALL PRIVILEGES ON database_name.* TO 'app_user'@'localhost';
GRANT SELECT, INSERT, UPDATE ON database_name.* TO 'app_user'@'localhost';
GRANT ALL PRIVILEGES ON *.* TO 'admin_user'@'localhost' WITH GRANT OPTION;

-- Grant specific privileges
GRANT SELECT ON database_name.users TO 'app_user'@'localhost';
GRANT EXECUTE ON PROCEDURE database_name.procedure_name TO 'app_user'@'localhost';

-- Revoke privileges
REVOKE ALL PRIVILEGES ON database_name.* FROM 'app_user'@'localhost';
REVOKE GRANT OPTION ON *.* FROM 'admin_user'@'localhost';

-- Show grants
SHOW GRANTS FOR 'app_user'@'localhost';
SHOW GRANTS;  -- For current user

-- Create user with password expiration
CREATE USER 'temp_user'@'localhost' IDENTIFIED BY 'password'
PASSWORD EXPIRE INTERVAL 30 DAY;

-- Create user with account lock
CREATE USER 'locked_user'@'localhost' IDENTIFIED BY 'password'
ACCOUNT LOCK;

-- Unlock account
ALTER USER 'locked_user'@'localhost' ACCOUNT UNLOCK;

-- Change password
ALTER USER 'app_user'@'localhost' IDENTIFIED BY 'new_password';
SET PASSWORD FOR 'app_user'@'localhost' = PASSWORD('new_password');

-- Roles (MySQL 8.0+)
CREATE ROLE 'app_role', 'admin_role';
GRANT SELECT ON database_name.* TO 'app_role';
GRANT ALL PRIVILEGES ON *.* TO 'admin_role';
GRANT 'app_role' TO 'app_user'@'localhost';
SET DEFAULT ROLE 'app_role' TO 'app_user'@'localhost';
Advanced
30. What are security best practices in SQL?

Security best practices include authentication, authorization, encryption, and auditing.

  • Authentication: Strong passwords, SSL/TLS
  • Authorization: Principle of least privilege
  • Encryption: Data at rest and in transit
  • Audit logging: Track activities
  • Updates: Keep SQL up-to-date
sql
-- Security Best Practices in SQL
-- Security configurations

-- Remove anonymous users
DELETE FROM mysql.user WHERE User = '';
FLUSH PRIVILEGES;

-- Remove test database
DROP DATABASE IF EXISTS test;

-- Disable remote root login
RENAME USER 'root'@'%' TO 'root'@'localhost';

-- Use SSL/TLS
-- my.cnf:
-- ssl-ca=/etc/mysql/ssl/ca.pem
-- ssl-cert=/etc/mysql/ssl/server-cert.pem
-- ssl-key=/etc/mysql/ssl/server-key.pem

-- Require SSL for user
ALTER USER 'app_user'@'%' REQUIRE SSL;

-- Set password policy
SET GLOBAL validate_password.policy = STRONG;
SET GLOBAL validate_password.length = 8;

-- Enable audit log
INSTALL PLUGIN audit_log SONAME 'audit_log.so';
SET GLOBAL audit_log_policy = ALL;

-- Limit connections per user
ALTER USER 'app_user'@'%' WITH MAX_CONNECTIONS_PER_HOUR 100;

-- Limit queries per hour
ALTER USER 'app_user'@'%' WITH MAX_QUERIES_PER_HOUR 1000;

-- Limit updates per hour
ALTER USER 'app_user'@'%' WITH MAX_UPDATES_PER_HOUR 100;

-- Disable LOAD DATA LOCAL INFILE
SET GLOBAL local_infile = 0;

-- Enable SQL_MODE
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE';

-- Show security variables
SHOW VARIABLES LIKE '%ssl%';
SHOW VARIABLES LIKE '%validate%';
SHOW VARIABLES LIKE '%secure%';

-- Check user connections
SELECT user, host, connection_id FROM information_schema.processlist;
Coding Round
31. Find maximum salary

Find maximum salary using MAX() function or ORDER BY LIMIT.

  • MAX(): SELECT MAX(salary) FROM employees
  • ORDER BY: SELECT salary FROM employees ORDER BY salary DESC LIMIT 1
  • Subquery: SELECT * FROM employees WHERE salary = (SELECT MAX(salary) FROM employees)
sql
-- Normalization in SQL
-- Database normalization principles

-- First Normal Form (1NF) - Atomic values
-- Bad: Products table with multiple categories
CREATE TABLE products_bad (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    categories VARCHAR(255)  -- Comma separated values
);

-- Good: 1NF compliant
CREATE TABLE products (
    id INT PRIMARY KEY,
    name VARCHAR(100)
);

CREATE TABLE product_categories (
    product_id INT,
    category VARCHAR(50),
    PRIMARY KEY (product_id, category)
);

-- Second Normal Form (2NF) - Remove partial dependencies
-- Bad: Orders with product details
CREATE TABLE orders_bad (
    order_id INT,
    product_id INT,
    product_name VARCHAR(100),
    quantity INT,
    unit_price DECIMAL(10,2),
    PRIMARY KEY (order_id, product_id)
);

-- Good: 2NF compliant
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    order_date DATE
);

CREATE TABLE order_items (
    order_id INT,
    product_id INT,
    quantity INT,
    unit_price DECIMAL(10,2),
    PRIMARY KEY (order_id, product_id)
);

CREATE TABLE products (
    product_id INT PRIMARY KEY,
    name VARCHAR(100)
);

-- Third Normal Form (3NF) - Remove transitive dependencies
-- Bad: Orders with customer details
CREATE TABLE orders_bad (
    order_id INT PRIMARY KEY,
    customer_id INT,
    customer_name VARCHAR(100),
    customer_city VARCHAR(100),
    order_date DATE
);

-- Good: 3NF compliant
CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    name VARCHAR(100),
    city VARCHAR(100)
);

CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    order_date DATE,
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);

-- Boyce-Codd Normal Form (BCNF)
-- Handle overlapping candidate keys

-- Fourth Normal Form (4NF)
-- Handle multi-valued dependencies

-- Fifth Normal Form (5NF)
-- Handle join dependencies
Coding Round
32. Find second highest salary

Find second highest salary using LIMIT, subquery, or window functions.

  • LIMIT: SELECT DISTINCT salary FROM employees ORDER BY salary DESC LIMIT 1 OFFSET 1
  • Subquery: SELECT MAX(salary) FROM employees WHERE salary < (SELECT MAX(salary) FROM employees)
  • Window function: DENSE_RANK() OVER (ORDER BY salary DESC)
  • Complexity: O(n log n)
sql
-- Denormalization in SQL
-- Denormalization for performance

-- Denormalized table with redundant data
CREATE TABLE orders_denormalized (
    order_id INT PRIMARY KEY,
    customer_id INT,
    customer_name VARCHAR(100),
    customer_email VARCHAR(255),
    product_id INT,
    product_name VARCHAR(100),
    quantity INT,
    unit_price DECIMAL(10,2),
    total DECIMAL(10,2),
    order_date DATE
);

-- Update denormalized data with triggers
DELIMITER //
CREATE TRIGGER update_order_total
BEFORE INSERT ON orders_denormalized
FOR EACH ROW
BEGIN
    SET NEW.total = NEW.quantity * NEW.unit_price;
END//
DELIMITER ;

-- Materialized views (using tables and triggers)
CREATE TABLE sales_summary (
    product_id INT PRIMARY KEY,
    total_sales DECIMAL(10,2),
    units_sold INT,
    last_updated TIMESTAMP
);

-- Refresh materialized view
UPDATE sales_summary ss
JOIN (
    SELECT 
        product_id,
        SUM(quantity * unit_price) AS total_sales,
        SUM(quantity) AS units_sold
    FROM order_items
    GROUP BY product_id
) o ON ss.product_id = o.product_id
SET 
    ss.total_sales = o.total_sales,
    ss.units_sold = o.units_sold,
    ss.last_updated = NOW();

-- Denormalized query performance
-- Without denormalization (JOIN)
SELECT 
    o.order_id,
    c.name AS customer_name,
    p.name AS product_name,
    oi.quantity,
    oi.unit_price
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id;

-- With denormalization (single table)
SELECT * FROM orders_denormalized;
Coding Round
33. Find duplicate emails

Find duplicate emails using GROUP BY and HAVING.

  • GROUP BY: SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1
  • Self-join: SELECT DISTINCT a.email FROM users a JOIN users b ON a.email = b.email AND a.id != b.id
  • Subquery: SELECT email FROM (SELECT email, COUNT(*) as cnt FROM users GROUP BY email) t WHERE cnt > 1
  • Complexity: O(n)
sql
-- JSON in SQL (MySQL 5.7+)
-- JSON data type and functions

-- Create table with JSON column
CREATE TABLE json_data (
    id INT PRIMARY KEY AUTO_INCREMENT,
    data JSON
);

-- Insert JSON
INSERT INTO json_data (data) VALUES 
    ('{"name": "Alice", "age": 25, "city": "NYC"}'),
    ('{"name": "Bob", "age": 30, "city": "LA", "hobbies": ["reading", "gaming"]}');

-- Extract value
SELECT 
    id,
    JSON_EXTRACT(data, '$.name') AS name,
    JSON_EXTRACT(data, '$.age') AS age
FROM json_data;

-- Extract with -> operator
SELECT 
    id,
    data->'$.name' AS name,
    data->'$.age' AS age
FROM json_data;

-- Extract as text with ->> operator
SELECT 
    id,
    data->>'$.name' AS name,
    data->>'$.age' AS age
FROM json_data;

-- JSON functions
SELECT 
    JSON_OBJECT('name', name, 'age', age) AS user_json
FROM users;

SELECT 
    JSON_ARRAY(name, age, city) AS user_array
FROM users;

-- Update JSON
UPDATE json_data 
SET data = JSON_SET(data, '$.age', 26, '$.city', 'NYC') 
WHERE id = 1;

-- Add to JSON
UPDATE json_data 
SET data = JSON_INSERT(data, '$.status', 'active') 
WHERE id = 1;

-- Remove from JSON
UPDATE json_data 
SET data = JSON_REMOVE(data, '$.status') 
WHERE id = 1;

-- Search in JSON
SELECT * FROM json_data 
WHERE JSON_EXTRACT(data, '$.name') = 'Alice';

-- JSON path
SELECT 
    JSON_SEARCH(data, 'one', 'Alice') AS path
FROM json_data;

-- JSON table (MySQL 8.0+)
SELECT * 
FROM JSON_TABLE(
    '[{"name": "Alice"}, {"name": "Bob"}]',
    '$[*]' COLUMNS (
        name VARCHAR(100) PATH '$.name'
    )
) AS jt;
Coding Round
34. Delete duplicates keeping first

Delete duplicate records keeping the first (lowest ID) occurrence.

  • Self-join: DELETE a FROM users a JOIN users b ON a.email = b.email AND a.id > b.id
  • Subquery: DELETE FROM users WHERE id NOT IN (SELECT MIN(id) FROM users GROUP BY email)
  • Window function: WITH ranked AS (SELECT id, ROW_NUMBER() OVER (PARTITION BY email ORDER BY id) as rn FROM users) DELETE FROM users WHERE id IN (SELECT id FROM ranked WHERE rn > 1)
  • Complexity: O(n log n)
sql
-- Full-Text Search in SQL
-- Full-text indexing and searching

-- Create table with FULLTEXT index
CREATE TABLE articles (
    id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255),
    content TEXT,
    FULLTEXT INDEX ft_title_content (title, content)
);

-- Insert data
INSERT INTO articles (title, content) VALUES
    ('MySQL Full-Text Search', 'MySQL supports full-text searching and indexing'),
    ('Advanced SQL Queries', 'Learn about complex SQL queries and optimization'),
    ('Database Performance Tuning', 'Tips for improving database performance');

-- NATURAL LANGUAGE MODE
SELECT * FROM articles 
WHERE MATCH(title, content) AGAINST('MySQL' IN NATURAL LANGUAGE MODE);

-- BOOLEAN MODE
-- + Required, - Excluded, * Wildcard, > Increase rank, < Decrease rank
SELECT * FROM articles 
WHERE MATCH(title, content) AGAINST('+MySQL +search' IN BOOLEAN MODE);

SELECT * FROM articles 
WHERE MATCH(title, content) AGAINST('MySQL -Oracle' IN BOOLEAN MODE);

SELECT * FROM articles 
WHERE MATCH(title, content) AGAINST('MySQL*' IN BOOLEAN MODE);

SELECT * FROM articles 
WHERE MATCH(title, content) AGAINST('>MySQL +search' IN BOOLEAN MODE);

-- WITH QUERY EXPANSION
SELECT * FROM articles 
WHERE MATCH(title, content) AGAINST('MySQL' WITH QUERY EXPANSION);

-- Query with relevance score
SELECT 
    *,
    MATCH(title, content) AGAINST('MySQL') AS relevance
FROM articles 
WHERE MATCH(title, content) AGAINST('MySQL')
ORDER BY relevance DESC;

-- Full-text search on multiple tables (using UNION)
SELECT * FROM articles 
WHERE MATCH(title, content) AGAINST('MySQL')
UNION
SELECT * FROM comments 
WHERE MATCH(comment) AGAINST('MySQL');

-- Stopwords
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD;

-- Minimum word length
SHOW VARIABLES LIKE 'ft_min_word_len';
SHOW VARIABLES LIKE 'innodb_ft_min_token_size';
Coding Round
35. Find employees earning more than managers

Find employees who earn more than their managers using self-join.

  • Self-join: SELECT e.name FROM employees e JOIN employees m ON e.manager_id = m.id WHERE e.salary > m.salary
  • Subquery: SELECT name FROM employees e WHERE salary > (SELECT salary FROM employees WHERE id = e.manager_id)
  • Complexity: O(n log n)
sql
-- Spatial Data in SQL (MySQL 5.7+)
-- Spatial data types and functions

-- Create table with spatial column
CREATE TABLE locations (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    coordinates POINT NOT NULL,
    SPATIAL INDEX idx_coords (coordinates)
);

-- Insert spatial data
INSERT INTO locations (name, coordinates) VALUES
    ('Central Park', ST_PointFromText('POINT(-73.9654 40.7829)')),
    ('Times Square', ST_PointFromText('POINT(-73.9855 40.7580)')),
    ('Empire State', ST_PointFromText('POINT(-73.9857 40.7484)'));

-- Create polygon
CREATE TABLE areas (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    boundary POLYGON NOT NULL,
    SPATIAL INDEX idx_boundary (boundary)
);

INSERT INTO areas (name, boundary) VALUES
    ('Manhattan', ST_PolygonFromText('POLYGON((-74.05 40.70, -73.90 40.70, -73.90 40.80, -74.05 40.80, -74.05 40.70))'));

-- Spatial queries
-- ST_Distance
SELECT 
    name,
    ST_Distance(coordinates, ST_PointFromText('POINT(-73.97 40.76)')) AS distance
FROM locations
ORDER BY distance;

-- ST_Within
SELECT 
    l.name AS location,
    a.name AS area
FROM locations l, areas a
WHERE ST_Within(l.coordinates, a.boundary);

-- ST_Contains
SELECT 
    a.name AS area,
    COUNT(*) AS location_count
FROM areas a, locations l
WHERE ST_Contains(a.boundary, l.coordinates)
GROUP BY a.id;

-- ST_Buffer
SELECT 
    name,
    ST_AsText(ST_Buffer(coordinates, 0.01)) AS buffer
FROM locations;

-- ST_Intersects
SELECT 
    l1.name AS point1,
    l2.name AS point2,
    ST_Distance(l1.coordinates, l2.coordinates) AS distance
FROM locations l1, locations l2
WHERE l1.id < l2.id
AND ST_Distance(l1.coordinates, l2.coordinates) < 0.01;

-- ST_Area
SELECT 
    name,
    ST_Area(boundary) AS area_sq_degrees
FROM areas;

-- ST_Centroid
SELECT 
    name,
    ST_AsText(ST_Centroid(boundary)) AS centroid
FROM areas;
Coding Round
36. Find employees in department with highest average salary

Find employees in the department with the highest average salary.

  • Subquery: SELECT * FROM employees WHERE department_id = (SELECT department_id FROM employees GROUP BY department_id ORDER BY AVG(salary) DESC LIMIT 1)
  • CTE: WITH dept_avg AS (SELECT department_id, AVG(salary) as avg_sal FROM employees GROUP BY department_id) SELECT e.* FROM employees e JOIN dept_avg d ON e.department_id = d.department_id WHERE d.avg_sal = (SELECT MAX(avg_sal) FROM dept_avg)
  • Complexity: O(n)
sql
-- Generated Columns in SQL
-- Virtual and stored generated columns

-- Stored generated column
CREATE TABLE sales (
    id INT PRIMARY KEY AUTO_INCREMENT,
    quantity INT NOT NULL,
    unit_price DECIMAL(10,2) NOT NULL,
    total_price DECIMAL(10,2) GENERATED ALWAYS AS (quantity * unit_price) STORED
);

-- Virtual generated column
CREATE TABLE employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(100),
    last_name VARCHAR(100),
    full_name VARCHAR(200) GENERATED ALWAYS AS (CONCAT(first_name, ' ', last_name)) VIRTUAL
);

-- Generated column with complex expression
CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    subtotal DECIMAL(10,2),
    tax_rate DECIMAL(5,2) DEFAULT 10.00,
    tax_amount DECIMAL(10,2) GENERATED ALWAYS AS (subtotal * tax_rate / 100) STORED,
    total DECIMAL(10,2) GENERATED ALWAYS AS (subtotal + (subtotal * tax_rate / 100)) STORED
);

-- Generated column with conditional logic
CREATE TABLE products (
    id INT PRIMARY KEY AUTO_INCREMENT,
    price DECIMAL(10,2),
    discount_percent DECIMAL(5,2) DEFAULT 0,
    discounted_price DECIMAL(10,2) GENERATED ALWAYS AS (
        CASE 
            WHEN discount_percent > 0 THEN price * (1 - discount_percent / 100)
            ELSE price
        END
    ) STORED
);

-- Index on generated column
CREATE INDEX idx_discounted_price ON products(discounted_price);

-- Generated column with JSON data
CREATE TABLE json_users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_data JSON,
    user_name VARCHAR(100) GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(user_data, '$.name'))) STORED,
    user_age INT GENERATED ALWAYS AS (JSON_EXTRACT(user_data, '$.age')) VIRTUAL
);

-- Insert into generated column
INSERT INTO sales (quantity, unit_price) VALUES (5, 10.00);
INSERT INTO employees (first_name, last_name) VALUES ('John', 'Doe');
INSERT INTO json_users (user_data) VALUES ('{"name": "Alice", "age": 25}');

-- Select generated columns
SELECT * FROM sales;
SELECT full_name FROM employees;
SELECT user_name, user_age FROM json_users;
Coding Round
37. Cumulative sum

Calculate cumulative sum using window functions or self-join.

  • Window function: SELECT id, amount, SUM(amount) OVER (ORDER BY id) as cumulative_sum FROM transactions
  • Self-join: SELECT a.id, a.amount, SUM(b.amount) as cumulative_sum FROM transactions a JOIN transactions b ON b.id <= a.id GROUP BY a.id, a.amount
  • Complexity: O(n log n)
sql
-- Views with Check Option in SQL
-- Updatable views with check option

-- Basic view with check option
CREATE VIEW active_users AS 
SELECT id, name, email, status
FROM users
WHERE status = 'active'
WITH CHECK OPTION;

-- Insert through view
INSERT INTO active_users (name, email, status) 
VALUES ('Alice', 'alice@example.com', 'active');  -- Works

-- This will fail (status not active)
INSERT INTO active_users (name, email, status) 
VALUES ('Bob', 'bob@example.com', 'inactive');  -- Fails

-- View with cascade check option
CREATE VIEW nyc_users AS 
SELECT id, name, city, status
FROM active_users
WHERE city = 'NYC'
WITH CASCADED CHECK OPTION;

-- View with local check option
CREATE VIEW la_users AS 
SELECT id, name, city, status
FROM active_users
WHERE city = 'LA'
WITH LOCAL CHECK OPTION;

-- View with no check option
CREATE VIEW all_users AS 
SELECT id, name, email, status, city
FROM users
WHERE status = 'active';

-- Insert into no-check view
INSERT INTO all_users (name, email, status, city) 
VALUES ('Bob', 'bob@example.com', 'inactive', 'LA');

-- Update view with check option
UPDATE active_users SET status = 'inactive' WHERE id = 1;  -- Fails
UPDATE active_users SET status = 'active' WHERE id = 1;  -- Works

-- View check option restrictions
-- Views with JOIN, GROUP BY, DISTINCT, UNION, subqueries cannot be updatable

-- Check if view is updatable
SELECT 
    TABLE_NAME,
    IS_UPDATABLE
FROM INFORMATION_SCHEMA.VIEWS
WHERE TABLE_SCHEMA = 'database_name';
Coding Round
38. Moving average

Calculate moving average over a window of rows.

  • Window function: SELECT date, amount, AVG(amount) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) as moving_avg FROM sales
  • Self-join: SELECT a.date, a.amount, AVG(b.amount) as moving_avg FROM sales a JOIN sales b ON b.date BETWEEN DATE_SUB(a.date, INTERVAL 2 DAY) AND a.date GROUP BY a.date, a.amount
  • Complexity: O(n log n)
sql
-- Temporary Tables in SQL
-- Temporary tables for session-specific data

-- Create temporary table
CREATE TEMPORARY TABLE temp_users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    age INT
);

-- Insert data
INSERT INTO temp_users (name, age) VALUES 
    ('Alice', 25),
    ('Bob', 30);

-- Query temporary table
SELECT * FROM temp_users;

-- Temporary table with SELECT
CREATE TEMPORARY TABLE temp_active_users
SELECT * FROM users WHERE status = 'active';

-- Temporary table with indexes
CREATE TEMPORARY TABLE temp_orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT,
    total DECIMAL(10,2),
    INDEX idx_user (user_id)
);

-- Temporary table with ENGINE option
CREATE TEMPORARY TABLE temp_memory (
    id INT PRIMARY KEY,
    data VARCHAR(100)
) ENGINE = MEMORY;

-- Temporary table with ON COMMIT DELETE ROWS
CREATE TEMPORARY TABLE temp_sessions (
    session_id VARCHAR(255),
    data TEXT
) ON COMMIT DELETE ROWS;

-- Drop temporary table
DROP TEMPORARY TABLE temp_users;
DROP TEMPORARY TABLE IF EXISTS temp_users;

-- Check if table is temporary
SELECT 
    TABLE_NAME,
    TABLE_TYPE
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'database_name'
AND TABLE_TYPE = 'TEMPORARY';

-- Using temporary table for complex query
CREATE TEMPORARY TABLE temp_high_spenders
SELECT 
    user_id,
    SUM(total) AS total_spent
FROM orders
GROUP BY user_id
HAVING total_spent > 1000;

SELECT 
    u.name,
    u.email,
    t.total_spent
FROM users u
JOIN temp_high_spenders t ON u.id = t.user_id
ORDER BY t.total_spent DESC;

-- Temporary table for pagination
CREATE TEMPORARY TABLE temp_page
SELECT * FROM users
ORDER BY name
LIMIT 10 OFFSET 20;

-- Clean up
DROP TEMPORARY TABLE temp_high_spenders;
DROP TEMPORARY TABLE temp_page;
Coding Round
39. Pivot table

Create a pivot table using conditional aggregation.

  • CASE with SUM: SELECT product, SUM(CASE WHEN month = 'Jan' THEN sales ELSE 0 END) as Jan, SUM(CASE WHEN month = 'Feb' THEN sales ELSE 0 END) as Feb FROM sales GROUP BY product
  • IF with SUM: SELECT product, SUM(IF(month = 'Jan', sales, 0)) as Jan, SUM(IF(month = 'Feb', sales, 0)) as Feb FROM sales GROUP BY product
  • Complexity: O(n)
sql
-- Character Sets and Collations in SQL
-- Character set and collation management

-- Show character sets
SHOW CHARACTER SET;
SHOW CHARSET;

-- Show collations
SHOW COLLATION;
SHOW COLLATION LIKE 'utf8%';

-- Set character set for database
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Set character set for table
CREATE TABLE mytable (
    id INT PRIMARY KEY,
    name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Set character set for column
ALTER TABLE users MODIFY name VARCHAR(100) CHARACTER SET utf8mb4;

-- Convert table character set
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Convert column character set
ALTER TABLE users MODIFY name VARCHAR(100) CHARACTER SET latin1;

-- Set session character set
SET NAMES 'utf8mb4';
SET CHARACTER SET utf8mb4;

-- Set global character set
SET GLOBAL character_set_server = 'utf8mb4';
SET GLOBAL collation_server = 'utf8mb4_unicode_ci';

-- Check character sets
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';

-- Compare strings with different collations
SELECT 'abc' = 'ABC' COLLATE utf8mb4_unicode_ci;  -- 1
SELECT 'abc' = 'ABC' COLLATE utf8mb4_bin;         -- 0

-- Use specific collation in query
SELECT * FROM users 
WHERE name = 'Alice' COLLATE utf8mb4_unicode_ci;

-- Unicode vs non-unicode
-- utf8mb4 supports all Unicode characters (including emoji)
CREATE TABLE messages (
    id INT PRIMARY KEY,
    content VARCHAR(255) CHARACTER SET utf8mb4
);

INSERT INTO messages (content) VALUES ('Hello 😊');
Coding Round
40. Get top N records per group

Get top N records per group using window functions or correlated subqueries.

  • Window function: WITH ranked AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) as rn FROM employees) SELECT * FROM ranked WHERE rn <= 3
  • Correlated subquery: SELECT * FROM employees e WHERE (SELECT COUNT(*) FROM employees WHERE department_id = e.department_id AND salary > e.salary) < 3
  • Complexity: O(n log n)
sql
-- Information Schema in SQL
-- Querying metadata

-- List all databases
SELECT * FROM INFORMATION_SCHEMA.SCHEMATA;

-- List all tables in database
SELECT 
    TABLE_NAME,
    TABLE_TYPE,
    ENGINE,
    ROW_FORMAT,
    TABLE_ROWS,
    DATA_LENGTH,
    INDEX_LENGTH
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'database_name';

-- List all columns in table
SELECT 
    COLUMN_NAME,
    DATA_TYPE,
    IS_NULLABLE,
    COLUMN_DEFAULT,
    CHARACTER_MAXIMUM_LENGTH,
    NUMERIC_PRECISION,
    COLUMN_KEY,
    EXTRA
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'database_name'
AND TABLE_NAME = 'users';

-- List indexes
SELECT * FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'database_name'
AND TABLE_NAME = 'users';

-- List foreign keys
SELECT 
    CONSTRAINT_NAME,
    TABLE_NAME,
    COLUMN_NAME,
    REFERENCED_TABLE_NAME,
    REFERENCED_COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = 'database_name'
AND REFERENCED_TABLE_NAME IS NOT NULL;

-- List views
SELECT 
    TABLE_NAME,
    VIEW_DEFINITION,
    CHECK_OPTION,
    IS_UPDATABLE
FROM INFORMATION_SCHEMA.VIEWS
WHERE TABLE_SCHEMA = 'database_name';

-- List privileges
SELECT * FROM INFORMATION_SCHEMA.USER_PRIVILEGES
WHERE GRANTEE LIKE '%app_user%';

-- Table sizes
SELECT 
    TABLE_NAME,
    ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS size_mb
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'database_name'
ORDER BY size_mb DESC;

-- Query optimizer statistics
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;

-- InnoDB metrics
SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS;

-- Show process list
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
Coding Round
41. Find missing IDs

Find missing IDs in a sequence using recursive CTE or self-join.

  • Recursive CTE: WITH RECURSIVE numbers(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM numbers WHERE n < (SELECT MAX(id) FROM table)) SELECT n FROM numbers WHERE n NOT IN (SELECT id FROM table)
  • Self-join: SELECT t1.id + 1 as missing_id FROM table t1 LEFT JOIN table t2 ON t2.id = t1.id + 1 WHERE t2.id IS NULL AND t1.id < (SELECT MAX(id) FROM table)
  • Complexity: O(n)
sql
-- Find maximum salary
SELECT MAX(salary) AS max_salary FROM employees;

-- Find employee with max salary
SELECT * FROM employees 
WHERE salary = (SELECT MAX(salary) FROM employees);

-- Using ORDER BY with LIMIT
SELECT * FROM employees 
ORDER BY salary DESC 
LIMIT 1;
Coding Round
42. Find consecutive days

Find consecutive days of activity using window functions.

  • ROW_NUMBER: WITH numbered AS (SELECT date, ROW_NUMBER() OVER (ORDER BY date) as rn FROM activities) SELECT MIN(date) as start_date, MAX(date) as end_date, COUNT(*) as days FROM (SELECT date, rn - DATEDIFF(date, (SELECT MIN(date) FROM activities)) as grp FROM numbered) grouped GROUP BY grp HAVING COUNT(*) >= 3
  • Complexity: O(n log n)
sql
-- Find second highest salary
-- Using LIMIT with OFFSET
SELECT DISTINCT salary 
FROM employees 
ORDER BY salary DESC 
LIMIT 1 OFFSET 1;

-- Using subquery
SELECT MAX(salary) 
FROM employees 
WHERE salary < (SELECT MAX(salary) FROM employees);

-- Using window function (MySQL 8.0+)
SELECT DISTINCT salary 
FROM (
    SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk 
    FROM employees
) t 
WHERE rnk = 2;
Coding Round
43. Find overlapping intervals

Find overlapping time intervals using self-join.

  • Self-join: SELECT a.id as interval1, b.id as interval2 FROM intervals a JOIN intervals b ON a.id < b.id AND a.start < b.end AND a.end > b.start
  • Complexity: O(n²)
sql
-- Find duplicate emails
SELECT email, COUNT(*) AS count
FROM users
GROUP BY email
HAVING COUNT(*) > 1;

-- Find duplicate emails with IDs
SELECT u1.id, u1.email
FROM users u1
JOIN users u2 ON u1.email = u2.email AND u1.id != u2.id
ORDER BY u1.email;
Coding Round
44. Recursive hierarchy

Traverse hierarchical data using recursive CTE.

  • Recursive CTE: WITH RECURSIVE org_tree(id, name, manager_id, level) AS (SELECT id, name, manager_id, 0 FROM employees WHERE manager_id IS NULL UNION ALL SELECT e.id, e.name, e.manager_id, ot.level + 1 FROM employees e JOIN org_tree ot ON e.manager_id = ot.id) SELECT * FROM org_tree ORDER BY level, id
  • Complexity: O(n)
sql
-- Delete duplicates keeping the lowest ID
DELETE u1 
FROM users u1
JOIN users u2 ON u1.email = u2.email AND u1.id > u2.id;

-- Using subquery
DELETE FROM users 
WHERE id NOT IN (
    SELECT MIN(id) 
    FROM users 
    GROUP BY email
);

-- Using CTE (MySQL 8.0+)
WITH ranked AS (
    SELECT id, ROW_NUMBER() OVER (PARTITION BY email ORDER BY id) AS rn
    FROM users
)
DELETE FROM users 
WHERE id IN (SELECT id FROM ranked WHERE rn > 1);
Coding Round
45. Find department with highest salary

Find department with highest average or total salary.

  • GROUP BY: SELECT department_id, AVG(salary) as avg_salary FROM employees GROUP BY department_id ORDER BY avg_salary DESC LIMIT 1
  • Subquery: SELECT department_id, AVG(salary) as avg_salary FROM employees GROUP BY department_id HAVING AVG(salary) = (SELECT MAX(avg_salary) FROM (SELECT AVG(salary) as avg_salary FROM employees GROUP BY department_id) t)
  • Complexity: O(n)
sql
-- Find employees earning more than their managers
SELECT e.name AS employee, e.salary AS emp_salary, 
       m.name AS manager, m.salary AS mgr_salary
FROM employees e
JOIN employees m ON e.manager_id = m.id
WHERE e.salary > m.salary;

-- Using subquery
SELECT name, salary
FROM employees e
WHERE salary > (SELECT salary FROM employees WHERE id = e.manager_id);
Coding Round
46. Percentage contribution

Calculate percentage contribution of each item to the total.

  • Window function: SELECT category, amount, (amount / SUM(amount) OVER ()) * 100 as percentage FROM sales
  • Subquery: SELECT category, amount, (amount / (SELECT SUM(amount) FROM sales)) * 100 as percentage FROM sales
  • Complexity: O(n)
sql
-- Find employees in department with highest average salary
SELECT e.*
FROM employees e
WHERE e.department_id = (
    SELECT department_id
    FROM employees
    GROUP BY department_id
    ORDER BY AVG(salary) DESC
    LIMIT 1
);

-- Using CTE (MySQL 8.0+)
WITH dept_avg AS (
    SELECT department_id, AVG(salary) AS avg_sal
    FROM employees
    GROUP BY department_id
)
SELECT e.*
FROM employees e
JOIN dept_avg d ON e.department_id = d.department_id
WHERE d.avg_sal = (SELECT MAX(avg_sal) FROM dept_avg);
Coding Round
47. Running total per category

Calculate running total per category using window function.

  • Window function: SELECT category, date, amount, SUM(amount) OVER (PARTITION BY category ORDER BY date) as running_total FROM sales
  • Complexity: O(n log n)
sql
-- Cumulative sum using window function (MySQL 8.0+)
SELECT 
    id,
    amount,
    SUM(amount) OVER (ORDER BY id) AS cumulative_sum
FROM transactions;

-- Cumulative sum using self-join
SELECT 
    a.id,
    a.amount,
    SUM(b.amount) AS cumulative_sum
FROM transactions a
JOIN transactions b ON b.id <= a.id
GROUP BY a.id, a.amount
ORDER BY a.id;
Coding Round
48. Find islands of data

Find groups of consecutive records (islands) using window functions.

  • ROW_NUMBER: WITH numbered AS (SELECT *, ROW_NUMBER() OVER (ORDER BY date) as rn FROM activities), grouped AS (SELECT *, rn - ROW_NUMBER() OVER (ORDER BY date) as grp FROM numbered) SELECT MIN(date) as start, MAX(date) as end, COUNT(*) as days FROM grouped GROUP BY grp HAVING COUNT(*) > 1
  • Complexity: O(n log n)
sql
-- Moving average (MySQL 8.0+)
SELECT 
    date,
    amount,
    AVG(amount) OVER (
        ORDER BY date 
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS moving_avg_3
FROM sales;

-- Moving average using self-join
SELECT 
    a.date,
    a.amount,
    AVG(b.amount) AS moving_avg_3
FROM sales a
JOIN sales b ON b.date BETWEEN DATE_SUB(a.date, INTERVAL 2 DAY) AND a.date
GROUP BY a.date, a.amount
ORDER BY a.date;
Coding Round
49. Gap analysis

Find gaps in sequences using window functions.

  • LAG: WITH numbered AS (SELECT id, LAG(id) OVER (ORDER BY id) as prev_id FROM table) SELECT prev_id + 1 as gap_start, id - 1 as gap_end FROM numbered WHERE id > prev_id + 1
  • Complexity: O(n log n)
sql
-- Pivot table using CASE
SELECT 
    product,
    SUM(CASE WHEN month = 'Jan' THEN sales ELSE 0 END) AS Jan,
    SUM(CASE WHEN month = 'Feb' THEN sales ELSE 0 END) AS Feb,
    SUM(CASE WHEN month = 'Mar' THEN sales ELSE 0 END) AS Mar
FROM sales_data
GROUP BY product;

-- Using IF function
SELECT 
    product,
    SUM(IF(month = 'Jan', sales, 0)) AS Jan,
    SUM(IF(month = 'Feb', sales, 0)) AS Feb,
    SUM(IF(month = 'Mar', sales, 0)) AS Mar
FROM sales_data
GROUP BY product;
Coding Round
50. Mode (most frequent value)

Find the most frequent value using GROUP BY and ORDER BY.

  • GROUP BY: SELECT column, COUNT(*) as count FROM table GROUP BY column ORDER BY count DESC LIMIT 1
  • Subquery: SELECT column FROM table GROUP BY column HAVING COUNT(*) = (SELECT MAX(count) FROM (SELECT COUNT(*) as count FROM table GROUP BY column) t)
  • Complexity: O(n log n)
sql
-- Top 3 employees per department (MySQL 8.0+)
WITH ranked AS (
    SELECT 
        *,
        ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn
    FROM employees
)
SELECT * FROM ranked WHERE rn <= 3;

-- Using correlated subquery
SELECT *
FROM employees e
WHERE (
    SELECT COUNT(*) 
    FROM employees 
    WHERE department_id = e.department_id AND salary > e.salary
) < 3;
Coding Round
51. Median

Find the median value using window functions or subqueries.

  • PERCENTILE_CONT: SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary) OVER () as median FROM employees LIMIT 1
  • NTILE: SELECT AVG(salary) as median FROM (SELECT salary, NTILE(2) OVER (ORDER BY salary) as tile FROM employees) t WHERE tile = 1 OR tile = 2 GROUP BY tile
  • Complexity: O(n log n)
sql
-- Find missing IDs using recursive CTE (MySQL 8.0+)
WITH RECURSIVE numbers(n) AS (
    SELECT 1
    UNION ALL
    SELECT n + 1 FROM numbers WHERE n < (SELECT MAX(id) FROM mytable)
)
SELECT n AS missing_id
FROM numbers
WHERE n NOT IN (SELECT id FROM mytable);

-- Using self-join
SELECT t1.id + 1 AS missing_id
FROM mytable t1
LEFT JOIN mytable t2 ON t2.id = t1.id + 1
WHERE t2.id IS NULL
AND t1.id < (SELECT MAX(id) FROM mytable);
Coding Round
52. N-th highest salary

Find the N-th highest salary using LIMIT or window functions.

  • LIMIT: SELECT DISTINCT salary FROM employees ORDER BY salary DESC LIMIT N-1, 1
  • DENSE_RANK: WITH ranked AS (SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) as rnk FROM employees) SELECT DISTINCT salary FROM ranked WHERE rnk = N
  • Complexity: O(n log n)
sql
-- Find consecutive days of activity (MySQL 8.0+)
WITH numbered AS (
    SELECT 
        date,
        ROW_NUMBER() OVER (ORDER BY date) AS rn
    FROM activities
),
grouped AS (
    SELECT 
        date,
        rn - DATEDIFF(date, (SELECT MIN(date) FROM activities)) AS grp
    FROM numbered
)
SELECT 
    MIN(date) AS start_date,
    MAX(date) AS end_date,
    COUNT(*) AS days
FROM grouped
GROUP BY grp
HAVING COUNT(*) >= 3
ORDER BY start_date;
Coding Round
53. Cumulative distribution

Calculate cumulative distribution using window functions.

  • CUME_DIST: SELECT value, CUME_DIST() OVER (ORDER BY value) as cume_dist FROM table
  • PERCENT_RANK: SELECT value, PERCENT_RANK() OVER (ORDER BY value) as percent_rank FROM table
  • Complexity: O(n log n)
sql
-- Find overlapping intervals
SELECT 
    a.id AS interval1,
    b.id AS interval2,
    a.start_date AS start1,
    a.end_date AS end1,
    b.start_date AS start2,
    b.end_date AS end2
FROM intervals a
JOIN intervals b ON a.id < b.id
WHERE a.start_date < b.end_date 
  AND a.end_date > b.start_date;
Coding Round
54. First and last value

Get first and last values in a group using window functions.

  • FIRST_VALUE: SELECT category, FIRST_VALUE(value) OVER (PARTITION BY category ORDER BY date) as first_value FROM table
  • LAST_VALUE: SELECT category, LAST_VALUE(value) OVER (PARTITION BY category ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as last_value FROM table
  • Complexity: O(n log n)
sql
-- Recursive hierarchy (MySQL 8.0+)
WITH RECURSIVE org_tree AS (
    -- Anchor: top-level employees
    SELECT 
        id,
        name,
        manager_id,
        0 AS level,
        CAST(name AS CHAR(200)) AS path
    FROM employees
    WHERE manager_id IS NULL
    
    UNION ALL
    
    -- Recursive: children
    SELECT 
        e.id,
        e.name,
        e.manager_id,
        ot.level + 1,
        CONCAT(ot.path, ' -> ', e.name)
    FROM employees e
    JOIN org_tree ot ON e.manager_id = ot.id
)
SELECT 
    CONCAT(REPEAT('  ', level), name) AS org_chart,
    level,
    path
FROM org_tree
ORDER BY path;
Coding Round
55. Lead and lag

Get previous and next row values using LAG and LEAD.

  • LAG: SELECT date, amount, LAG(amount, 1) OVER (ORDER BY date) as previous_amount FROM sales
  • LEAD: SELECT date, amount, LEAD(amount, 1) OVER (ORDER BY date) as next_amount FROM sales
  • Complexity: O(n log n)
sql
-- Department with highest average salary
SELECT 
    department_id,
    AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
ORDER BY avg_salary DESC
LIMIT 1;

-- Using subquery
SELECT 
    department_id,
    AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
    SELECT MAX(avg_salary)
    FROM (SELECT AVG(salary) AS avg_salary FROM employees GROUP BY department_id) t
);
Coding Round
56. Difference between current and previous

Calculate difference between current and previous row using LAG.

  • LAG: SELECT date, amount, amount - LAG(amount, 1) OVER (ORDER BY date) as difference FROM sales
  • Self-join: SELECT a.date, a.amount - b.amount as difference FROM sales a JOIN sales b ON b.date = (SELECT MAX(date) FROM sales WHERE date < a.date)
  • Complexity: O(n log n)
sql
-- Percentage contribution (MySQL 8.0+)
SELECT 
    category,
    amount,
    (amount / SUM(amount) OVER ()) * 100 AS percentage
FROM sales;

-- Using subquery
SELECT 
    category,
    amount,
    (amount / (SELECT SUM(amount) FROM sales)) * 100 AS percentage
FROM sales;

-- Percentage with grouping
SELECT 
    category,
    amount,
    (amount / SUM(amount) OVER (PARTITION BY category)) * 100 AS percentage_in_category
FROM sales;
Coding Round
57. Percentage change

Calculate percentage change between current and previous row.

  • LAG: SELECT date, amount, ((amount - LAG(amount, 1) OVER (ORDER BY date)) / LAG(amount, 1) OVER (ORDER BY date)) * 100 as pct_change FROM sales
  • Self-join: SELECT a.date, ((a.amount - b.amount) / b.amount) * 100 as pct_change FROM sales a JOIN sales b ON b.date = (SELECT MAX(date) FROM sales WHERE date < a.date)
  • Complexity: O(n log n)
sql
-- Running total per category (MySQL 8.0+)
SELECT 
    category,
    date,
    amount,
    SUM(amount) OVER (PARTITION BY category ORDER BY date) AS running_total
FROM sales
ORDER BY category, date;

-- Running total using self-join
SELECT 
    a.category,
    a.date,
    a.amount,
    SUM(b.amount) AS running_total
FROM sales a
JOIN sales b ON a.category = b.category AND b.date <= a.date
GROUP BY a.category, a.date, a.amount
ORDER BY a.category, a.date;
Coding Round
58. Year-over-year comparison

Compare values with the same period in the previous year.

  • LAG with INTERVAL: SELECT date, amount, LAG(amount, 12) OVER (ORDER BY date) as same_period_previous_year FROM monthly_sales
  • Self-join: SELECT a.date, a.amount - b.amount as yoy_change FROM sales a JOIN sales b ON YEAR(a.date) = YEAR(b.date) + 1 AND MONTH(a.date) = MONTH(b.date)
  • Complexity: O(n log n)
sql
-- Find islands of data (MySQL 8.0+)
WITH numbered AS (
    SELECT 
        date,
        ROW_NUMBER() OVER (ORDER BY date) AS rn
    FROM activities
),
grouped AS (
    SELECT 
        date,
        rn - ROW_NUMBER() OVER (ORDER BY date) AS grp
    FROM numbered
)
SELECT 
    MIN(date) AS start_date,
    MAX(date) AS end_date,
    COUNT(*) AS days
FROM grouped
GROUP BY grp
HAVING COUNT(*) > 1
ORDER BY start_date;
Coding Round
59. Rolling sum

Calculate rolling sum over a window.

  • Window function: SELECT date, amount, SUM(amount) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as rolling_7day_sum FROM daily_sales
  • Complexity: O(n log n)
sql
-- Gap analysis using LAG (MySQL 8.0+)
WITH numbered AS (
    SELECT 
        id,
        LAG(id) OVER (ORDER BY id) AS prev_id
    FROM mytable
)
SELECT 
    prev_id + 1 AS gap_start,
    id - 1 AS gap_end
FROM numbered
WHERE id > prev_id + 1;

-- Gap analysis using self-join
SELECT 
    t1.id + 1 AS gap_start,
    MIN(t2.id) - 1 AS gap_end
FROM mytable t1
JOIN mytable t2 ON t2.id > t1.id
WHERE NOT EXISTS (
    SELECT 1 FROM mytable t3 
    WHERE t3.id > t1.id AND t3.id < t2.id
)
GROUP BY t1.id;
Coding Round
60. Fill missing dates

Fill missing dates in a time series using recursive CTE.

  • Recursive CTE: WITH RECURSIVE dates(dt) AS (SELECT MIN(date) FROM sales UNION ALL SELECT dt + INTERVAL 1 DAY FROM dates WHERE dt < (SELECT MAX(date) FROM sales)) SELECT d.dt, COALESCE(s.amount, 0) as amount FROM dates d LEFT JOIN sales s ON d.dt = s.date
  • Complexity: O(n)
sql
-- Mode (most frequent value)
SELECT column_name, COUNT(*) AS frequency
FROM mytable
GROUP BY column_name
ORDER BY frequency DESC
LIMIT 1;

-- Using subquery
SELECT column_name
FROM mytable
GROUP BY column_name
HAVING COUNT(*) = (
    SELECT MAX(count)
    FROM (SELECT COUNT(*) AS count FROM mytable GROUP BY column_name) t
);
Coding Round
61. Difference between dates

Calculate difference between dates using DATEDIFF or TIMESTAMPDIFF.

  • DATEDIFF: SELECT DATEDIFF(end_date, start_date) as days_diff FROM projects
  • TIMESTAMPDIFF: SELECT TIMESTAMPDIFF(DAY, start_date, end_date) as days_diff FROM projects
  • Complexity: O(1)
sql
-- Median using PERCENTILE_CONT (MySQL 8.0+)
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary) 
OVER () AS median
FROM employees
LIMIT 1;

-- Median using NTILE (MySQL 8.0+)
SELECT AVG(salary) AS median
FROM (
    SELECT 
        salary,
        NTILE(2) OVER (ORDER BY salary) AS tile
    FROM employees
) t
WHERE tile = 1 OR tile = 2
GROUP BY tile;

-- Median using user variables (older MySQL)
SELECT AVG(salary) AS median
FROM (
    SELECT salary
    FROM employees
    ORDER BY salary
    LIMIT 2 - (SELECT COUNT(*) FROM employees) % 2
    OFFSET (SELECT (COUNT(*) - 1) / 2 FROM employees)
) t;
Coding Round
62. Extract date parts

Extract year, month, day from date using YEAR, MONTH, DAY functions.

  • YEAR: SELECT YEAR(date) as year, MONTH(date) as month, DAY(date) as day FROM events
  • DATE_FORMAT: SELECT DATE_FORMAT(date, '%Y') as year, DATE_FORMAT(date, '%m') as month FROM events
  • EXTRACT: SELECT EXTRACT(YEAR FROM date) as year, EXTRACT(MONTH FROM date) as month FROM events
  • Complexity: O(1)
sql
-- Nth highest salary using LIMIT
SELECT DISTINCT salary 
FROM employees 
ORDER BY salary DESC 
LIMIT N-1, 1;

-- Nth highest using DENSE_RANK (MySQL 8.0+)
WITH ranked AS (
    SELECT 
        salary,
        DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
    FROM employees
)
SELECT DISTINCT salary
FROM ranked
WHERE rnk = N;

-- 3rd highest salary example
SELECT DISTINCT salary 
FROM employees 
ORDER BY salary DESC 
LIMIT 2, 1;
Coding Round
63. Format date

Format date using DATE_FORMAT function.

  • DATE_FORMAT: SELECT DATE_FORMAT(date, '%Y-%m-%d') as formatted_date FROM events
  • Common formats: SELECT DATE_FORMAT(date, '%M %e, %Y') as full_date FROM events
  • Complexity: O(1)
sql
-- Cumulative distribution (MySQL 8.0+)
SELECT 
    value,
    CUME_DIST() OVER (ORDER BY value) AS cume_dist,
    PERCENT_RANK() OVER (ORDER BY value) AS percent_rank
FROM mytable
ORDER BY value;

-- Manual calculation
SELECT 
    value,
    (SELECT COUNT(*) FROM mytable WHERE value <= t.value) / COUNT(*) AS cume_dist
FROM mytable t
GROUP BY value
ORDER BY value;
Coding Round
64. Date arithmetic

Add or subtract intervals from dates using DATE_ADD or DATE_SUB.

  • DATE_ADD: SELECT DATE_ADD(date, INTERVAL 1 DAY) as next_day FROM events
  • DATE_SUB: SELECT DATE_SUB(date, INTERVAL 1 MONTH) as previous_month FROM events
  • Complexity: O(1)
sql
-- First and last value in group (MySQL 8.0+)
SELECT 
    category,
    date,
    value,
    FIRST_VALUE(value) OVER (PARTITION BY category ORDER BY date) AS first_value,
    LAST_VALUE(value) OVER (
        PARTITION BY category 
        ORDER BY date 
        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
    ) AS last_value
FROM mytable
ORDER BY category, date;

-- Using subquery
SELECT 
    category,
    date,
    value,
    (SELECT value FROM mytable t2 
     WHERE t2.category = t1.category 
     ORDER BY t2.date ASC LIMIT 1) AS first_value,
    (SELECT value FROM mytable t2 
     WHERE t2.category = t1.category 
     ORDER BY t2.date DESC LIMIT 1) AS last_value
FROM mytable t1;
Coding Round
65. Current date and time

Get current date and time using NOW, CURDATE, CURTIME.

  • NOW: SELECT NOW() as current_datetime
  • CURDATE: SELECT CURDATE() as current_date
  • CURTIME: SELECT CURTIME() as current_time
  • Complexity: O(1)
sql
-- LAG and LEAD (MySQL 8.0+)
SELECT 
    date,
    amount,
    LAG(amount, 1) OVER (ORDER BY date) AS previous_amount,
    LAG(amount, 2) OVER (ORDER BY date) AS previous_2_amount,
    LEAD(amount, 1) OVER (ORDER BY date) AS next_amount,
    LEAD(amount, 2) OVER (ORDER BY date) AS next_2_amount
FROM sales
ORDER BY date;

-- LAG and LEAD with partition
SELECT 
    category,
    date,
    amount,
    LAG(amount, 1) OVER (PARTITION BY category ORDER BY date) AS prev_in_category,
    LEAD(amount, 1) OVER (PARTITION BY category ORDER BY date) AS next_in_category
FROM sales
ORDER BY category, date;
Coding Round
66. String concatenation

Concatenate strings using CONCAT or CONCAT_WS.

  • CONCAT: SELECT CONCAT(first_name, ' ', last_name) as full_name FROM users
  • CONCAT_WS: SELECT CONCAT_WS(' ', first_name, last_name) as full_name FROM users
  • Complexity: O(n)
sql
-- Difference between current and previous (MySQL 8.0+)
SELECT 
    date,
    amount,
    amount - LAG(amount, 1) OVER (ORDER BY date) AS difference,
    amount - LAG(amount, 1) OVER (ORDER BY date) AS diff_from_prev
FROM sales
ORDER BY date;

-- Using self-join
SELECT 
    a.date,
    a.amount,
    a.amount - b.amount AS difference
FROM sales a
JOIN sales b ON b.date = (
    SELECT MAX(date) 
    FROM sales 
    WHERE date < a.date
)
ORDER BY a.date;
Coding Round
67. String splitting

Split string using SUBSTRING_INDEX or JSON functions.

  • SUBSTRING_INDEX: SELECT SUBSTRING_INDEX('a,b,c', ',', 1) as first, SUBSTRING_INDEX(SUBSTRING_INDEX('a,b,c', ',', -1), ',', 1) as second
  • JSON: SELECT JSON_EXTRACT('["a","b","c"]', '$[0]') as first, JSON_EXTRACT('["a","b","c"]', '$[1]') as second
  • Complexity: O(n)
sql
-- Percentage change (MySQL 8.0+)
SELECT 
    date,
    amount,
    ((amount - LAG(amount, 1) OVER (ORDER BY date)) / 
     LAG(amount, 1) OVER (ORDER BY date)) * 100 AS pct_change
FROM sales
ORDER BY date;

-- Percentage change from previous year
SELECT 
    date,
    amount,
    ((amount - LAG(amount, 12) OVER (ORDER BY date)) / 
     LAG(amount, 12) OVER (ORDER BY date)) * 100 AS yoy_pct_change
FROM monthly_sales
ORDER BY date;
Coding Round
68. String pattern matching

Match string patterns using LIKE or REGEXP.

  • LIKE: SELECT * FROM users WHERE email LIKE '%@example.com'
  • REGEXP: SELECT * FROM users WHERE email REGEXP '^[a-z]+@[a-z]+\.[a-z]+$'
  • RLIKE: SELECT * FROM users WHERE email RLIKE '^[a-zA-Z]+@[a-zA-Z]+\.[a-zA-Z]+$'
  • Complexity: O(n)
sql
-- Year-over-year comparison
SELECT 
    YEAR(date) AS year,
    MONTH(date) AS month,
    amount,
    LAG(amount, 12) OVER (ORDER BY date) AS same_month_last_year,
    amount - LAG(amount, 12) OVER (ORDER BY date) AS yoy_change,
    ((amount - LAG(amount, 12) OVER (ORDER BY date)) / 
     LAG(amount, 12) OVER (ORDER BY date)) * 100 AS yoy_pct_change
FROM monthly_sales
ORDER BY date;
Coding Round
69. Substring extraction

Extract substring using SUBSTR or LEFT/RIGHT.

  • SUBSTR: SELECT SUBSTR('Hello World', 1, 5) as first_word
  • LEFT: SELECT LEFT('Hello World', 5) as first_word
  • RIGHT: SELECT RIGHT('Hello World', 5) as last_word
  • Complexity: O(n)
sql
-- Rolling sum (MySQL 8.0+)
SELECT 
    date,
    amount,
    SUM(amount) OVER (
        ORDER BY date 
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) AS rolling_7day_sum,
    AVG(amount) OVER (
        ORDER BY date 
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) AS rolling_7day_avg
FROM daily_sales
ORDER BY date;

-- Rolling sum with partition
SELECT 
    category,
    date,
    amount,
    SUM(amount) OVER (
        PARTITION BY category
        ORDER BY date 
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) AS rolling_7day_sum_category
FROM daily_sales
ORDER BY category, date;
Coding Round
70. Case conversion

Convert case using UPPER, LOWER, or INITCAP (SQL 8.0+).

  • UPPER: SELECT UPPER('hello') as upper_string
  • LOWER: SELECT LOWER('HELLO') as lower_string
  • INITCAP: SELECT INITCAP('hello world') as title_case
  • Complexity: O(n)
sql
-- Fill missing dates (MySQL 8.0+)
WITH RECURSIVE dates(dt) AS (
    SELECT MIN(date) FROM sales
    UNION ALL
    SELECT dt + INTERVAL 1 DAY
    FROM dates
    WHERE dt < (SELECT MAX(date) FROM sales)
)
SELECT 
    d.dt AS date,
    COALESCE(s.amount, 0) AS amount
FROM dates d
LEFT JOIN sales s ON d.dt = s.date
ORDER BY d.dt;

-- Fill missing dates with previous value
WITH RECURSIVE dates(dt) AS (
    SELECT MIN(date) FROM sales
    UNION ALL
    SELECT dt + INTERVAL 1 DAY
    FROM dates
    WHERE dt < (SELECT MAX(date) FROM sales)
),
filled AS (
    SELECT 
        d.dt AS date,
        s.amount,
        @prev_amount := COALESCE(s.amount, @prev_amount) AS filled_amount
    FROM dates d
    LEFT JOIN sales s ON d.dt = s.date
    CROSS JOIN (SELECT @prev_amount := 0) init
)
SELECT date, filled_amount AS amount
FROM filled;
Coding Round
71. String cleaning

Clean strings using TRIM, RTRIM, LTRIM.

  • TRIM: SELECT TRIM(' hello ') as trimmed
  • LTRIM: SELECT LTRIM(' hello') as left_trimmed
  • RTRIM: SELECT RTRIM('hello ') as right_trimmed
  • Complexity: O(n)
sql
-- Difference between dates
SELECT 
    start_date,
    end_date,
    DATEDIFF(end_date, start_date) AS days_diff,
    TIMESTAMPDIFF(DAY, start_date, end_date) AS days_diff_2,
    TIMESTAMPDIFF(MONTH, start_date, end_date) AS months_diff,
    TIMESTAMPDIFF(YEAR, start_date, end_date) AS years_diff
FROM projects;

-- Difference from current date
SELECT 
    start_date,
    DATEDIFF(CURDATE(), start_date) AS days_since_start,
    TIMESTAMPDIFF(DAY, start_date, CURDATE()) AS days_since_start_2
FROM projects;
Coding Round
72. Replace in string

Replace substrings using REPLACE or REGEXP_REPLACE.

  • REPLACE: SELECT REPLACE('Hello World', 'World', 'SQL') as replaced
  • REGEXP_REPLACE: SELECT REGEXP_REPLACE('Hello 123 World', '[0-9]+', '') as cleaned
  • Complexity: O(n)
sql
-- Extract date parts
SELECT 
    date_col,
    YEAR(date_col) AS year,
    MONTH(date_col) AS month,
    DAY(date_col) AS day,
    HOUR(date_col) AS hour,
    MINUTE(date_col) AS minute,
    SECOND(date_col) AS second,
    WEEK(date_col) AS week,
    QUARTER(date_col) AS quarter,
    DAYOFWEEK(date_col) AS day_of_week,
    DAYOFYEAR(date_col) AS day_of_year,
    WEEKDAY(date_col) AS weekday_index
FROM events;

-- Using DATE_FORMAT
SELECT 
    date_col,
    DATE_FORMAT(date_col, '%Y') AS year,
    DATE_FORMAT(date_col, '%m') AS month,
    DATE_FORMAT(date_col, '%d') AS day,
    DATE_FORMAT(date_col, '%W') AS day_name,
    DATE_FORMAT(date_col, '%M') AS month_name
FROM events;
Coding Round
73. String length

Get string length using LENGTH or CHAR_LENGTH.

  • LENGTH: SELECT LENGTH('Hello') as bytes_length
  • CHAR_LENGTH: SELECT CHAR_LENGTH('Hello') as char_length
  • Complexity: O(1)
sql
-- Format date
SELECT 
    date_col,
    DATE_FORMAT(date_col, '%Y-%m-%d') AS yyyy_mm_dd,
    DATE_FORMAT(date_col, '%m/%d/%Y') AS mm_dd_yyyy,
    DATE_FORMAT(date_col, '%M %e, %Y') AS full_date,
    DATE_FORMAT(date_col, '%W, %M %e, %Y') AS full_date_with_day,
    DATE_FORMAT(date_col, '%r') AS time_12h,
    DATE_FORMAT(date_col, '%H:%i:%s') AS time_24h,
    DATE_FORMAT(date_col, '%Y-%m-%d %H:%i:%s') AS datetime_format
FROM events;
Coding Round
74. String position

Find position of substring using LOCATE or POSITION.

  • LOCATE: SELECT LOCATE('World', 'Hello World') as position
  • POSITION: SELECT POSITION('World' IN 'Hello World') as position
  • INSTR: SELECT INSTR('Hello World', 'World') as position
  • Complexity: O(n)
sql
-- Date arithmetic
SELECT 
    date_col,
    DATE_ADD(date_col, INTERVAL 1 DAY) AS tomorrow,
    DATE_ADD(date_col, INTERVAL 1 WEEK) AS next_week,
    DATE_ADD(date_col, INTERVAL 1 MONTH) AS next_month,
    DATE_ADD(date_col, INTERVAL 1 YEAR) AS next_year,
    DATE_SUB(date_col, INTERVAL 1 DAY) AS yesterday,
    DATE_SUB(date_col, INTERVAL 1 MONTH) AS last_month,
    date_col + INTERVAL 1 DAY AS tomorrow_alt,
    date_col - INTERVAL 1 DAY AS yesterday_alt
FROM events;

-- Date arithmetic with NOW
SELECT 
    NOW() AS now,
    NOW() + INTERVAL 1 HOUR AS in_1_hour,
    NOW() - INTERVAL 1 DAY AS yesterday,
    DATE_ADD(NOW(), INTERVAL 1 HOUR) AS in_1_hour_2;
Coding Round
75. Aggregate with JSON

Use JSON functions for aggregation and data manipulation.

  • JSON_ARRAYAGG: SELECT JSON_ARRAYAGG(name) as names FROM users WHERE city = 'NYC'
  • JSON_OBJECTAGG: SELECT JSON_OBJECTAGG(id, name) as user_map FROM users
  • Complexity: O(n)
sql
-- Current date and time
SELECT 
    NOW() AS current_datetime,
    CURDATE() AS current_date,
    CURTIME() AS current_time,
    UTC_TIMESTAMP() AS utc_timestamp,
    UNIX_TIMESTAMP() AS unix_timestamp,
    CURRENT_TIMESTAMP() AS current_timestamp,
    SYSDATE() AS sysdate;

-- Date only
SELECT 
    DATE(NOW()) AS date_only,
    TIME(NOW()) AS time_only,
    YEAR(NOW()) AS current_year,
    MONTH(NOW()) AS current_month,
    DAY(NOW()) AS current_day;
Coding Round
76. JSON path queries

Query JSON data using path expressions.

  • JSON_EXTRACT: SELECT JSON_EXTRACT(data, '$.name') as name FROM users
  • ->: SELECT data->'$.name' as name FROM users
  • ->>: SELECT data->>'$.name' as name FROM users
  • Complexity: O(1)
sql
-- String concatenation
SELECT 
    CONCAT(first_name, ' ', last_name) AS full_name,
    CONCAT_WS(' ', first_name, last_name) AS full_name_ws,
    CONCAT(first_name, ' ', last_name, ' (', email, ')') AS detailed_info
FROM users;

-- Concatenation with NULL handling
SELECT 
    CONCAT(first_name, ' ', COALESCE(middle_name, ''), ' ', last_name) AS full_name,
    CONCAT_WS(' ', first_name, middle_name, last_name) AS full_name_ws
FROM users;

-- Group concatenation
SELECT 
    department_id,
    GROUP_CONCAT(name ORDER BY name SEPARATOR ', ') AS employees
FROM employees
GROUP BY department_id;
Coding Round
77. JSON array operations

Manipulate JSON arrays using JSON functions.

  • JSON_ARRAY_APPEND: SELECT JSON_ARRAY_APPEND('[1,2,3]', '$', 4) as appended
  • JSON_ARRAY_INSERT: SELECT JSON_ARRAY_INSERT('[1,2,3]', '$[1]', 99) as inserted
  • JSON_REMOVE: SELECT JSON_REMOVE('[1,2,3,4]', '$[2]') as removed
  • Complexity: O(n)
sql
-- String splitting using SUBSTRING_INDEX
SELECT 
    'a,b,c,d,e' AS original,
    SUBSTRING_INDEX('a,b,c,d,e', ',', 1) AS first,
    SUBSTRING_INDEX('a,b,c,d,e', ',', 2) AS first_two,
    SUBSTRING_INDEX('a,b,c,d,e', ',', -1) AS last,
    SUBSTRING_INDEX(SUBSTRING_INDEX('a,b,c,d,e', ',', 3), ',', -1) AS third;

-- Splitting into rows using JSON (MySQL 8.0+)
SELECT 
    JSON_EXTRACT(
        JSON_ARRAY('a', 'b', 'c', 'd', 'e'),
        CONCAT('$[', n, ']')
    ) AS element
FROM (
    SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
) numbers;
Coding Round
78. JSON table

Convert JSON to relational table using JSON_TABLE (SQL 8.0+).

  • JSON_TABLE: SELECT * FROM JSON_TABLE('[{"name":"Alice"},{"name":"Bob"}]', '$[*]' COLUMNS (name VARCHAR(100) PATH '$.name')) AS jt
  • Complexity: O(n)
sql
-- String pattern matching using LIKE
SELECT * FROM users 
WHERE email LIKE '%@example.com';

SELECT * FROM users 
WHERE name LIKE 'A%';

SELECT * FROM users 
WHERE name LIKE '%son%';

-- Using REGEXP
SELECT * FROM users 
WHERE email REGEXP '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$';

SELECT * FROM users 
WHERE name REGEXP '^[A-Z]';

SELECT * FROM users 
WHERE phone REGEXP '^[0-9]{3}-[0-9]{3}-[0-9]{4}$';

-- Using RLIKE (synonym for REGEXP)
SELECT * FROM users 
WHERE email RLIKE '^[a-z]+@[a-z]+\.[a-z]+$';
Coding Round
79. JSON validation

Validate JSON using JSON_VALID (SQL 5.7+).

  • JSON_VALID: SELECT JSON_VALID('{"name":"Alice"}') as valid, JSON_VALID('invalid') as invalid
  • Schema validation: SELECT JSON_SCHEMA_VALID('{"type":"object"}', '{"name":"Alice"}') as valid
  • Complexity: O(n)
sql
-- Substring extraction
SELECT 
    'Hello World' AS original,
    SUBSTR('Hello World', 1, 5) AS first_word,
    SUBSTRING('Hello World', 7, 5) AS second_word,
    SUBSTR('Hello World', 7) AS from_position_7,
    LEFT('Hello World', 5) AS left_5,
    RIGHT('Hello World', 5) AS right_5,
    SUBSTRING_INDEX('Hello World', ' ', 1) AS first_word_2,
    SUBSTRING_INDEX('Hello World', ' ', -1) AS last_word
FROM dual;

-- Extract from column
SELECT 
    email,
    SUBSTRING_INDEX(email, '@', 1) AS username,
    SUBSTRING_INDEX(email, '@', -1) AS domain
FROM users;
Coding Round
80. Group concat

Concatenate values from grouped rows using GROUP_CONCAT.

  • GROUP_CONCAT: SELECT department_id, GROUP_CONCAT(name ORDER BY name SEPARATOR ', ') as employees FROM employees GROUP BY department_id
  • Complexity: O(n log n)
sql
-- Case conversion
SELECT 
    UPPER('hello world') AS upper_case,
    LOWER('HELLO WORLD') AS lower_case,
    'hello world' AS original,
    UPPER(first_name) AS upper_name,
    LOWER(email) AS lower_email
FROM users;

-- INITCAP (MySQL 8.0+)
SELECT 
    INITCAP('hello world') AS title_case;

-- Custom INITCAP for older MySQL
SELECT 
    CONCAT(
        UPPER(SUBSTR('hello world', 1, 1)),
        LOWER(SUBSTR('hello world', 2))
    ) AS custom_initcap;
Coding Round
81. Generate random number

Generate random numbers using RAND or RANDOM.

  • RAND: SELECT RAND() as random, FLOOR(RAND() * 100) as random_int
  • RANDOM: SELECT RANDOM() as random
  • Complexity: O(1)
sql
-- String cleaning
SELECT 
    '  hello  ' AS original,
    TRIM('  hello  ') AS trimmed,
    LTRIM('  hello') AS left_trimmed,
    RTRIM('hello  ') AS right_trimmed,
    TRIM(LEADING ' ' FROM '  hello') AS lead_trimmed,
    TRIM(TRAILING ' ' FROM 'hello  ') AS trail_trimmed,
    TRIM(BOTH ' ' FROM '  hello  ') AS both_trimmed;

-- Trimming specific characters
SELECT 
    TRIM(LEADING 'x' FROM 'xxhelloxx') AS trim_leading_x,
    TRIM(TRAILING 'x' FROM 'xxhelloxx') AS trim_trailing_x,
    TRIM(BOTH 'x' FROM 'xxhelloxx') AS trim_both_x;
Coding Round
82. Row number

Generate row numbers using ROW_NUMBER or user variables.

  • ROW_NUMBER: SELECT *, ROW_NUMBER() OVER (ORDER BY id) as row_num FROM users
  • User variable: SELECT *, @row_num := @row_num + 1 as row_num FROM users, (SELECT @row_num := 0) r
  • Complexity: O(n log n)
sql
-- Replace in string
SELECT 
    'Hello World' AS original,
    REPLACE('Hello World', 'World', 'MySQL') AS replaced,
    REPLACE('Hello World', 'o', '0') AS replace_o;

-- REGEXP_REPLACE (MySQL 8.0+)
SELECT 
    'Hello 123 World 456' AS original,
    REGEXP_REPLACE('Hello 123 World 456', '[0-9]+', '') AS remove_numbers,
    REGEXP_REPLACE('Hello 123 World 456', '[^0-9]+', ' ') AS extract_numbers,
    REGEXP_REPLACE('Hello World', '([A-Z])', '_\1') AS add_underscore;

-- Remove multiple spaces
SELECT 
    REGEXP_REPLACE('Hello   World', '\s+', ' ') AS normalize_spaces;
Coding Round
83. Conditional aggregation

Aggregate with conditions using CASE in aggregates.

  • CASE with SUM: SELECT department, SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active_count, SUM(CASE WHEN status = 'inactive' THEN 1 ELSE 0 END) as inactive_count FROM users GROUP BY department
  • Complexity: O(n)
sql
-- String length
SELECT 
    'Hello' AS str,
    LENGTH('Hello') AS bytes_length,
    CHAR_LENGTH('Hello') AS char_length,
    CHARACTER_LENGTH('Hello') AS char_length_2;

-- Unicode strings
SELECT 
    '你好' AS unicode_str,
    LENGTH('你好') AS bytes_length_unicode,
    CHAR_LENGTH('你好') AS char_length_unicode;

-- Length of column
SELECT 
    name,
    LENGTH(name) AS byte_length,
    CHAR_LENGTH(name) AS char_length
FROM users;
Coding Round
84. Filtered aggregation

Use filtered aggregates for conditional counts.

  • FILTER: SELECT department, COUNT(*) FILTER (WHERE status = 'active') as active_count FROM users GROUP BY department
  • Complexity: O(n)
sql
-- Find position of substring
SELECT 
    'Hello World' AS str,
    LOCATE('World', 'Hello World') AS locate_position,
    POSITION('World' IN 'Hello World') AS position_function,
    INSTR('Hello World', 'World') AS instr_function,
    LOCATE('o', 'Hello World', 5) AS locate_from_position,
    LOCATE('World', 'Hello World') AS locate_position;

-- Position in column
SELECT 
    email,
    LOCATE('@', email) AS at_position,
    LOCATE('.', email) AS dot_position
FROM users;
Coding Round
85. Greatest and least

Find greatest or least value among columns using GREATEST and LEAST.

  • GREATEST: SELECT GREATEST(col1, col2, col3) as max_value FROM table
  • LEAST: SELECT LEAST(col1, col2, col3) as min_value FROM table
  • Complexity: O(1)
sql
-- JSON aggregation (MySQL 5.7+)
SELECT 
    department_id,
    JSON_ARRAYAGG(name) AS employee_names,
    JSON_OBJECTAGG(id, name) AS employee_map
FROM employees
GROUP BY department_id;

-- JSON_ARRAY with grouping
SELECT 
    city,
    JSON_ARRAYAGG(name) AS users_in_city
FROM users
GROUP BY city;

-- JSON_OBJECT with grouping
SELECT 
    department_id,
    JSON_OBJECT(
        'department', department_id,
        'employees', JSON_ARRAYAGG(name),
        'count', COUNT(*)
    ) AS department_info
FROM employees
GROUP BY department_id;
Coding Round
86. Bitwise operations

Use bitwise operators for flag manipulation.

  • Bitwise AND: SELECT flags & 1 as flag1, flags & 2 as flag2 FROM permissions
  • Bitwise OR: UPDATE permissions SET flags = flags | 4 WHERE id = 1
  • Bitwise XOR: SELECT flags ^ 4 as toggled FROM permissions
  • Complexity: O(1)
sql
-- JSON path queries
SELECT 
    JSON_EXTRACT(data, '$.name') AS name,
    JSON_EXTRACT(data, '$.age') AS age,
    data->'$.name' AS name_operator,
    data->>'$.name' AS name_operator_text,
    data->'$.address.city' AS city,
    JSON_EXTRACT(data, '$.hobbies[0]') AS first_hobby
FROM users_json;

-- Nested JSON path
SELECT 
    data->>'$.name' AS name,
    data->'$.address' AS address,
    data->'$.address.city' AS city,
    JSON_EXTRACT(data, '$.address.zip') AS zip
FROM users_json;
Coding Round
87. Convert between types

Convert between data types using CAST or CONVERT.

  • CAST: SELECT CAST('123' AS SIGNED) as int_val, CAST('123.45' AS DECIMAL(10,2)) as dec_val
  • CONVERT: SELECT CONVERT('123', SIGNED) as int_val, CONVERT('2024-01-01', DATE) as date_val
  • Complexity: O(1)
sql
-- JSON array operations
SELECT 
    '["a","b","c"]' AS original,
    JSON_ARRAY_APPEND('["a","b","c"]', '$', 'd') AS append,
    JSON_ARRAY_INSERT('["a","b","c"]', '$[1]', 'x') AS insert,
    JSON_REMOVE('["a","b","c","d"]', '$[2]') AS remove,
    JSON_INSERT('["a","b","c"]', '$[3]', 'd') AS insert_2,
    JSON_REPLACE('["a","b","c"]', '$[1]', 'x') AS replace;

-- JSON array functions
SELECT 
    JSON_LENGTH('["a","b","c"]') AS array_length,
    JSON_CONTAINS('["a","b","c"]', '"b"') AS contains_b,
    JSON_SEARCH('["a","b","c"]', 'one', 'b') AS search_b;
Coding Round
88. Conditional update

Conditionally update rows using CASE in UPDATE.

  • CASE: UPDATE employees SET salary = CASE WHEN performance = 'excellent' THEN salary * 1.10 WHEN performance = 'good' THEN salary * 1.05 ELSE salary END
  • Complexity: O(n)
sql
-- JSON_TABLE (MySQL 8.0+)
SELECT *
FROM JSON_TABLE(
    '[{"name": "Alice", "age": 25}, {"name": "Bob", "age": 30}]',
    '$[*]' COLUMNS (
        name VARCHAR(100) PATH '$.name',
        age INT PATH '$.age'
    )
) AS jt;

-- JSON_TABLE with nested data
SELECT *
FROM JSON_TABLE(
    '{"users": [{"name": "Alice", "hobbies": ["reading", "gaming"]}]}',
    '$.users[*]' COLUMNS (
        name VARCHAR(100) PATH '$.name',
        hobbies JSON PATH '$.hobbies'
    )
) AS jt;
Coding Round
89. Merge (UPSERT)

Insert or update using INSERT ... ON DUPLICATE KEY UPDATE or REPLACE.

  • INSERT ON DUPLICATE: INSERT INTO users (id, name, age) VALUES (1, 'Alice', 25) ON DUPLICATE KEY UPDATE name = VALUES(name), age = VALUES(age)
  • REPLACE: REPLACE INTO users (id, name, age) VALUES (1, 'Alice', 25)
  • Complexity: O(1)
sql
-- JSON validation (MySQL 5.7+)
SELECT 
    JSON_VALID('{"name": "Alice"}') AS valid_json,
    JSON_VALID('invalid') AS invalid_json;

-- JSON schema validation (MySQL 8.0+)
SELECT 
    JSON_SCHEMA_VALID(
        '{"type": "object", "properties": {"name": {"type": "string"}}}',
        '{"name": "Alice"}'
    ) AS valid_schema;

-- Using JSON_VALID in constraint
ALTER TABLE users
ADD CONSTRAINT check_json_valid
CHECK (JSON_VALID(data));
Coding Round
90. Bulk insert

Insert multiple rows efficiently.

  • Multiple VALUES: INSERT INTO users (name, age) VALUES ('Alice', 25), ('Bob', 30), ('Charlie', 35)
  • INSERT FROM SELECT: INSERT INTO archive_users SELECT * FROM users WHERE created_at < '2023-01-01'
  • Complexity: O(n)
sql
-- GROUP_CONCAT
SELECT 
    department_id,
    GROUP_CONCAT(name) AS employees,
    GROUP_CONCAT(name ORDER BY name) AS employees_sorted,
    GROUP_CONCAT(name ORDER BY name SEPARATOR '; ') AS employees_separated,
    COUNT(*) AS employee_count
FROM employees
GROUP BY department_id;

-- GROUP_CONCAT with DISTINCT
SELECT 
    department_id,
    GROUP_CONCAT(DISTINCT title ORDER BY title) AS unique_titles
FROM employees
GROUP BY department_id;

-- GROUP_CONCAT with CONCAT
SELECT 
    department_id,
    GROUP_CONCAT(CONCAT(name, ' (', title, ')') SEPARATOR ', ') AS employees_info
FROM employees
GROUP BY department_id;
Coding Round
91. Copy table structure

Copy table structure with or without data.

  • Structure only: CREATE TABLE new_table LIKE existing_table
  • Structure and data: CREATE TABLE new_table AS SELECT * FROM existing_table
  • Complexity: O(n)
sql
-- Random number generation
SELECT 
    RAND() AS random_float,
    RAND(123) AS random_seeded,
    FLOOR(RAND() * 100) AS random_int_0_99,
    FLOOR(RAND() * 100) + 1 AS random_int_1_100,
    ROUND(RAND() * 100) AS rounded_random;

-- Random order
SELECT * FROM users ORDER BY RAND() LIMIT 5;

-- Random sample (MySQL 8.0+)
SELECT * FROM users ORDER BY RAND() LIMIT 5;

-- Random sample using TABLESAMPLE (MySQL 8.0+)
SELECT * FROM users TABLESAMPLE SYSTEM(10);
Coding Round
92. Alter table

Modify table structure using ALTER TABLE.

  • ADD COLUMN: ALTER TABLE users ADD COLUMN phone VARCHAR(20)
  • MODIFY COLUMN: ALTER TABLE users MODIFY phone VARCHAR(15)
  • DROP COLUMN: ALTER TABLE users DROP COLUMN phone
  • RENAME COLUMN: ALTER TABLE users RENAME COLUMN phone TO mobile
  • Complexity: O(n)
sql
-- Row number using ROW_NUMBER (MySQL 8.0+)
SELECT 
    *,
    ROW_NUMBER() OVER (ORDER BY id) AS row_num
FROM users;

-- Row number with partition
SELECT 
    *,
    ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank_in_dept
FROM employees;

-- Row number using user variables (older MySQL)
SELECT 
    *,
    @row_num := @row_num + 1 AS row_num
FROM users, (SELECT @row_num := 0) r
ORDER BY id;

-- Row number with reset
SELECT 
    *,
    @row_num := IF(@prev_dept = department_id, @row_num + 1, 1) AS row_num,
    @prev_dept := department_id
FROM employees
CROSS JOIN (SELECT @row_num := 0, @prev_dept := NULL) r
ORDER BY department_id, salary DESC;
Coding Round
93. Foreign key constraints

Add and manage foreign key constraints.

  • CREATE: CREATE TABLE orders (id INT PRIMARY KEY, user_id INT, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE)
  • ALTER ADD: ALTER TABLE orders ADD CONSTRAINT fk_orders_users FOREIGN KEY (user_id) REFERENCES users(id)
  • DROP: ALTER TABLE orders DROP FOREIGN KEY fk_orders_users
  • Complexity: O(n)
sql
-- Conditional aggregation
SELECT 
    department_id,
    COUNT(*) AS total_employees,
    SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) AS active_count,
    SUM(CASE WHEN status = 'inactive' THEN 1 ELSE 0 END) AS inactive_count,
    SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS pending_count,
    AVG(CASE WHEN status = 'active' THEN salary ELSE NULL END) AS avg_active_salary
FROM employees
GROUP BY department_id;

-- Conditional aggregation with multiple conditions
SELECT 
    department_id,
    SUM(CASE WHEN gender = 'M' AND status = 'active' THEN 1 ELSE 0 END) AS active_males,
    SUM(CASE WHEN gender = 'F' AND status = 'active' THEN 1 ELSE 0 END) AS active_females
FROM employees
GROUP BY department_id;
Coding Round
94. Check constraint

Use CHECK constraints for data validation.

  • CREATE: CREATE TABLE users (id INT PRIMARY KEY, age INT CHECK (age >= 0 AND age <= 150))
  • ALTER ADD: ALTER TABLE users ADD CONSTRAINT check_age CHECK (age >= 0 AND age <= 150)
  • Complexity: O(1)
sql
-- Filtered aggregation (MySQL 8.0+)
SELECT 
    department_id,
    COUNT(*) AS total,
    COUNT(*) FILTER (WHERE status = 'active') AS active_count,
    COUNT(*) FILTER (WHERE status = 'inactive') AS inactive_count,
    AVG(salary) FILTER (WHERE status = 'active') AS avg_active_salary
FROM employees
GROUP BY department_id;

-- Multiple filters
SELECT 
    department_id,
    COUNT(*) FILTER (WHERE gender = 'M') AS male_count,
    COUNT(*) FILTER (WHERE gender = 'F') AS female_count,
    AVG(salary) FILTER (WHERE gender = 'M') AS avg_male_salary,
    AVG(salary) FILTER (WHERE gender = 'F') AS avg_female_salary
FROM employees
GROUP BY department_id;
Coding Round
95. Default values

Set default values for columns.

  • CREATE: CREATE TABLE users (id INT PRIMARY KEY, status VARCHAR(20) DEFAULT 'active', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
  • ALTER: ALTER TABLE users ALTER COLUMN status SET DEFAULT 'active'
  • Complexity: O(1)
sql
-- GREATEST and LEAST
SELECT 
    col1,
    col2,
    col3,
    GREATEST(col1, col2, col3) AS max_value,
    LEAST(col1, col2, col3) AS min_value
FROM mytable;

-- GREATEST with NULL handling
SELECT 
    col1,
    col2,
    col3,
    GREATEST(COALESCE(col1, 0), COALESCE(col2, 0), COALESCE(col3, 0)) AS max_with_default
FROM mytable;

-- Find max of values from different tables
SELECT 
    u.id,
    GREATEST(u.salary, COALESCE(b.bonus, 0)) AS total_compensation
FROM users u
LEFT JOIN bonuses b ON u.id = b.user_id;
Coding Round
96. Drop table

Drop tables with caution using DROP TABLE.

  • DROP: DROP TABLE users
  • DROP IF EXISTS: DROP TABLE IF EXISTS users
  • TRUNCATE: TRUNCATE TABLE users
  • Complexity: O(1)
sql
-- Bitwise operations
-- Example table: permissions with bit flags
-- 1 = read, 2 = write, 4 = execute, 8 = delete

-- Check if flag is set
SELECT 
    permissions,
    (permissions & 1) AS can_read,
    (permissions & 2) AS can_write,
    (permissions & 4) AS can_execute,
    (permissions & 8) AS can_delete
FROM user_permissions;

-- Set flag
UPDATE user_permissions 
SET permissions = permissions | 4 
WHERE user_id = 1;

-- Clear flag
UPDATE user_permissions 
SET permissions = permissions & ~4 
WHERE user_id = 1;

-- Toggle flag
UPDATE user_permissions 
SET permissions = permissions ^ 4 
WHERE user_id = 1;

-- Check multiple flags
SELECT * FROM user_permissions 
WHERE (permissions & 3) = 3;  -- Has read AND write
Coding Round
97. Temporary table usage

Use temporary tables for complex queries.

  • CREATE TEMPORARY: CREATE TEMPORARY TABLE temp_users SELECT * FROM users WHERE status = 'active'
  • DROP TEMPORARY: DROP TEMPORARY TABLE temp_users
  • Complexity: O(n)
sql
-- Type conversion
-- CAST
SELECT 
    CAST('123' AS SIGNED) AS int_val,
    CAST('123.45' AS DECIMAL(10,2)) AS dec_val,
    CAST('2024-01-01' AS DATE) AS date_val,
    CAST(123 AS CHAR) AS char_val,
    CAST(123.45 AS UNSIGNED) AS unsigned_val;

-- CONVERT
SELECT 
    CONVERT('123', SIGNED) AS int_val,
    CONVERT('123.45', DECIMAL(10,2)) AS dec_val,
    CONVERT('2024-01-01', DATE) AS date_val,
    CONVERT(123, CHAR) AS char_val;

-- Converting binary
SELECT 
    CONVERT('Hello' USING utf8mb4) AS utf8_string,
    CAST('Hello' AS BINARY) AS binary_data;
Coding Round
98. Show table info

Show table information using various commands.

  • DESCRIBE: DESCRIBE users
  • SHOW CREATE TABLE: SHOW CREATE TABLE users
  • SHOW TABLE STATUS: SHOW TABLE STATUS LIKE 'users'
  • Complexity: O(1)
sql
-- Conditional UPDATE
-- Update with CASE
UPDATE employees 
SET salary = CASE 
    WHEN performance_rating = 5 THEN salary * 1.20
    WHEN performance_rating = 4 THEN salary * 1.15
    WHEN performance_rating = 3 THEN salary * 1.10
    WHEN performance_rating = 2 THEN salary * 1.05
    ELSE salary
END
WHERE status = 'active';

-- Update with IF
UPDATE employees 
SET status = IF(active_years > 5, 'senior', 'junior')
WHERE status = 'active';

-- Update with multiple conditions
UPDATE products 
SET price = CASE 
    WHEN category = 'electronics' THEN price * 0.90
    WHEN category = 'clothing' THEN price * 0.85
    WHEN category = 'books' THEN price * 0.80
    ELSE price
END;
Coding Round
99. Database info

Get database and server information.

  • Database: SELECT DATABASE() as current_db
  • Server version: SELECT VERSION() as mysql_version
  • Connection info: SELECT CONNECTION_ID() as connection_id
  • Complexity: O(1)
sql
-- INSERT ON DUPLICATE KEY UPDATE
INSERT INTO users (id, name, age, email) 
VALUES (1, 'Alice', 25, 'alice@example.com')
ON DUPLICATE KEY UPDATE 
    name = VALUES(name),
    age = VALUES(age),
    email = VALUES(email),
    updated_at = NOW();

-- REPLACE (delete + insert)
REPLACE INTO users (id, name, age, email) 
VALUES (1, 'Alice', 25, 'alice@example.com');

-- INSERT with multiple rows
INSERT INTO users (id, name, age) 
VALUES 
    (1, 'Alice', 25),
    (2, 'Bob', 30),
    (3, 'Charlie', 35)
ON DUPLICATE KEY UPDATE 
    name = VALUES(name),
    age = VALUES(age);
Coding Round
100. Query optimization tips

Essential query optimization tips for better performance.

  • Use EXPLAIN: Analyze query execution plans
  • Create indexes: On columns used in WHERE, JOIN, ORDER BY
  • Limit results: Use LIMIT for pagination
  • Avoid SELECT *: Specify only needed columns
  • Use joins instead of subqueries: When possible
  • Use EXISTS instead of IN: For large datasets
  • Use UNION ALL instead of UNION: When duplicates are acceptable
  • Batch operations: Use bulk inserts and updates
sql
-- Query optimization tips

-- 1. Use EXPLAIN to analyze queries
EXPLAIN SELECT * FROM users WHERE name = 'Alice';
EXPLAIN FORMAT=JSON SELECT * FROM users WHERE name = 'Alice';

-- 2. Create indexes on frequently used columns
CREATE INDEX idx_users_name ON users(name);
CREATE INDEX idx_users_email_age ON users(email, age);

-- 3. Use LIMIT for pagination
SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20;

-- 4. Avoid SELECT *
SELECT id, name, email FROM users WHERE active = 1;

-- 5. Use EXISTS instead of IN when possible
SELECT * FROM users u 
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);

-- 6. Use JOIN instead of subqueries
SELECT u.*, o.total
FROM users u
JOIN orders o ON u.id = o.user_id;

-- 7. Use UNION ALL instead of UNION when duplicates are acceptable
SELECT id, name FROM users
UNION ALL
SELECT id, name FROM archived_users;

-- 8. Use appropriate data types
-- VARCHAR for variable length, CHAR for fixed length
-- INT vs BIGINT based on range needed

-- 9. Use batch operations
INSERT INTO users (name, email) VALUES 
    ('Alice', 'alice@example.com'),
    ('Bob', 'bob@example.com');

-- 10. Use prepared statements for repeated queries
PREPARE stmt FROM 'SELECT * FROM users WHERE id = ?';
SET @id = 1;
EXECUTE stmt USING @id;