Complete SQL Cheatsheet with All Commands and Examples
This SQL cheatsheet covers DDL, DML, DCL, TCL, queries, joins, subqueries, indexes, views, stored procedures, triggers, transactions, and advanced SQL concepts with practical examples for MySQL, PostgreSQL, SQL Server, and Oracle.
Database
Contents15 sections
1
SQL Basics and Introduction
Understanding SQL fundamentals and database concepts
basics
SQL (Structured Query Language): A standard language for managing and manipulating relational databases. SQL allows you to create, read, update, and delete data (CRUD operations), as well as define database structures, control access, and manage transactions. SQL is used by all major relational database management systems (RDBMS) including MySQL, PostgreSQL, SQL Server, Oracle, and SQLite. Understanding SQL is essential for any developer working with data-driven applications.
sql
-- SQL Command Categories-- 1. DDL (Data Definition Language)-- CREATE, ALTER, DROP, TRUNCATE, RENAME-- Used to define database structure-- 2. DML (Data Manipulation Language)-- SELECT, INSERT, UPDATE, DELETE-- Used to manipulate data-- 3. DCL (Data Control Language)-- GRANT, REVOKE-- Used to control access permissions-- 4. TCL (Transaction Control Language)-- COMMIT, ROLLBACK, SAVEPOINT-- Used to manage transactions-- 5. DQL (Data Query Language)-- SELECT (sometimes classified separately)
sql
-- Basic SQL Syntax Rules-- 1. SQL is not case-sensitive (keywords)SELECT*FROM users;-- same asselect*from users;-- 2. Semicolon ends a statementSELECT*FROM users;
2
DDL - Creating Databases and Tables
Data Definition Language commands for creating structures
ddl
CREATE Commands: DDL commands are used to define and modify database structures. The CREATE statement allows you to create databases, tables, indexes, views, and other database objects. When creating tables, you define columns with specific data types and constraints to enforce data integrity. Understanding proper table design with primary keys, foreign keys, and constraints is fundamental to building robust database applications.
sql
-- Create DatabaseCREATEDATABASE company_db;CREATEDATABASEIFNOTEXISTS company_db;-- Use DatabaseUSE company_db;
3
DDL - Altering and Managing Tables
Modifying existing table structures
ddl
ALTER Commands: The ALTER TABLE statement allows you to modify existing table structures without losing data. You can add new columns, modify existing columns, drop columns, add or remove constraints, and rename tables. These operations are crucial for database evolution as application requirements change over time. Always be cautious when altering production tables, especially when dropping columns or changing data types.
INSERT Statement: The INSERT command adds new rows to a table. You can insert single or multiple rows in one statement, specify values for all or selected columns, and use default values or expressions. Understanding different INSERT variations helps you write efficient data insertion code. For bulk inserts, using multi-row INSERT statements is much faster than individual inserts. Always ensure data integrity by respecting constraints and data types.
sql
-- Insert Single Row (all columns)INSERTINTO employees
VALUES(1,'John','Doe','john@email.com'
5
DML - Selecting Data (Basic)
Retrieving data with SELECT queries
dml
SELECT Statement: The SELECT command is the most frequently used SQL statement, allowing you to retrieve data from one or more tables. You can select all columns or specific columns, filter results with WHERE clauses, sort data with ORDER BY, limit results, and perform calculations. Mastering SELECT queries is essential for data analysis and reporting. Understanding how to write efficient queries with proper indexing will significantly improve application performance.
sql
-- Select All ColumnsSELECT*FROM employees;-- Select Specific ColumnsSELECT first_name, last_name, salary FROM employees
6
DML - Advanced SELECT Queries
Complex filtering and pattern matching
dml
Advanced Filtering: SQL provides powerful operators for complex filtering scenarios. The BETWEEN operator simplifies range queries, IN allows checking against multiple values, and LIKE enables pattern matching with wildcards. Understanding logical operators (AND, OR, NOT) and operator precedence is crucial for writing correct query conditions. CASE expressions add conditional logic to SELECT statements, enabling dynamic column values based on conditions.
sql
-- BETWEEN OperatorSELECT*FROM employees
WHERE salary BETWEEN60000AND80000;SELECT*
7
DML - Updating Data
Modifying existing records with UPDATE
dml
UPDATE Statement: The UPDATE command modifies existing rows in a table. You can update one or more columns, use expressions for calculated values, and apply conditions with WHERE clauses to target specific rows. Always use WHERE clauses carefully to avoid accidentally updating all rows. For safety, many database configurations require explicit WHERE clauses in UPDATE statements. You can also update based on data from other tables using subqueries or joins.
sql
-- Update Single ColumnUPDATE employees
SET salary =80000WHERE id =1;-- Update Multiple Columns
8
DML - Deleting Data
Removing records from tables
dml
DELETE Statement: The DELETE command removes rows from a table based on specified conditions. Like UPDATE, you should always use WHERE clauses to target specific rows unless you intentionally want to delete all data. DELETE removes rows but keeps the table structure intact, unlike DROP TABLE which removes the entire table. TRUNCATE is faster than DELETE for removing all rows but cannot be rolled back in most databases and does not fire triggers.
sql
-- Delete Specific RowsDELETEFROM employees
WHERE id =1;DELETEFROM employees
WHERE salary <
9
Aggregate Functions
Performing calculations on data sets
functions
Aggregate Functions: These functions perform calculations on multiple rows and return a single result. Common aggregate functions include COUNT, SUM, AVG, MAX, and MIN. They are essential for statistical analysis and reporting. Aggregate functions ignore NULL values (except COUNT(*)), and you can combine them with GROUP BY to calculate statistics for different groups of data. Understanding how to use these functions effectively is crucial for data analysis tasks.
sql
-- COUNT: Count rowsSELECTCOUNT(*)FROM employees;-- All rowsSELECTCOUNT(
10
GROUP BY and HAVING
Grouping data and filtering groups
grouping
GROUP BY Clause: Groups rows that have the same values in specified columns into summary rows. It is typically used with aggregate functions to perform calculations on each group separately. The HAVING clause filters groups based on aggregate conditions, unlike WHERE which filters individual rows before grouping. Understanding the order of execution (WHERE → GROUP BY → HAVING → SELECT → ORDER BY) is crucial for writing correct queries with grouping.
sql
-- Basic GROUP BYSELECT department_id,COUNT(*)AS employee_count
FROM employees
GROUPBY department_id;
11
JOINS - Inner and Outer Joins
Combining rows from multiple tables
joins
Joins: Joins let you combine rows from two or more tables based on related columns. INNER JOIN returns matching rows, LEFT/RIGHT OUTER JOIN keep unmatched rows from one side, and FULL OUTER JOIN keeps all rows from both sides. CROSS JOIN creates a cartesian product. SELF JOIN lets a table join to itself for hierarchical data.
sql
-- Inner Join (only matches)SELECT e.first_name, d.dept_name
FROM employees e
INNERJOIN departments d ON e.department_id = d.dept_id;
12
Subqueries and CTEs
Using subqueries and common table expressions
subqueries
Subqueries & CTEs: Subqueries run inside another query for filtering or derived tables. Common Table Expressions (CTEs) improve readability and can be recursive for hierarchical data. Use CTEs to break complex logic into steps.
sql
-- Subquery in WHERESELECT first_name, salary
FROM employees
WHERE salary >(SELECTAVG(salary)FROM employees);-- Subquery as derived table
13
Indexes and Performance
Improving query speed with indexes and EXPLAIN
performance
Indexes: Indexes speed up reads by keeping sorted references to data. Create indexes on frequently filtered or joined columns. Avoid over-indexing because each index slows inserts/updates. Use EXPLAIN/EXPLAIN ANALYZE to inspect query plans.
sql
-- Create / drop indexesCREATEINDEX idx_emp_dept ON employees(department_id);CREATEUNIQUEINDEX idx_emp_email ON employees(email);
14
Transactions and ACID
Ensuring consistency with transactions and isolation levels
transactions
Transactions: Group statements so they succeed or fail together (atomicity). Use proper isolation levels to balance consistency and concurrency. Always COMMIT on success and ROLLBACK on error.
sql
-- Basic transactionSTARTTRANSACTION;-- or BEGINUPDATE accounts SET balance = balance -100WHERE id =1;UPDATE
15
Views, Functions, and Procedures
Encapsulating logic on the database side
admin
Views & Routines: Views expose saved queries, while stored procedures and functions package reusable logic. Use them to enforce consistency and reduce duplication. Grant minimal privileges to execute these objects.
sql
-- Create / drop viewCREATEVIEW active_employees ASSELECT id, first_name, last_name, department_id
FROM employees
WHERE is_active =TRUE;SELECT*
-- Used to query and retrieve data
-- 3. Comments
-- Single line comment
/* Multi-line
comment */
-- 4. String literals use single quotes
SELECT
*
FROM
users
WHERE
name
=
'John'
;
-- 5. Identifiers (table/column names) can use backticks
-- Common Data Types-- Numeric TypesINT,SMALLINT,BIGINT-- IntegersDECIMAL(10,2),NUMERIC(10,2)-- Fixed-pointFLOAT,DOUBLE,REAL-- Floating-point-- String TypesCHAR(10)-- Fixed lengthVARCHAR(255)-- Variable lengthTEXT,MEDIUMTEXT,LONGTEXT-- Long text-- Date and Time TypesDATE-- YYYY-MM-DDTIME-- HH:MM:SSDATETIME-- YYYY-MM-DD HH:MM:SSTIMESTAMP-- With timezoneYEAR-- YYYY-- Binary TypesBLOB,MEDIUMBLOB,LONGBLOB-- Binary dataBINARY,VARBINARY-- Binary strings-- Other TypesBOOLEAN,BOOL-- True/False (TINYINT(1))ENUM('S','M','L')-- EnumerationJSON -- JSON data (MySQL 5.7+)
-- Other Table Operations-- Truncate Table (delete all rows, keep structure)TRUNCATETABLE employees;-- Drop TableDROPTABLE employees;DROPTABLEIFEXISTS employees;-- Show Table StructureDESCRIBE employees;DESC employees;SHOWCOLUMNSFROM employees;-- Show Create StatementSHOWCREATETABLE employees;-- Show All TablesSHOWTABLES;-- Copy Table StructureCREATETABLE employees_backup LIKE employees;-- Copy Table with DataCREATETABLE employees_backup ASSELECT*FROM employees;
,
'1234567890'
,
'2024-01-15'
,
75000.00
,
1
,
TRUE
,
NOW
(
)
)
;
-- Insert Single Row (specific columns)
INSERT
INTO
employees
(
first_name
,
last_name
,
email
,
hire_date
,
salary
)
VALUES
(
'Jane'
,
'Smith'
,
'jane@email.com'
,
'2024-02-01'
,
80000.00
)
;
-- Insert Multiple Rows
INSERT
INTO
employees
(
first_name
,
last_name
,
email
,
hire_date
,
salary
)
VALUES
(
'Alice'
,
'Johnson'
,
'alice@email.com'
,
'2024-03-01'
,
70000.00
)
,
(
'Bob'
,
'Williams'
,
'bob@email.com'
,
'2024-03-15'
,
72000.00
)
,
(
'Carol'
,
'Brown'
,
'carol@email.com'
,
'2024-04-01'
,
75000.00
)
;
sql
-- Insert with SELECT (copy data from another table)INSERTINTO employees_backup (first_name, last_name, email, salary)SELECT first_name, last_name, email, salary
FROM employees
WHERE department_id =1;-- Insert with Default ValuesINSERTINTO employees (first_name, last_name, email)VALUES('David','Miller','david@email.com');-- Other columns use DEFAULT values-- Insert Ignore (skip if duplicate key)INSERTIGNOREINTO employees (id, first_name, last_name, email)VALUES(1,'John','Doe','john@email.com');-- Insert On Duplicate Key Update (MySQL)INSERTINTO employees (id, first_name, last_name, salary)VALUES(1,'John','Doe',80000.00)ONDUPLICATEKEYUPDATE salary =VALUES(salary), last_name =VALUES(last_name);
-- WHERE Clause (Filtering)SELECT*FROM employees WHERE salary >70000;SELECT*FROM employees WHERE department_id =1;SELECT*FROM employees
WHERE first_name ='John'AND last_name ='Doe';SELECT*FROM employees
WHERE salary >=60000AND salary <=80000;SELECT*FROM employees
WHERE department_id IN(1,2,3);SELECT*FROM employees
WHERE first_name LIKE'J%';-- Starts with JSELECT*FROM employees
WHERE email LIKE'%@gmail.com';-- Ends with @gmail.comSELECT*FROM employees
WHERE first_name LIKE'%oh%';-- Contains 'oh'SELECT*FROM employees
WHERE phone ISNULL;SELECT*FROM employees
WHERE phone ISNOTNULL;
sql
-- ORDER BY (Sorting)SELECT*FROM employees
ORDERBY salary DESC;SELECT*FROM employees
ORDERBY last_name ASC, first_name ASC;SELECT*FROM employees
ORDERBY hire_date DESC;-- LIMIT (Restricting Results)SELECT*FROM employees
LIMIT10;SELECT*FROM employees
ORDERBY salary DESCLIMIT5;-- Top 5 highest salaries-- OFFSET (Pagination)SELECT*FROM employees
LIMIT10OFFSET20;-- Skip first 20, get next 10-- MySQL alternativeSELECT*FROM employees
LIMIT20,10;-- Skip 20, get 10
FROM
employees
WHERE
hire_date
BETWEEN
'2024-01-01'
AND
'2024-12-31'
;
-- IN Operator
SELECT
*
FROM
employees
WHERE
department_id
IN
(
1
,
2
,
3
)
;
SELECT
*
FROM
employees
WHERE
first_name
IN
(
'John'
,
'Jane'
,
'Alice'
)
;
-- NOT IN
SELECT
*
FROM
employees
WHERE
department_id
NOT
IN
(
1
,
2
)
;
-- EXISTS
SELECT
*
FROM
employees e
WHERE
EXISTS
(
SELECT
1
FROM
departments d
WHERE
d
.
dept_id
=
e
.
department_id
)
;
sql
-- LIKE PatternsSELECT*FROM employees
WHERE first_name LIKE'J%';-- Starts with JSELECT*FROM employees
WHERE first_name LIKE'%n';-- Ends with nSELECT*FROM employees
WHERE first_name LIKE'%oh%';-- Contains ohSELECT*FROM employees
WHERE first_name LIKE'J___';-- J followed by 3 charsSELECT*FROM employees
WHERE first_name LIKE'[JM]%';-- Starts with J or M (SQL Server)SELECT*FROM employees
WHERE first_name LIKE'[A-M]%';-- Starts with A to MSELECT*FROM employees
WHERE email NOTLIKE'%@gmail.com';-- REGEXP (MySQL, PostgreSQL)SELECT*FROM employees
WHERE first_name REGEXP'^[A-M]';-- Starts with A-MSELECT*FROM employees
WHERE email REGEXP'[0-9]';-- Contains digit
sql
-- CASE ExpressionSELECT first_name, last_name, salary,CASEWHEN salary <50000THEN'Low'WHEN salary BETWEEN50000AND80000THEN'Medium'WHEN salary >80000THEN'High'ELSE'Unknown'ENDAS salary_category
FROM employees;-- Simple CASESELECT first_name, department_id,CASE department_id
WHEN1THEN'IT'WHEN2THEN'HR'WHEN3THEN'Sales'ELSE'Other'ENDAS department_name
FROM employees;-- CASE in ORDER BYSELECT*FROM employees
ORDERBYCASEWHEN department_id =1THEN1WHEN department_id =2THEN2ELSE3END;
UPDATE
employees
SET
salary
=
85000
,
department_id
=
2
,
is_active
=
TRUE
WHERE
id
=
1
;
-- Update with Expression
UPDATE
employees
SET
salary
=
salary
*
1.1
-- 10% raise
WHERE
department_id
=
1
;
-- Update All Rows (DANGEROUS!)
UPDATE
employees
SET
is_active
=
TRUE
;
-- Update with CASE
UPDATE
employees
SET
salary
=
CASE
WHEN
department_id
=
1
THEN
salary
*
1.15
WHEN
department_id
=
2
THEN
salary
*
1.10
WHEN
department_id
=
3
THEN
salary
*
1.08
ELSE
salary
END
;
sql
-- Update with SubqueryUPDATE employees
SET department_id =(SELECT dept_id FROM departments
WHERE dept_name ='IT')WHERE first_name ='John';-- Update with JOIN (MySQL)UPDATE employees e
INNERJOIN departments d ON e.department_id = d.dept_id
SET e.salary = e.salary *1.1WHERE d.dept_name ='Sales';-- Update Multiple Tables (MySQL)UPDATE employees e, departments d
SET e.salary = e.salary *1.1, d.budget = d.budget -10000WHERE e.department_id = d.dept_id
AND d.dept_name ='IT';-- Update with RETURNING (PostgreSQL)UPDATE employees
SET salary =90000WHERE id =1RETURNING id, first_name, salary;
sql
-- Safe Update Practices-- 1. Always use WHERE clauseUPDATE employees
SET salary =80000WHERE id =1;-- NOT: without WHERE-- 2. Test with SELECT firstSELECT*FROM employees WHERE id =1;-- Then UPDATE-- 3. Use transactions for safetySTARTTRANSACTION;UPDATE employees SET salary =90000WHERE id =1;-- Check resultsSELECT*FROM employees WHERE id =1;-- If correct: COMMIT, else: ROLLBACK-- 4. Backup before mass updatesCREATETABLE employees_backup ASSELECT*FROM employees;-- 5. Use LIMIT for testing (MySQL)UPDATE employees
SET salary = salary *1.1WHERE department_id =1LIMIT5;
40000
;
DELETE
FROM
employees
WHERE
hire_date
<
'2020-01-01'
;
-- Delete with Multiple Conditions
DELETE
FROM
employees
WHERE
department_id
=
1
AND
is_active
=
FALSE
;
DELETE
FROM
employees
WHERE
last_name
IN
(
'Doe'
,
'Smith'
)
;
-- Delete All Rows (DANGEROUS!)
DELETE
FROM
employees
;
-- Delete with LIMIT (MySQL)
DELETE
FROM
employees
WHERE
salary
<
50000
LIMIT
10
;
sql
-- Delete with SubqueryDELETEFROM employees
WHERE department_id IN(SELECT dept_id FROM departments
WHERE budget <50000);DELETEFROM employees
WHERE id NOTIN(SELECTDISTINCT employee_id FROM projects
);-- Delete with JOIN (MySQL)DELETE e FROM employees e
INNERJOIN departments d ON e.department_id = d.dept_id
WHERE d.dept_name ='Closed';-- Delete with RETURNING (PostgreSQL)DELETEFROM employees
WHERE id =1RETURNING id, first_name, last_name;
sql
-- TRUNCATE vs DELETE-- DELETE: Removes rows one by oneDELETEFROM employees;-- - Slower-- - Can be rolled back-- - Fires triggers-- - Can use WHERE clause-- - Logs each row deletion-- TRUNCATE: Removes all rows at onceTRUNCATETABLE employees;-- - Faster-- - Cannot be rolled back (in most DBs)-- - Does not fire triggers-- - No WHERE clause-- - Minimal logging-- - Resets auto-increment counter-- DROP: Removes entire tableDROPTABLE employees;-- - Removes structure and data-- - Cannot recover without backup-- Safe Delete Practices-- 1. Use SELECT firstSELECT*FROM employees WHERE id =1;-- 2. Then DELETEDELETEFROM employees WHERE id =1;
phone
)
FROM
employees
;
-- Non-NULL values
SELECT
COUNT
(
DISTINCT
department_id
)
FROM
employees
;
-- SUM: Total of numeric values
SELECT
SUM
(
salary
)
FROM
employees
;
SELECT
SUM
(
salary
)
AS
total_payroll
FROM
employees
;
-- AVG: Average value
SELECT
AVG
(
salary
)
FROM
employees
;
SELECT
AVG
(
salary
)
AS
average_salary
FROM
employees
WHERE
department_id
=
1
;
-- MAX: Maximum value
SELECT
MAX
(
salary
)
FROM
employees
;
SELECT
MAX
(
hire_date
)
AS
latest_hire
FROM
employees
;
-- MIN: Minimum value
SELECT
MIN
(
salary
)
FROM
employees
;
SELECT
MIN
(
hire_date
)
AS
earliest_hire
FROM
employees
;
sql
-- Multiple AggregatesSELECTCOUNT(*)AS total_employees,SUM(salary)AS total_payroll,AVG(salary)AS avg_salary,MAX(salary)AS highest_salary,MIN(salary)AS lowest_salary
FROM employees;-- Aggregates with WHERESELECTCOUNT(*)AS it_employees,AVG(salary)AS avg_it_salary
FROM employees
WHERE department_id =1;-- ROUND for precisionSELECTROUND(AVG(salary),2)AS avg_salary,ROUND(SUM(salary),2)AS total_payroll
FROM employees;-- Aggregates with DISTINCTSELECTCOUNT(DISTINCT department_id)AS unique_departments,COUNT(DISTINCT last_name)AS unique_surnames
FROM employees;
sql
-- Statistical Functions-- STDDEV: Standard deviationSELECT STDDEV(salary)AS salary_std_dev FROM employees;-- VARIANCE: VarianceSELECT VARIANCE(salary)AS salary_variance FROM employees;-- String Aggregation (MySQL)SELECT GROUP_CONCAT(first_name)AS all_names
FROM employees;SELECT GROUP_CONCAT(first_name SEPARATOR ', ')AS names
FROM employees;-- String Aggregation (PostgreSQL)SELECT STRING_AGG(first_name,', ')AS names
FROM employees;-- Conditional AggregationSELECTCOUNT(*)AS total,COUNT(CASEWHEN salary >70000THEN1END)AS high_earners,COUNT(CASEWHEN salary <=70000THEN1END)AS others
FROM employees;
SELECT
department_id
,
AVG
(
salary
)
AS
avg_salary
FROM
employees
GROUP
BY
department_id
;
-- Multiple Columns in GROUP BY
SELECT
department_id
,
is_active
,
COUNT
(
*
)
AS
count
FROM
employees
GROUP
BY
department_id
,
is_active
;
-- GROUP BY with Multiple Aggregates
SELECT
department_id
,
COUNT
(
*
)
AS
emp_count
,
SUM
(
salary
)
AS
total_salary
,
AVG
(
salary
)
AS
avg_salary
,
MAX
(
salary
)
AS
max_salary
,
MIN
(
salary
)
AS
min_salary
FROM
employees
GROUP
BY
department_id
;
sql
-- HAVING Clause (Filter Groups)SELECT department_id,AVG(salary)AS avg_salary
FROM employees
GROUPBY department_id
HAVINGAVG(salary)>70000;SELECT department_id,COUNT(*)AS emp_count
FROM employees
GROUPBY department_id
HAVINGCOUNT(*)>=5;-- WHERE vs HAVING-- WHERE: Filters rows before grouping-- HAVING: Filters groups after aggregationSELECT department_id,COUNT(*)AS emp_count
FROM employees
WHERE salary >50000-- Filter rows firstGROUPBY department_id
HAVINGCOUNT(*)>3;-- Then filter groups-- Multiple HAVING ConditionsSELECT department_id,COUNT(*)AS emp_count,AVG(salary)AS avg_salary
FROM employees
GROUPBY department_id
HAVINGCOUNT(*)>5ANDAVG(salary)>60000;
sql
-- GROUP BY with ORDER BYSELECT department_id,COUNT(*)AS emp_count,AVG(salary)AS avg_salary
FROM employees
GROUPBY department_id
ORDERBY emp_count DESC;-- GROUP BY with ExpressionsSELECTYEAR(hire_date)AS hire_year,COUNT(*)AS hires
FROM employees
GROUPBYYEAR(hire_date)ORDERBY hire_year;-- ROLLUP (Subtotals)SELECT department_id,COUNT(*)AS emp_count,SUM(salary)AS total_salary
FROM employees
GROUPBY department_id WITH ROLLUP;-- GROUPING SETS (Advanced)SELECT department_id, is_active,COUNT(*)AS count
FROM employees
GROUPBY GROUPING SETS ((department_id),(is_active),(department_id, is_active));
-- Left Join (all left, matching right)
SELECT
e
.
first_name
,
d
.
dept_name
FROM
employees e
LEFT
JOIN
departments d
ON
e
.
department_id
=
d
.
dept_id
;
-- Right Join (all right, matching left)
SELECT
e
.
first_name
,
d
.
dept_name
FROM
employees e
RIGHT
JOIN
departments d
ON
e
.
department_id
=
d
.
dept_id
;
sql
-- Full Outer Join (all rows both sides)-- PostgreSQL / SQL ServerSELECT e.first_name, d.dept_name
FROM employees e
FULLOUTERJOIN departments d ON e.department_id = d.dept_id;-- MySQL alternative using UNIONSELECT e.first_name, d.dept_name
FROM employees e
LEFTJOIN departments d ON e.department_id = d.dept_id
UNIONSELECT e.first_name, d.dept_name
FROM employees e
RIGHTJOIN departments d ON e.department_id = d.dept_id;
sql
-- Cross Join (cartesian product)SELECT e.first_name, p.project_name
FROM employees e
CROSSJOIN projects p;-- Self Join (table joins itself)SELECT e.first_name AS employee, m.first_name AS manager
FROM employees e
LEFTJOIN employees m ON e.manager_id = m.id;
SELECT
dept_name
,
avg_salary
FROM
(
SELECT
department_id
,
AVG
(
salary
)
AS
avg_salary
FROM
employees
GROUP
BY
department_id
)
t
JOIN
departments d
ON
t
.
department_id
=
d
.
dept_id
;
sql
-- CTE (WITH)WITH dept_salary AS(SELECT department_id,AVG(salary)AS avg_salary
FROM employees
GROUPBY department_id
)SELECT d.dept_name, ds.avg_salary
FROM dept_salary ds
JOIN departments d ON ds.department_id = d.dept_id;-- Recursive CTE (hierarchy)WITH RECURSIVE employee_path AS(SELECT id, first_name, manager_id,0ASlevelFROM employees
WHERE manager_id ISNULLUNIONALLSELECT e.id, e.first_name, e.manager_id, ep.level+1FROM employees e
JOIN employee_path ep ON e.manager_id = ep.id
)SELECT*FROM employee_path
ORDERBYlevel, first_name;
DROP
INDEX
idx_emp_dept
ON
employees
;
-- MySQL
DROP
INDEX
idx_emp_email
;
-- PostgreSQL
-- Composite index (order matters)
CREATE
INDEX
idx_emp_dept_salary
ON
employees
(
department_id
,
salary
)
;
-- Covering index example (MySQL/InnoDB)
CREATE
INDEX
idx_emp_email_phone
ON
employees
(
email
,
phone
)
;
sql
-- Analyze query planEXPLAINSELECT*FROM employees WHERE email ='john@email.com';-- PostgreSQL with runtime statsEXPLAINANALYZESELECT*FROM employees WHERE department_id =1;-- Update statistics (PostgreSQL)VACUUM ANALYZE employees;-- MySQL optimizer hintsSELECT/*+ INDEX(employees idx_emp_dept) */*FROM employees
WHERE department_id =1;
accounts
SET
balance
=
balance
+
100
WHERE
id
=
2
;
COMMIT
;
-- or ROLLBACK on failure
-- Set isolation level
SET
TRANSACTION
ISOLATION
LEVEL
READ
COMMITTED
;
-- Savepoints
START
TRANSACTION
;
SAVEPOINT
before_bonus
;
UPDATE
employees
SET
salary
=
salary
*
1.1
WHERE
department_id
=
1
;
ROLLBACK
TO
SAVEPOINT
before_bonus
;
COMMIT
;
FROM
active_employees
;
DROP
VIEW
active_employees
;
sql
-- Stored procedure (MySQL)DELIMITER//CREATEPROCEDURE give_raise(IN dept INT,IN pct DECIMAL(5,2))BEGINUPDATE employees
SET salary = salary *(1+ pct /100)WHERE department_id = dept;END//DELIMITER;CALL give_raise(1,5.0);-- Scalar function (PostgreSQL)CREATEORREPLACEFUNCTION full_name(firstTEXT,lastTEXT)RETURNSTEXTAS $$
BEGINRETURNfirst||' '||last;END;$$ LANGUAGE plpgsql;