home / Intermediate / Databases and SQL Basics

Databases and SQL Basics

level: intermediate · difficulty 2/3 · published 2026-10-02

What it is

A database is an organized collection of data that supports efficient storage, retrieval, and modification. A relational database organizes data into tables with rows and columns, where each row represents a record and each column a field. SQL (Structured Query Language) is the standard language for defining, querying, and manipulating data in relational databases. SQL includes several sub-languages: DDL (Data Definition Language) for creating and altering schema objects like tables and indexes; DML (Data Manipulation Language) for inserting, updating, and deleting rows; and DQL (Data Query Language), primarily the SELECT statement, for retrieving data. Most relational databases also support transactions, constraints, and joins. Popular implementations include PostgreSQL, MySQL, SQLite, Microsoft SQL Server, and Oracle Database. While SQL is standardized by ANSI and ISO, each system has extensions and subtle differences, so always consult your database's documentation. Non-relational databases (NoSQL) exist, but this lesson focuses on relational databases and SQL.

Why it matters

Databases power nearly every application that needs to store data persistently: web apps, mobile apps, analytics tools, and enterprise systems. SQL provides a declarative way to express what data you want, not how to retrieve it, which lets the database engine optimize execution. This separation of concerns means you can change hardware or tune indexes without rewriting queries. Learning SQL is valuable because it is a long-lived skill; the language has been stable for decades and remains in high demand. Relational databases enforce data integrity through constraints like PRIMARY KEY, FOREIGN KEY, and UNIQUE, reducing application bugs. Transactions with ACID properties (Atomicity, Consistency, Isolation, Durability) ensure reliable updates even during failures. Understanding SQL also helps you reason about data modeling, indexing, and performance, which are critical when applications scale. Even if you later use an ORM or a NoSQL store, the concepts of tables, keys, and joins transfer.

How it works under the hood

A relational database management system (RDBMS) stores data in pages on disk and caches frequently used pages in memory. When you submit a SQL query, the database parses it, validates it against the schema, and produces a logical plan. The query optimizer then rewrites the plan and chooses an execution strategy, often using indexes to avoid full table scans. An index is a data structure, typically a B-tree or hash table, that allows fast lookup by key. For a join, the engine may use nested loops, hash join, or merge join, depending on table sizes and available indexes. Transactions are managed with a write-ahead log (WAL) or similar mechanism to guarantee durability; changes are first written to the log and then applied to data pages. Concurrency control uses locks or multiversion concurrency control (MVCC) to let readers and writers proceed without blocking each other in many cases. Understanding these internals helps you write efficient queries and choose appropriate indexes.

A worked example

Suppose you have two tables: customers(id, name, email) and orders(id, customer_id, amount, created_at). To find the total amount spent by each customer, you join the tables and aggregate. The following SQL is standard and works in PostgreSQL, MySQL, and SQLite with minor syntax variations:

SELECT c.name, SUM(o.amount) AS total_spent
FROM customers c
JOIN orders o ON o.customer_id = c.id
GROUP BY c.id, c.name
ORDER BY total_spent DESC;

This query joins customers to orders on the foreign key customer_id, groups rows by customer, sums the amount column, and orders the result from highest to lowest. The AS total_spent clause names the computed column. If you only want customers who spent more than 100, add HAVING SUM(o.amount) > 100 after the GROUP BY clause. Note that WHERE filters rows before grouping, while HAVING filters groups after aggregation. Always include the join condition to avoid a Cartesian product, which multiplies rows and yields incorrect totals.

Common mistakes

A frequent mistake is omitting the join condition, which produces a Cartesian product and incorrect results. Another is using SELECT * in production queries; it retrieves unnecessary columns, increases network traffic, and can break code when the schema changes. Misunderstanding NULL leads to bugs: NULL is not equal to any value, so column = NULL is never true; use IS NULL or IS NOT NULL. Forgetting to index foreign keys or columns used in WHERE and JOIN clauses can cause slow queries. Writing WHERE conditions that prevent index usage, such as applying a function to an indexed column, also hurts performance. Not using transactions for multi-step updates can leave data inconsistent if a step fails. Assuming SQL is identical across databases leads to portability issues; for example, string concatenation differs (|| vs CONCAT). Finally, ignoring SQL injection risks when building queries with string concatenation; always use parameterized queries or prepared statements.

When to use it

Use a relational database and SQL when your data has clear structure, relationships, and integrity requirements, such as users, orders, and products. It excels at transactional workloads where consistency is critical, like banking or inventory systems. SQL is also strong for reporting and analytics on structured data, especially with window functions and common table expressions (CTEs). If your data is highly unstructured or you need extreme horizontal scalability with eventual consistency, a NoSQL database may be a better fit, but many NoSQL systems now support SQL-like query languages. For small projects, SQLite offers a zero-configuration, file-based database. For web applications, PostgreSQL and MySQL are common choices. Use an ORM when you want to work with objects in your programming language, but understand the SQL it generates to avoid performance pitfalls. In short, choose SQL when you need reliable, queryable, and well-modeled data.

Frequently asked questions

What is the difference between WHERE and HAVING? WHERE filters individual rows before grouping and aggregation, while HAVING filters groups after aggregation. For example, WHERE amount > 10 removes rows with small amounts, whereas HAVING SUM(amount) > 100 keeps only groups whose total exceeds 100. Can I use SQL without a database server? Yes, SQLite is an embedded database that stores data in a single file and requires no separate server process, making it ideal for learning and small applications. How do I avoid SQL injection? Use parameterized queries or prepared statements, where placeholders are used for user input instead of concatenating strings. Most database drivers provide this feature. Finally, is SQL case-sensitive? Keywords are case-insensitive, but identifiers like table and column names may be case-sensitive depending on the database and operating system; PostgreSQL folds unquoted identifiers to lowercase, while MySQL varies by configuration.