DEV Community

Julie
Julie

Posted on

SQL for absolute beginners: a map of CRUD

Have you heard of SQL but aren't sure where to start? I felt the same way once. It turns out SQL is easier than most people imagine, especially if you already know your way around Excel.

In this post, I'll give you a map of SQL: the four core operations, the keywords to perform them, and enough examples to run your first queries right away.

What SQL actually is

SQL is not a database. I used to think it was, because of the names of database management systems like SQLite and MySQL.

SQL stands for Structured Query Language. It's the language we use to talk to a relational database. Though it's called a language, it's much simpler than general-purpose programming languages like Python, JavaScript, or C. A programming language tells the computer how to do a task; SQL tells the database what you want. That's why we call it declarative.

If you're coming from Excel, a database is like a workbook, and each table is like a sheet. Data lives in rows and columns: a row describes one thing, like an order, while a column holds one attribute of that thing, such as a product name or price.

Where to practice

I'd start with SQLBolt. It's a great site: it introduces these concepts and gives you exercises so you learn by doing. I learned a lot from it.

Another option is DB Browser for SQLite. Install it, open it, and click New Database to create a database (a .db file). Then open the Execute SQL tab shown below, type a SQL statement in the blank area, and click Run (the ▶ button).

DB Browser

If you'd like to follow the examples in this post, run the SQL below to create the tables and add a few rows. Don't worry about the syntax yet, as you'll learn what each statement does in the following sections.

CREATE TABLE IF NOT EXISTS students(
    id INTEGER PRIMARY KEY,
    name TEXT,
    class TEXT
);
CREATE TABLE IF NOT EXISTS scores(
    student_id INTEGER,
    subject TEXT,
    score INTEGER
);
INSERT INTO students
VALUES (1, 'Mary',  'A'),
       (2, 'Bob',   'A'),
       (3, 'Alice', 'A'),
       (4, 'John',  'B'),
       (5, 'Cathy', 'B');
INSERT INTO scores
VALUES (1, 'English', 88),
       (1, 'Math',    91),
       (2, 'Math',    79),
       (4, 'Math',    87);
Enter fullscreen mode Exit fullscreen mode

The example database has two tables, students and scores, linked by a key: students.id matches scores.student_id. You'll see why that matters when we join them.

The tables of the example database

If you have your own data, you can use that too: save an .xlsx file as CSV, create a new database in DB Browser, and import the CSV. In real applications, though, rows usually arrive through the application itself, and table structures are managed by developers using migration tools.

One practical tip: DB Browser doesn't commit your changes to the database file until you click Write Changes (or run COMMIT;), so click Write Changes after running the setup above. If you close the app and choose Discard, or if it crashes, the changes are rolled back.

The basic operations: CRUD

The basic operations on a database are Create, Read, Update, and Delete—CRUD. Create, update, and delete are "write" operations: they modify the data.

Let's start with read, since it's the most common operation.

Read: SELECT

Querying one table

Use SELECT column1, column2, ... FROM mytable to read only some of the columns. Since a table can contain millions of rows, you'll often want to read only some of the rows as well. Here's the template:

SELECT column1, column2, ...
FROM mytable
WHERE condition                 -- filter rows; combine conditions with AND / OR
ORDER BY column_name            -- ascending by default; add DESC for descending
LIMIT n OFFSET m;               -- return n rows, skipping the first m
Enter fullscreen mode Exit fullscreen mode

Now let's apply this to the example tables, students and scores. Try writing each query yourself before you look at the solution.

  1. List every student's name:
SELECT name FROM students;
Enter fullscreen mode Exit fullscreen mode

The result:

name
Mary
Bob
Alice
John
Cathy
Enter fullscreen mode Exit fullscreen mode
  1. List the students in class A:
SELECT name FROM students WHERE class = 'A';
Enter fullscreen mode Exit fullscreen mode
  1. List the students' Math scores, highest first:
SELECT subject, score FROM scores WHERE subject = 'Math' ORDER BY score DESC;
Enter fullscreen mode Exit fullscreen mode

The result:

subject score
Math    91
Math    87
Math    79
Enter fullscreen mode Exit fullscreen mode
  1. Find the second-highest Math score:
SELECT subject, score FROM scores WHERE subject = 'Math' ORDER BY score DESC LIMIT 1 OFFSET 1;
Enter fullscreen mode Exit fullscreen mode

SELECT * FROM mytable; selects every column of every row. It's a quick way to see all the data at once. Try it on both example tables.

The SELECT clause can also contain expressions, so you can convert a score out of 100 to a 5-point scale like this:

SELECT subject, score * 5.0/100 AS score_out_of_5 FROM scores;
Enter fullscreen mode Exit fullscreen mode

AS names the result (an alias), which makes the output easier to read.

Note: Keep the 5.0. 5/100 is integer division in SQLite and evaluates to 0, while 5.0/100 gives 0.05.

In real work you'll often want summary statistics. Aggregate functions like SUM(), AVG(), and MIN() work on a whole column, and GROUP BY lets you calculate them for each group.

For example, to see the average score for each subject:

SELECT subject, AVG(score) AS average_score FROM scores GROUP BY subject;
Enter fullscreen mode Exit fullscreen mode

Querying two tables

Tables are joined on a matching key column. The template is:

SELECT column1, column2, ...
FROM mytable1
JOIN mytable2
  ON mytable1.column_id1 = mytable2.column_id2;  -- the two key columns to match on
Enter fullscreen mode Exit fullscreen mode

There are four kinds of join: INNER JOIN (the default, often written simply as JOIN), LEFT JOIN, RIGHT JOIN, and FULL JOIN. The two key columns don't necessarily contain the same values. The diagram below shows this: the small black circles in the orange circle are the values in column_id1 of mytable1, while those in the blue circle are the values in column_id2 of mytable2.

  • INNER JOIN (JOIN): keeps only the keys that appear in both tables—the overlap between the circles.
  • LEFT JOIN: keeps every key from mytable1 (the orange circle), filling in NULL where mytable2 has no match.
  • RIGHT JOIN: keeps every key from mytable2 (the blue circle).
  • FULL JOIN: keeps every key from both circles combined.

The four kinds of join illustrated

Suppose we want to see every student's scores in the example database:

SELECT name, subject, score
FROM students
JOIN scores ON students.id = scores.student_id;
Enter fullscreen mode Exit fullscreen mode

Change JOIN to one of the other three kinds and see how the result changes. In this example, students.id contains every value in scores.student_id. In other words, the orange circle contains the blue circle. So you'll find the result of the RIGHT JOIN query is the same as that of JOIN, and the result of the FULL JOIN query is the same as that of LEFT JOIN.

The result of the JOIN query:

name    subject score
Mary    English 88
Mary    Math    91
Bob     Math    79
John    Math    87
Enter fullscreen mode Exit fullscreen mode

The result of the LEFT JOIN query:

name    subject score
Mary    English 88
Mary    Math    91
Bob     Math    79
Alice   NULL    NULL
John    Math    87
Cathy   NULL    NULL
Enter fullscreen mode Exit fullscreen mode

Because Alice and Cathy have no scores, JOIN returns only four rows. LEFT JOIN lists them too, with NULL in the subject and score columns.

Once you have the joined table, you can treat it as a single table and apply the filtering, ordering, and column selection from earlier.

Write operations: create, update, delete

Working with rows

A row is one piece of data, such as a transaction, an online order, or an employee record, so row-level operations are common and run in real time in applications.

1. Create new rows: INSERT

The template:

INSERT INTO mytable
    (column, another_column, ...)
VALUES
    (value1, another_value1, ...),
    (value2, another_value2, ...);
Enter fullscreen mode Exit fullscreen mode

If you provide a value for every column, in table order, the column list (column, another_column, ...) can be omitted. See the INSERT statements at the top for examples.

2. Update row values: UPDATE

UPDATE mytable
SET column = value,
    another_column = another_value
WHERE condition;
Enter fullscreen mode Exit fullscreen mode

For example, if Mary changes class from 'A' to 'B':

UPDATE students
SET class = 'B'
WHERE id = 1;
Enter fullscreen mode Exit fullscreen mode

3. Delete rows: DELETE

DELETE FROM mytable
WHERE condition;
Enter fullscreen mode Exit fullscreen mode

For example, if Alice moves to another school:

DELETE FROM students
WHERE id = 3;
Enter fullscreen mode Exit fullscreen mode

A word of warning: an UPDATE or DELETE without a WHERE clause affects every row in the table. Run a SELECT with the same condition first to check what you're about to change.

Working with table structure

1. Create a new table: CREATE

The template:

CREATE TABLE IF NOT EXISTS mytable(
    column         DataType TableConstraint DEFAULT default_value,
    another_column DataType TableConstraint DEFAULT default_value
);
Enter fullscreen mode Exit fullscreen mode

See the CREATE TABLE statements at the top for examples.

2. Change a table's structure: ALTER

ALTER changes the table's structure—its columns—not the data inside it. (To change data, use UPDATE.)

To add a column:

ALTER TABLE mytable
ADD COLUMN column_name DataType DEFAULT default_value;
Enter fullscreen mode Exit fullscreen mode

For example, to add an age column to the students table:

ALTER TABLE students
ADD COLUMN age INTEGER;
Enter fullscreen mode Exit fullscreen mode

To delete a column:

ALTER TABLE mytable
DROP COLUMN column_name;
Enter fullscreen mode Exit fullscreen mode

To rename a column:

ALTER TABLE mytable
RENAME COLUMN column_name TO new_column_name;
Enter fullscreen mode Exit fullscreen mode

To rename a table:

ALTER TABLE mytable
RENAME TO new_table_name;
Enter fullscreen mode Exit fullscreen mode

Note: SQLite's ALTER TABLE can add, drop, and rename columns, but it can't change a column's type or constraints. For that, you have to rebuild the table.

Other databases, such as MySQL and PostgreSQL, support more ALTER operations.

3. Delete a table: DROP

DROP TABLE IF EXISTS mytable;
Enter fullscreen mode Exit fullscreen mode

DROP is permanent—there's no undo.

Wrapping up

That's the whole map: Create, Read, Update, Delete. Four verbs cover most of what you'll do with a database day to day.

The fastest way to make it stick is to run each query yourself. Start with the examples in this post, then move to SQLBolt. When you're comfortable, import a CSV you actually care about and try the same statements on it. Once you've practiced joins, GROUP BY and aggregate functions on real data, you'll see why people call SQL magic.

Top comments (0)