Easy Hands on Guide how to get Started With SQL
Updated: March 27, 2026
TL;DR
SQL queries data from databases using SELECT, filtering with WHERE, and aggregating with GROUP BY. Modern SQL adds CTEs (temporary result sets), window functions (ranking, running totals), and JSON functions. Practice platforms like SQLBolt are free; cloud databases like Supabase and PlanetScale offer instant databases; AI tools now convert natural language to SQL.
SQL is the language of data. Whether you're building web applications, analyzing business metrics, or exploring datasets, SQL is unavoidable. And for good reason — it's powerful, standardized across databases, and relatively approachable.
The challenge isn't learning SQL's basics. SELECT, WHERE, JOIN — those take an afternoon. The challenge is building intuition. Knowing when to use a window function instead of a subquery. Understanding query performance. Recognizing that a denormalized schema sometimes makes sense.
In 2026, SQL has evolved significantly. Modern SQL (PostgreSQL, MySQL 8.0+, SQLite) supports advanced features that make complex problems elegant: Common Table Expressions (CTEs) simplify nested queries, window functions eliminate redundant aggregations, and JSON functions bridge relational and document-oriented paradigms.
This guide takes you from "SELECT * FROM users" to writing queries that leverage modern SQL's power. And it'll take less than an hour.
Getting Started: SELECT, WHERE, and ORDER BY
A database is a collection of tables. Each table has columns (fields) and rows (records).
users table:
id | name | email | created_at
1 | Alice | alice@example.com | 2026-01-15
2 | Bob | bob@example.com | 2026-02-03
3 | Charlie | charlie@example.com| 2026-02-15
The most basic query retrieves all rows and columns:
SELECT * FROM users;
This returns all 3 rows. The * means "all columns."
Selecting Specific Columns
SELECT name, email FROM users;
Output:
name | email
--------|--------------------
Alice | alice@example.com
Bob | bob@example.com
Charlie | charlie@example.com
Filtering with WHERE
SELECT name, email FROM users WHERE created_at > '2026-02-01';
Output:
name | email
--------|--------------------
Bob | bob@example.com
Charlie | charlie@example.com
WHERE filters rows. Only rows matching the condition are returned.
Sorting with ORDER BY
SELECT name, email FROM users ORDER BY created_at DESC;
DESC sorts in descending order (newest first). ASC (ascending, the default) sorts oldest to newest.
Aggregation: COUNT, SUM, AVG
When you want statistics instead of individual rows, use aggregate functions.
orders table:
id | user_id | amount
1 | 1 | 50.00
2 | 1 | 75.00
3 | 2 | 120.00
4 | 3 | 30.00
SELECT COUNT(*) as total_orders FROM orders;
Output: total_orders: 4
SELECT SUM(amount) as total_revenue FROM orders;
Output: total_revenue: 275.00
GROUP BY: Aggregating per Category
SELECT user_id, COUNT(*) as num_orders, SUM(amount) as total_spent
FROM orders
GROUP BY user_id;
Output:
user_id | num_orders | total_spent
--------|------------|------------
1 | 2 | 125.00
2 | 1 | 120.00
3 | 1 | 30.00
GROUP BY splits rows into groups (by user_id) and applies aggregates within each group.
JOINs: Combining Tables
Real databases split information across tables to avoid duplication. JOINs recombine them.
users:
id | name
1 | Alice
2 | Bob
orders:
id | user_id | amount
1 | 1 | 50
2 | 2 | 120
SELECT users.name, orders.amount
FROM users
JOIN orders ON users.id = orders.user_id;
Output:
name | amount
-------|-------
Alice | 50
Bob | 120
The JOIN condition ON users.id = orders.user_id matches rows where user_id in orders equals id in users.
Types of JOINs
- INNER JOIN: Only rows that match in both tables
- LEFT JOIN: All rows from the left table, matching rows from the right table
- RIGHT JOIN: All rows from the right table, matching from the left
- FULL OUTER JOIN: All rows from both tables
Example LEFT JOIN:
SELECT users.name, COUNT(orders.id) as num_orders
FROM users
LEFT JOIN orders ON users.id = orders.user_id
GROUP BY users.id;
This shows all users, even those with no orders (their count will be 0).
Modern SQL: CTEs and Window Functions
Common Table Expressions (CTEs)
CTEs create temporary named result sets. They make complex queries readable.
WITH user_order_stats AS (
SELECT user_id, COUNT(*) as num_orders, SUM(amount) as total_spent
FROM orders
GROUP BY user_id
),
high_value_users AS (
SELECT user_id, total_spent
FROM user_order_stats
WHERE total_spent > 100
)
SELECT users.name, high_value_users.total_spent
FROM high_value_users
JOIN users ON high_value_users.user_id = users.id;
Instead of nesting subqueries, you name intermediate results. The query reads top-to-bottom, making logic clear.
Window Functions: Ranking and Running Totals
Window functions compute values over a "window" of rows.
SELECT
name,
amount,
ROW_NUMBER() OVER (ORDER BY amount DESC) as rank,
SUM(amount) OVER (ORDER BY amount DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as running_total
FROM orders;
Output:
name | amount | rank | running_total
--------|--------|------|---------------
Large | 150 | 1 | 150
Medium | 100 | 2 | 250
Small | 50 | 3 | 300
ROW_NUMBER() OVER (ORDER BY amount DESC) ranks rows by amount in descending order.
The SUM(...) OVER (...) computes a cumulative sum as you go down the rows.
Window functions replace the need for complex self-joins and subqueries.
JSON Functions: Bridging Relational and Document Models
Modern SQL databases support JSON. You can store, query, and transform JSON data natively.
users:
id | name | profile
1 | Alice| {"age": 28, "city": "New York", "interests": ["AI", "music"]}
2 | Bob | {"age": 35, "city": "San Francisco", "interests": ["sports"]}
Extract JSON fields:
-- PostgreSQL
SELECT name, profile->>'age' as age, profile->>'city' as city
FROM users;
Output:
name | age | city
------|-----|----------------
Alice | 28 | New York
Bob | 35 | San Francisco
Filter by JSON field:
SELECT name FROM users WHERE (profile->>'age')::int > 30;
Output: Bob
JSON functions are powerful for semi-structured data without sacrificing SQL's querying power.
Cloud Databases: Getting Started Instantly
You don't need to install a database server. Cloud platforms offer instant databases.
Supabase
Supabase is PostgreSQL in the cloud. Sign up, create a project, get a database instantly.
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(URL, KEY);
const { data, error } = await supabase
.from('users')
.select('*')
.gt('created_at', '2026-02-01');
Supabase abstracts the SQL layer with a JavaScript client, but you can also write raw SQL.
PlanetScale
PlanetScale is MySQL at scale, built on Vitess (MySQL at YouTube scale). It's optimized for web applications and includes branching (branches for your database, like Git branches for code).
pscale connect mydb main
Then write SQL directly:
SELECT * FROM users WHERE created_at > '2026-02-01';
Neon and Turso
Neon is serverless PostgreSQL with automatic scaling. Turso is SQLite at scale, with global read replicas for ultra-low latency.
Both are excellent for small to medium projects and offer generous free tiers.
Practice Platforms
Learning SQL requires hands-on practice. These platforms are free and excellent.
SQLBolt (sqlbolt.com): Interactive lessons with built-in practice. Complete in 15 minutes.
Mode Analytics (mode.com/sql-tutorial): Advanced SQL tutorial with real datasets.
LeetCode SQL (leetcode.com/study-plan/sql): Coding challenges with difficulty ratings. Great for interview prep.
SQLZoo (sqlzoo.net): Interactive tutorials covering basic to advanced SQL.
Spend 30 minutes on each platform. The patterns will stick.
AI-Powered SQL: Natural Language to Queries
LLMs have made SQL writing more accessible. You can describe what you want in English, and the AI generates SQL.
You: "Show me the top 5 customers by revenue"
AI:
SELECT user_id, SUM(amount) as total_revenue
FROM orders
GROUP BY user_id
ORDER BY total_revenue DESC
LIMIT 5;
Tools like GitHub Copilot, ChatGPT, and database-specific assistants (BigQuery's Copilot, Supabase's SQL editor) can generate queries. But you should understand what they generate — never blindly trust LLM-generated SQL, especially for data modification.
Query Performance: Why it Matters
A well-written query returns results in milliseconds. A poorly-written one times out. Here's why:
Indexes speed up searches. Without an index, the database scans every row. With an index on email, finding a user by email is instant.
-- Slow without an index on email
SELECT * FROM users WHERE email = 'alice@example.com';
-- Fast if there's an index on email
CREATE INDEX idx_users_email ON users(email);
Joins can be expensive. Joining large tables requires the database to match millions of rows. Optimize by:
- Filtering early (WHERE before JOIN)
- Joining on indexed columns
- Avoiding unnecessary columns in SELECT
GROUP BY can be slow. Grouping millions of rows for aggregates requires sorting. If the group column has an index, it's faster.
Beginners often write logically correct queries that are terribly slow. As you practice, you'll develop intuition for performance.
SQL Antipatterns to Avoid
1. SELECT * (unless you really need all columns)
-- Bad: fetches unused columns, wastes bandwidth
SELECT * FROM users WHERE id = 1;
-- Good: fetch only what you need
SELECT id, name, email FROM users WHERE id = 1;
2. Not using indexes
-- If you frequently filter by email, add an index
CREATE INDEX idx_users_email ON users(email);
3. Subqueries in SELECT (use window functions instead)
-- Slow: subquery runs per row
SELECT user_id, (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) as num_orders
FROM users u;
-- Fast: window function
SELECT user_id, COUNT(*) OVER (PARTITION BY user_id) as num_orders
FROM orders;
4. Implicit type conversions
-- Bad: comparing string '100' to integer 100 requires conversion
SELECT * FROM products WHERE price = '100';
-- Good: match types
SELECT * FROM products WHERE price = 100;
Conclusion
SQL is approachable and powerful. Start with SELECT, WHERE, and JOINs. Once comfortable, explore CTEs and window functions — they'll change how you think about data queries.
Use cloud databases like Supabase or PlanetScale to skip infrastructure setup. Practice on SQLBolt or LeetCode. And leverage AI tools to generate starting queries, but always understand what they produce.
SQL skills compound. A week of focused practice gives you foundation that lasts decades. Pick a database, open a practice platform, and start querying.