dev.rean.me
โญ FEATURED POSTdatabase

Complete Database & SQL References & Tips with Code Examples

Comprehensive SQL reference guide covering DDL, DML, SELECT queries, JOINs, aggregation, subqueries, CTEs, indexing, transactions, data types, security, and performance tips with code examples and related tutorials.

2026-09-19 ยท 19 min read

Share:

Hello my friend! Welcome to the Complete Database & SQL References & Tips guide on dev.rean.me!

Relational databases and SQL (Structured Query Language) are the foundation of modern software development. Whether you work with MySQL, PostgreSQL, Microsoft SQL Server, SQLite, or Oracle, mastering SQL query syntax, schema design, indexes, transactions, and performance optimization is essential for building scalable applications.

In this comprehensive guide, we cover all core SQL concepts โ€” data types, DDL schema creation, DML operations, complex SELECT queries, JOINs, GROUP BY aggregations, CTE subqueries, window functions, indexes, transactions, security practices, and practical tips โ€” paired with code examples and links to related database tutorials. Bookmark this page for your daily database reference! ๐Ÿ›ข๏ธโšก


1. Database Setup & Environment

Database EngineTypeCommon Use CaseDefault Port
MySQL / MariaDBOpen Source RelationalWeb applications, WordPress, LAMP stack3306
PostgreSQLAdvanced Open Source RDBMSComplex data models, JSONB, geospatial, enterprise apps5432
Microsoft SQL ServerEnterprise Commercial RDBMSEnterprise .NET applications, Windows Server1433
SQLiteEmbedded Serverless FileMobile apps, local desktop apps, testingN/A (File)

CLI Quick Connect Commands

# Connect to MySQL server via CLI
mysql -u root -p -h localhost -P 3306

# Connect to PostgreSQL server via CLI
psql -U postgres -d my_database -h localhost

# Connect to SQLite database file
sqlite3 mydata.db

# Connect to SQL Server using sqlcmd
sqlcmd -S localhost -U sa -P 'MyStrongPass123!'

2. SQL Data Types Reference

Selecting the right data type ensures storage efficiency, data integrity, and faster query execution.

CategoryData TypeDescription & Typical StorageExample
NumericINT / INTEGER4-byte integer (-2.1B to +2.1B)42
NumericBIGINT8-byte large integer (auto-increment IDs)9223372036854775807
NumericDECIMAL(p,s) / NUMERICExact decimal for currency/financialsDECIMAL(10,2) -> 199.99
NumericFLOAT / DOUBLEApproximate floating-point numbers3.14159
StringVARCHAR(n)Variable-length string up to n charsVARCHAR(255)
StringCHAR(n)Fixed-length string (padded with spaces)CHAR(2) -> 'KH'
StringTEXTLong text field (articles, comments)Up to 64KB (MySQL)
Date/TimeDATECalendar date (YYYY-MM-DD)'2026-09-19'
Date/TimeDATETIME / TIMESTAMPDate and time (YYYY-MM-DD HH:MM:SS)'2026-09-19 14:30:00'
BooleanBOOLEAN / TINYINT(1)True/False flag (1 or 0)TRUE or 1
Binary/JSONJSONNative JSON document indexing'{"role": "admin"}'

๐Ÿ’ก Tip: Always use DECIMAL(p,s) or NUMERIC(p,s) for financial amounts and money values. Never use FLOAT or DOUBLE for currency because floating-point binary representation causes rounding errors (0.1 + 0.2 = 0.30000000000000004).


3. Data Definition Language (DDL) โ€” Schemas & Tables

DDL statements create, alter, and delete database structures like databases, tables, indexes, and views.

Managing Databases

-- Create database
CREATE DATABASE IF NOT EXISTS school_db 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

-- Switch database
USE school_db;

-- Drop database (CAUTION: Deletes all data!)
DROP DATABASE IF EXISTS old_school_db;

Table Creation with Constraints

CREATE TABLE users (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    status ENUM('active', 'inactive', 'banned') DEFAULT 'active',
    balance DECIMAL(10, 2) DEFAULT 0.00,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

Altering & Modifying Tables

-- Add new column
ALTER TABLE users ADD COLUMN phone VARCHAR(20) AFTER email;

-- Modify existing column type
ALTER TABLE users MODIFY COLUMN username VARCHAR(80) NOT NULL;

-- Rename column (MySQL 8.0+)
ALTER TABLE users RENAME COLUMN phone TO mobile_number;

-- Drop column
ALTER TABLE users DROP COLUMN status;

-- Rename table
RENAME TABLE users TO app_users;

Dropping & Truncating Tables

-- TRUNCATE: Instantly removes all rows and resets AUTO_INCREMENT (Faster than DELETE)
TRUNCATE TABLE logs;

-- DROP: Completely removes table structure and data
DROP TABLE IF EXISTS temporary_imports;

4. Data Manipulation Language (DML) โ€” INSERT, UPDATE, DELETE

DML statements manage data records inside existing tables.

INSERT Statements

-- Insert single record
INSERT INTO users (username, email, password_hash, balance) 
VALUES ('sokha_dev', 'sokha@rean.me', '$2y$10$e8Z...', 150.00);

-- Insert multiple records in a single query
INSERT INTO users (username, email, password_hash, balance) VALUES
('cheata_ui', 'cheata@rean.me', '$2y$10$x9K...', 200.50),
('bopha_code', 'bopha@rean.me', '$2y$10$w1P...', 75.00),
('vanna_db', 'vanna@rean.me', '$2y$10$z4M...', 310.00);

-- INSERT IGNORE (Skip duplicates without erroring)
INSERT IGNORE INTO users (user_id, username, email, password_hash)
VALUES (1, 'sokha_dev', 'sokha@rean.me', '$2y$10$e8Z...');

-- UPSERT / ON DUPLICATE KEY UPDATE (Insert or Update if Primary Key exists)
INSERT INTO users (user_id, username, balance) 
VALUES (1, 'sokha_dev', 500.00)
ON DUPLICATE KEY UPDATE balance = balance + VALUES(balance);

UPDATE Statements

-- Update specific columns for matching rows
UPDATE users 
SET balance = balance + 50.00, 
    status = 'active'
WHERE user_id = 1;

-- Update with conditional CASE statement
UPDATE users 
SET status = CASE 
    WHEN balance > 100 THEN 'active'
    ELSE 'inactive'
END;

โš ๏ธ Warning: Always test UPDATE and DELETE queries with a SELECT statement first to verify which rows will be affected before running the actual modification query without a safety clause!

DELETE Statements

-- Delete specific rows matching condition
DELETE FROM users 
WHERE status = 'banned' AND created_at < '2025-01-01';

-- Safe pattern: Check affected rows before deleting
SELECT COUNT(*) FROM users WHERE status = 'banned';
-- If count is correct, execute DELETE

5. SELECT Statements & Data Retrieval

The SELECT query retrieves rows from tables using filtering, sorting, pagination, and projection.

Core SELECT Query Syntax

-- Basic SELECT all columns
SELECT * FROM products;

-- SELECT specific columns with aliases
SELECT 
    product_id AS id,
    product_name AS title,
    unit_price AS price,
    unit_price * 1.10 AS price_with_tax
FROM products;

-- Distinct unique values
SELECT DISTINCT category_id FROM products;

WHERE Clause & Filtering

SELECT product_id, product_name, unit_price, stock_quantity
FROM products
WHERE unit_price >= 50.00 
  AND stock_quantity > 0 
  AND category_id IN (1, 3, 5)
ORDER BY unit_price DESC;

Sorting & Pagination (ORDER BY, LIMIT, OFFSET)

-- Top 10 most expensive items
SELECT product_id, product_name, unit_price
FROM products
ORDER BY unit_price DESC
LIMIT 10;

-- Pagination: Page 2 (10 items per page -> Skip 10, Take 10)
SELECT product_id, product_name, unit_price
FROM products
ORDER BY product_id ASC
LIMIT 10 OFFSET 10;

6. Logical SQL Execution Order

Understanding how SQL processes query clauses under the hood helps prevent syntax errors (like trying to use a SELECT column alias in a WHERE clause).

 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 โ”‚ 1. FROM & JOIN     -> Locate source tables & merge    โ”‚
 โ”‚ 2. WHERE           -> Filter individual rows           โ”‚
 โ”‚ 3. GROUP BY        -> Group rows into summary buckets  โ”‚
 โ”‚ 4. HAVING          -> Filter grouped aggregate buckets โ”‚
 โ”‚ 5. SELECT          -> Compute columns & aliases        โ”‚
 โ”‚ 6. DISTINCT        -> Remove duplicate result rows      โ”‚
 โ”‚ 7. ORDER BY        -> Sort final output rows           โ”‚
 โ”‚ 8. LIMIT / OFFSET  -> Paginate result slice            โ”‚
 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
-- Query demonstrating execution logic
SELECT 
    category_id,
    COUNT(product_id) AS total_items,
    AVG(unit_price) AS avg_price           -- Step 5: SELECT & Aliases
FROM products                              -- Step 1: FROM
WHERE stock_quantity > 0                   -- Step 2: WHERE (row filter)
GROUP BY category_id                       -- Step 3: GROUP BY
HAVING AVG(unit_price) > 20.00             -- Step 4: HAVING (group filter - cannot use avg_price alias in standard SQL!)
ORDER BY total_items DESC                  -- Step 7: ORDER BY (can use alias)
LIMIT 5;                                   -- Step 8: LIMIT

7. Filtering & Conditional Operators Cheat Sheet

OperatorSyntax ExampleMeaning
LIKEname LIKE 'Sok%'Starts with "Sok" (% = wildcard, _ = single char)
INstatus IN ('paid', 'shipped')Matches any value in the provided list
BETWEENprice BETWEEN 10 AND 50Range match inclusive of endpoints
IS NULLdeleted_at IS NULLChecks if column value is NULL
IS NOT NULLemail IS NOT NULLChecks if column contains a non-null value
NOTNOT (status = 'cancelled')Inverts boolean condition
CASE WHENCASE WHEN stock > 0 THEN 'In Stock' ELSE 'Out' ENDConditional branching expression

LIKE Wildcard Examples

-- Contains 'sql' anywhere in title (case-insensitive in default collation)
SELECT * FROM articles WHERE title LIKE '%sql%';

-- 4-letter word starting with 'd' and ending with 'ev'
SELECT * FROM tags WHERE tag_name LIKE 'd_ev';

CASE WHEN Expressions

SELECT 
    order_id,
    total_amount,
    CASE 
        WHEN total_amount >= 500 THEN 'VIP Customer'
        WHEN total_amount >= 100 THEN 'Regular Customer'
        ELSE 'Basic Customer'
    END AS customer_tier
FROM orders;

8. SQL JOINs Reference

JOIN clauses combine rows from two or more tables based on a related column between them.

       INNER JOIN                   LEFT JOIN                  RIGHT JOIN
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚ Table โ”‚ Table โ”‚           โ”‚ Table โ”‚ Table โ”‚          โ”‚ Table โ”‚ Table โ”‚
   โ”‚   A   โ”‚   B   โ”‚           โ”‚   A   โ”‚   B   โ”‚          โ”‚   A   โ”‚   B   โ”‚
   โ”‚    โ”Œโ”€โ”€โ”ดโ”€โ”€โ”    โ”‚           โ”‚โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ”ผโ”€โ”€โ”    โ”‚          โ”‚    โ”Œโ”€โ”€โ”ผโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ”‚
   โ”‚    โ”‚โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ”‚    โ”‚           โ”‚โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ”‚โ–ˆโ–ˆโ”‚    โ”‚          โ”‚    โ”‚โ–ˆโ–ˆโ”‚โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ”‚
   โ”‚    โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜    โ”‚           โ”‚โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ”ผโ”€โ”€โ”˜    โ”‚          โ”‚    โ””โ”€โ”€โ”ผโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  Only matching rows         All Left + matching Right   All Right + matching Left

1. INNER JOIN (Matching records in both tables)

SELECT 
    o.order_id,
    c.customer_name,
    c.email,
    o.order_date,
    o.total_amount
FROM orders o
INNER JOIN customers c ON o.customer_id = c.customer_id;

2. LEFT JOIN (All rows from left table + matched rows from right)

-- Find all customers, including those with 0 orders
SELECT 
    c.customer_id,
    c.customer_name,
    COUNT(o.order_id) AS total_orders
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name;

3. Finding Unmatched Records (Anti-JOIN pattern)

-- Find customers who have NEVER placed an order
SELECT 
    c.customer_id,
    c.customer_name,
    c.email
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;

4. FULL OUTER JOIN (All records from both tables)

-- Supported natively in PostgreSQL / SQL Server (Emulated with UNION in MySQL)
SELECT c.customer_name, o.order_id
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
UNION
SELECT c.customer_name, o.order_id
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;

9. Aggregation & Grouping (GROUP BY & HAVING)

Aggregate functions compute a single summary value from multiple row values.

Common Aggregate Functions

FunctionPurposeExample
COUNT()Counts total rows or non-null valuesCOUNT(*), COUNT(DISTINCT category_id)
SUM()Calculates total numeric sumSUM(total_amount)
AVG()Calculates average numeric valueAVG(unit_price)
MIN()Returns minimum valueMIN(created_at)
MAX()Returns maximum valueMAX(score)

Grouping and HAVING Example

SELECT 
    category_id,
    COUNT(product_id) AS item_count,
    MIN(unit_price) AS cheapest,
    MAX(unit_price) AS most_expensive,
    AVG(unit_price) AS average_price
FROM products
GROUP BY category_id
HAVING COUNT(product_id) >= 5
ORDER BY average_price DESC;

๐Ÿ’ก Tip: Use WHERE to filter rows before aggregation occurs (faster performance). Use HAVING only to filter aggregated results after GROUP BY.


10. Subqueries & Common Table Expressions (CTEs)

CTEs (WITH clause) break complex nested queries into clean, readable tabular steps.

Subquery in WHERE Clause

-- Find employees who earn more than the department average salary
SELECT employee_id, first_name, salary, department_id
FROM employees
WHERE salary > (
    SELECT AVG(salary) 
    FROM employees
);

Subquery with IN / EXISTS

-- Find categories that have at least one product in stock
SELECT category_id, category_name
FROM categories c
WHERE EXISTS (
    SELECT 1 
    FROM products p 
    WHERE p.category_id = c.category_id 
      AND p.stock_quantity > 0
);

Common Table Expression (CTE - WITH Clause)

WITH HighValueOrders AS (
    SELECT customer_id, SUM(total_amount) AS total_spent
    FROM orders
    WHERE order_date >= '2026-01-01'
    GROUP BY customer_id
    HAVING SUM(total_amount) > 1000.00
),
CustomerDetails AS (
    SELECT customer_id, customer_name, email
    FROM customers
)
SELECT 
    cd.customer_name,
    cd.email,
    hvo.total_spent
FROM HighValueOrders hvo
JOIN CustomerDetails cd ON hvo.customer_id = cd.customer_id
ORDER BY hvo.total_spent DESC;

11. Primary Keys, Foreign Keys & Constraints

Constraints enforce relational data integrity and prevent invalid data entries.

CREATE TABLE departments (
    dept_id INT AUTO_INCREMENT PRIMARY KEY,
    dept_name VARCHAR(100) NOT NULL UNIQUE
);

CREATE TABLE employees (
    emp_id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    salary DECIMAL(10,2) CHECK (salary > 0),    -- CHECK constraint
    dept_id INT NOT NULL,
    
    -- Foreign Key Definition with CASCADE action
    CONSTRAINT fk_employees_departments 
        FOREIGN KEY (dept_id) 
        REFERENCES departments(dept_id)
        ON DELETE RESTRICT
        ON UPDATE CASCADE
);

Foreign Key Cascade Options

Cascade ActionBehavior on Parent Record Deletion/Update
RESTRICT / NO ACTIONBlocks deletion if child records exist (Default / Safest)
CASCADEAutomatically deletes or updates matching child rows
SET NULLSets the foreign key column in child rows to NULL

12. Practical Database Schemas & Multi-Table Projects

Here are real-world relational database design examples implemented across different database systems:

Complete Student Exam System Schema Example (MySQL)

CREATE TABLE students (
    student_id VARCHAR(10) PRIMARY KEY,
    full_name VARCHAR(100) NOT NULL,
    gender CHAR(1) CHECK (gender IN ('M', 'F')),
    dob DATE
);

CREATE TABLE subjects (
    subject_id INT AUTO_INCREMENT PRIMARY KEY,
    subject_name VARCHAR(100) NOT NULL
);

CREATE TABLE exam_scores (
    score_id INT AUTO_INCREMENT PRIMARY KEY,
    student_id VARCHAR(10) NOT NULL,
    subject_id INT NOT NULL,
    score DECIMAL(5,2) CHECK (score BETWEEN 0 AND 100),
    exam_date DATE NOT NULL,
    FOREIGN KEY (student_id) REFERENCES students(student_id),
    FOREIGN KEY (subject_id) REFERENCES subjects(subject_id)
);

13. Built-in SQL Functions Reference

String Functions

SELECT 
    CONCAT(first_name, ' ', last_name) AS full_name,
    UPPER(email) AS upper_email,
    LOWER(dept_name) AS lower_dept,
    LENGTH(username) AS char_count,
    SUBSTRING(phone, 1, 3) AS area_code,
    REPLACE(slug, '-', '_') AS clean_slug,
    TRIM('   hello   ') AS trimmed_text
FROM users;

Date & Time Functions

-- Current Date & Time
SELECT CURRENT_TIMESTAMP, CURRENT_DATE(), CURRENT_TIME();

-- Extract Date Parts (MySQL)
SELECT 
    created_at,
    YEAR(created_at) AS year_val,
    MONTH(created_at) AS month_val,
    DAY(created_at) AS day_val,
    DATE_FORMAT(created_at, '%d/%m/%Y %H:%i') AS formatted_date
FROM orders;

-- Date Arithmetic (MySQL)
SELECT 
    order_date,
    DATE_ADD(order_date, INTERVAL 7 DAY) AS estimated_delivery,
    DATEDIFF(NOW(), order_date) AS days_elapsed
FROM orders;

Handling NULL Values (COALESCE & IFNULL)

-- Return first non-null argument
SELECT 
    username,
    COALESCE(phone, mobile, email, 'No Contact Info') AS primary_contact
FROM users;

-- IFNULL (MySQL specific)
SELECT product_name, IFNULL(discount_price, regular_price) AS final_price
FROM products;

14. Indexes, Performance Optimization & Query Tuning

Indexes speed up read query lookups (SELECT) by maintaining a balanced tree (B-Tree) structure, at the cost of slightly slower writes (INSERT/UPDATE).

Creating Indexes

-- Single-column index for fast WHERE / JOIN filtering
CREATE INDEX idx_users_email ON users(email);

-- Composite Index (Order matters! Left-to-right prefix rule)
CREATE INDEX idx_orders_customer_date ON orders(customer_id, order_date);

-- Unique index
CREATE UNIQUE INDEX idx_products_sku ON products(sku);

-- Drop index
DROP INDEX idx_users_email ON users;

Analyzing Query Performance (EXPLAIN)

-- Inspect execution plan to check if index is used
EXPLAIN SELECT * FROM users WHERE email = 'sokha@rean.me';

๐Ÿ’ก Indexing Best Practices:

  1. Index columns used frequently in WHERE, ON (JOINs), ORDER BY, and GROUP BY.
  2. Avoid indexing small tables (less than 1,000 rows) as full table scans are faster.
  3. Do not apply functions to indexed columns in WHERE queries (WHERE YEAR(created_at) = 2026 invalidates index! Use WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01' instead).

15. Transactions & Concurrency Control

Transactions group multiple database statements into a single atomic execution unit adhering to ACID properties (Atomicity, Consistency, Isolation, Durability).

-- Start transaction block
START TRANSACTION;  -- Or BEGIN; in PostgreSQL / SQLite

-- Step 1: Deduct balance from sender
UPDATE accounts 
SET balance = balance - 100.00 
WHERE account_id = 101 AND balance >= 100.00;

-- Step 2: Add balance to recipient
UPDATE accounts 
SET balance = balance + 100.00 
WHERE account_id = 202;

-- Step 3: Insert audit log
INSERT INTO transaction_logs (sender_id, receiver_id, amount) 
VALUES (101, 202, 100.00);

-- If everything succeeds, commit changes permanently
COMMIT;

-- If an error occurs, undo all changes in transaction
-- ROLLBACK;

16. Views & Stored Procedures

Views (Virtual Saved Queries)

-- Create View for popular active products
CREATE VIEW vw_active_products AS
SELECT 
    p.product_id,
    p.product_name,
    p.unit_price,
    c.category_name
FROM products p
JOIN categories c ON p.category_id = c.category_id
WHERE p.stock_quantity > 0;

-- Querying the View like a real table
SELECT * FROM vw_active_products WHERE unit_price < 50.00;

Stored Procedures (MySQL Example)

DELIMITER //

CREATE PROCEDURE GetCustomerSummary(IN customerId INT, OUT totalOrders INT, OUT totalSpent DECIMAL(10,2))
BEGIN
    SELECT COUNT(*), IFNULL(SUM(total_amount), 0.00)
    INTO totalOrders, totalSpent
    FROM orders
    WHERE customer_id = customerId;
END //

DELIMITER ;

-- Calling Stored Procedure
CALL GetCustomerSummary(1, @count, @spent);
SELECT @count AS total_orders, @spent AS total_amount_spent;

17. SQL Security & SQL Injection Prevention

SQL Injection occurs when user inputs are directly concatenated into dynamic SQL string queries.

Vulnerable Code vs Secure Parameterized Query

โŒ Vulnerable (DO NOT DO THIS!):

// User input: ' OR '1'='1
$sql = "SELECT * FROM users WHERE username = '" . $_POST['user'] . "'";
// Resulting Query: SELECT * FROM users WHERE username = '' OR '1'='1'
// Allows attacker to bypass authentication!

โœ… Secure Parameterized Query (PDO in PHP):

$stmt = $pdo->prepare("SELECT user_id, password_hash FROM users WHERE username = :user");
$stmt->execute(['user' => $_POST['user']]);
$user = $stmt->fetch();

โœ… Secure Parameterized Query (Node.js MySQL2 / pg):

// Parameter placeholder (?) escapes input automatically
const [rows] = await db.execute(
  'SELECT * FROM users WHERE email = ? AND status = ?',
  [userInputEmail, 'active']
);

18. SQL Best Practices vs Common Mistakes

Recommended Best PracticeAvoid Common Mistake
Use explicit column names (SELECT id, name)Using SELECT * in production application APIs
Use parameterized queries (?, :var)Concatenating user inputs directly into SQL strings
Wrap multi-step mutations in START TRANSACTIONRunning multi-step updates without transaction safety
Use DECIMAL(10,2) for currency valuesUsing FLOAT or DOUBLE for monetary amounts
Add Indexes on Foreign Keys & WHERE columnsLeaving foreign keys unindexed causing slow table joins
Use TRUNCATE TABLE to clear all table rowsRunning DELETE FROM table without WHERE clause
Filter dates with range bounds (date >= '2026-01-01')Wrapping indexed date columns in functions (YEAR(date) = 2026)
Use EXPLAIN to audit slow query executionGuessing why a query takes seconds to execute

Summary Tag Cloud Directory

Happy querying and building high-performance database-driven applications! ๐Ÿ›ข๏ธ๐Ÿš€