SQL Statements Cheatsheet — Comprehensive Reference for All Database Operations
A comprehensive cheatsheet covering all SQL statements, including DDL, DML, DQL, Joins, Subqueries & CTEs, Grouping & Aggregation, Filtering & Sorting, Indexes, Views, Stored Procedures & Functions, Triggers, Transactions, DCL, and Common Patterns. Includes inline and table-level syntax, add/drop/modify examples, cross-engine compatibility.
Posted Updated
SQL Statements Cheatsheet
By
23 min read
SQL Statements Cheatsheet — Comprehensive Reference for All Database Operations
📘 SQL Statements Cheatsheet
Grouped by category · Full syntax examples · Cross-engine compatibility
Legend
| Symbol | Meaning | |——–|———| | ✅ | Supported (same or very similar syntax) | | ⚠️ | Supported with different syntax | | ❌ | Not supported / no direct equivalent |
In article
Here’s your SQL Statements Cheatsheet! It covers 14 categories:
#
Category
What’s Inside
1
DDL
CREATE / ALTER / DROP / TRUNCATE TABLE, DATABASE, INDEX
-- Single tableUPDATEemployeesSETsalary=salary*1.10,updated_at=NOW()WHEREdept_id=3;-- Multi-table update (join)UPDATEemployeeseJOINdepartmentsdONe.dept_id=d.idSETe.salary=e.salary*1.15WHEREd.name='Engineering';
DELETE
1
2
3
4
5
6
7
8
9
10
11
-- Delete with conditionDELETEFROMemployeesWHEREactive=0ANDlast_login<'2023-01-01';-- Delete with joinDELETEeFROMemployeeseJOINdepartmentsdONe.dept_id=d.idWHEREd.name='Temp';-- Delete all rows (use TRUNCATE for speed if no WHERE needed)DELETEFROMemployees;
-- MySQL does not support FULL OUTER JOIN directly; emulate with UNION:SELECTe.name,d.nameASdeptFROMemployeeseLEFTJOINdepartmentsdONe.dept_id=d.idUNIONSELECTe.name,d.nameASdeptFROMemployeeseRIGHTJOINdepartmentsdONe.dept_id=d.id;
-- Customers who placed at least one orderSELECTnameFROMcustomerscWHEREEXISTS(SELECT1FROMordersoWHEREo.customer_id=c.id);-- Customers with no ordersSELECTnameFROMcustomerscWHERENOTEXISTS(SELECT1FROMordersoWHEREo.customer_id=c.id);
-- Org chart: find all reports under manager id=1WITHRECURSIVEorg_chartAS(-- anchor: start with the root managerSELECTid,name,manager_id,0ASlevelFROMemployeesWHEREid=1UNIONALL-- recursive: find their direct reportsSELECTe.id,e.name,e.manager_id,oc.level+1FROMemployeeseJOINorg_chartocONe.manager_id=oc.id)SELECTlevel,nameFROMorg_chartORDERBYlevel;
-- RangeWHEREsalaryBETWEEN50000AND90000-- List membershipWHEREcountryIN('EG','US','UK')-- Pattern matching (% = any chars, _ = one char)WHEREemailLIKE'%@gmail.com'WHEREcodeLIKE'A__-___'-- NULL checks (never use = NULL)WHEREphoneISNULLWHEREphoneISNOTNULL-- Date rangeWHEREcreated_at>='2024-01-01'ANDcreated_at<'2025-01-01'-- CombiningWHERE(salary>70000ORrole='Lead')ANDactive=1
Regular Expression filter
1
2
3
4
5
6
7
8
-- MySQLWHEREnameREGEXP'^[A-Z][a-z]+$'-- PostgreSQL / OracleWHEREname~'^[A-Z][a-z]+$'-- SQL Server-- No native REGEXP; use LIKE patterns or PATINDEX()
ORDER BY
1
2
3
4
5
6
7
8
9
10
11
-- Single columnSELECT*FROMemployeesORDERBYsalaryDESC;-- Multiple columnsSELECT*FROMemployeesORDERBYdept_idASC,salaryDESC;-- NULL handling (PostgreSQL / Oracle)SELECT*FROMemployeesORDERBYsalaryDESCNULLSLAST;-- By expressionSELECT*FROMemployeesORDERBYYEAR(hire_date),salaryDESC;
Cross-Engine Compatibility — Filtering & Sorting
Feature
MySQL
SQLite
PostgreSQL
SQL Server
Oracle
MS Access
WHERE / AND / OR
✅
✅
✅
✅
✅
✅
LIKE%_ wildcards
✅
✅
✅
✅
✅
⚠️ * and ?
REGEXP
✅
✅ REGEXP
⚠️ ~ operator
⚠️ PATINDEX()
⚠️ REGEXP_LIKE()
❌
BETWEEN
✅
✅
✅
✅
✅
✅
ORDER BY … NULLS LAST
❌ use ISNULL(col,1)
✅
✅
❌ use CASE
✅
❌
8. Indexes
Speed up queries by creating lookup structures.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- Basic indexCREATEINDEXidx_salaryONemployees(salary);-- Composite index (order matters — most selective column first)CREATEINDEXidx_dept_salaryONemployees(dept_id,salary);-- Unique indexCREATEUNIQUEINDEXidx_emailONemployees(email);-- Full-text index (for MATCH … AGAINST searches)CREATEFULLTEXTINDEXidx_ft_descONproducts(description);-- Partial / functional index (PostgreSQL)CREATEINDEXidx_activeONemployees(id)WHEREactive=TRUE;-- Drop indexDROPINDEXidx_salaryONemployees;-- MySQLDROPINDEXidx_salary;-- PostgreSQL (auto-detects table)
-- Create a viewCREATEVIEWactive_employeesASSELECTid,name,dept_id,salaryFROMemployeesWHEREactive=1;-- Query a view like a tableSELECT*FROMactive_employeesWHEREdept_id=2;-- Create or replace (no need to drop first)CREATEORREPLACEVIEWactive_employeesASSELECTid,name,dept_id,salary,emailFROMemployeesWHEREactive=1;-- Drop a viewDROPVIEWactive_employees;DROPVIEWIFEXISTSactive_employees;-- Updatable view (simple views without GROUP BY / DISTINCT)UPDATEactive_employeesSETsalary=75000WHEREid=5;
Materialized View (pre-computed, stored result)
1
2
3
4
5
6
7
-- PostgreSQLCREATEMATERIALIZEDVIEWdept_summaryASSELECTdept_id,COUNT(*)AScnt,AVG(salary)ASavg_salFROMemployeesGROUPBYdept_id;-- Refresh the materialized viewREFRESHMATERIALIZEDVIEWdept_summary;
DELIMITER//CREATEFUNCTIONannual_salary(monthlyDECIMAL(10,2))RETURNSDECIMAL(12,2)DETERMINISTICBEGINRETURNmonthly*12;END//DELIMITER;-- Use it in a querySELECTname,annual_salary(salary)ASyearlyFROMemployees;
-- Audit log trigger: record salary changesCREATETABLEsalary_audit(idINTAUTO_INCREMENTPRIMARYKEY,employee_idINT,old_salaryDECIMAL(10,2),new_salaryDECIMAL(10,2),changed_atDATETIMEDEFAULTCURRENT_TIMESTAMP,changed_byVARCHAR(100));DELIMITER//CREATETRIGGERtrg_salary_auditAFTERUPDATEONemployeesFOREACHROWBEGINIFOLD.salary<>NEW.salaryTHENINSERTINTOsalary_audit(employee_id,old_salary,new_salary,changed_by)VALUES(OLD.id,OLD.salary,NEW.salary,CURRENT_USER());ENDIF;END//DELIMITER;-- Drop triggerDROPTRIGGERIFEXISTStrg_salary_audit;
-- Begin a transactionSTARTTRANSACTION;-- MySQL, PostgreSQL, SQLite-- BEGIN; -- also valid in PostgreSQL / SQLite-- BEGIN TRANSACTION; -- SQL Server / SQLite-- Make changesUPDATEaccountsSETbalance=balance-500WHEREid=1;UPDATEaccountsSETbalance=balance+500WHEREid=2;-- Commit if all goodCOMMIT;-- Roll back on errorROLLBACK;-- Savepoints (partial rollback)SAVEPOINTsp1;UPDATEproductsSETstock=stock-1WHEREid=10;SAVEPOINTsp2;UPDATEordersSETstatus='processed'WHEREid=99;ROLLBACKTOSAVEPOINTsp1;-- undo back to sp1, keep nothing after itRELEASESAVEPOINTsp1;-- discard savepoint (don't rollback, just clean up)
Isolation Levels
1
2
3
4
SETTRANSACTIONISOLATIONLEVELREADCOMMITTED;SETTRANSACTIONISOLATIONLEVELREPEATABLEREAD;-- MySQL defaultSETTRANSACTIONISOLATIONLEVELSERIALIZABLE;SETTRANSACTIONISOLATIONLEVELREADUNCOMMITTED;
-- Create a userCREATEUSER'alice'@'localhost'IDENTIFIEDBY'str0ngP@ss!';CREATEUSER'app_user'@'%'IDENTIFIEDBY'appP@ss!';-- any host-- Grant privilegesGRANTSELECT,INSERT,UPDATEONshop.employeesTO'alice'@'localhost';GRANTALLPRIVILEGESONshop.*TO'app_user'@'%';GRANTSELECTONshop.*TO'readonly_user'@'%';-- Revoke privilegesREVOKEINSERT,UPDATEONshop.employeesFROM'alice'@'localhost';-- Show grants for a userSHOWGRANTSFOR'alice'@'localhost';-- Drop a userDROPUSER'alice'@'localhost';-- Apply privilege changesFLUSHPRIVILEGES;
Cross-Engine Compatibility — DCL
Statement
MySQL
SQLite
PostgreSQL
SQL Server
Oracle
MS Access
CREATE USER
✅
❌ file-level security
✅
✅
✅
❌
GRANT
✅
❌
✅
✅
✅
❌
REVOKE
✅
❌
✅
✅
✅
❌
SHOW GRANTS
✅
❌
⚠️ \du in psql / pg_roles table
⚠️ sys.database_permissions
⚠️ DBA_SYS_PRIVS
❌
14. Useful Patterns
Upsert — Insert or Update
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- MySQLINSERTINTOproducts(sku,name,price)VALUES('X1','Widget',9.99)ONDUPLICATEKEYUPDATEprice=VALUES(price),name=VALUES(name);-- PostgreSQLINSERTINTOproducts(sku,name,price)VALUES('X1','Widget',9.99)ONCONFLICT(sku)DOUPDATESETprice=EXCLUDED.price,name=EXCLUDED.name;-- SQL Server / OracleMERGEINTOproductsAStargetUSING(SELECT'X1'ASsku,'Widget'ASname,9.99ASprice)ASsrcONtarget.sku=src.skuWHENMATCHEDTHENUPDATESETprice=src.price,name=src.nameWHENNOTMATCHEDTHENINSERT(sku,name,price)VALUES(src.sku,src.name,src.price);
Pagination (all engines)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- MySQL / PostgreSQL / SQLiteSELECT*FROMproductsORDERBYidLIMIT10OFFSET30;-- page 4-- SQL ServerSELECT*FROMproductsORDERBYidOFFSET30ROWSFETCHNEXT10ROWSONLY;-- Oracle 12c+SELECT*FROMproductsORDERBYidOFFSET30ROWSFETCHNEXT10ROWSONLY;-- Oracle 11g and olderSELECT*FROM(SELECTp.*,ROWNUMrnFROMproductspWHEREROWNUM<=40)WHERErn>30;