Lab 03: Inserting and Querying Data

Time: 30 minutes | Level: Foundations | DB: MySQL 8 / PostgreSQL 15

Overview

Learn to insert single and multiple rows, query with SELECT, use column aliases, and handle upsert patterns with REPLACE INTO (MySQL) and INSERT … ON CONFLICT (PostgreSQL).


Step 1: Setup

docker run -d --name mysql-lab -e MYSQL_ROOT_PASSWORD=rootpass mysql:8.0
for i in $(seq 1 30); do docker exec mysql-lab mysql -uroot -prootpass -e "SELECT 1" 2>/dev/null && break || sleep 2; done

docker run -d --name pg-lab -e POSTGRES_PASSWORD=rootpass postgres:15
sleep 10

Create the schema:

docker exec mysql-lab mysql -uroot -prootpass -e "
CREATE DATABASE IF NOT EXISTS shop;
USE shop;
CREATE TABLE products (
    product_id   INT          NOT NULL AUTO_INCREMENT,
    name         VARCHAR(100) NOT NULL,
    category     VARCHAR(50)  NOT NULL,
    price        DECIMAL(10,2) NOT NULL,
    stock        INT          NOT NULL DEFAULT 0,
    created_at   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (product_id)
);"

docker exec pg-lab psql -U postgres -c "CREATE DATABASE shop;"
docker exec pg-lab psql -U postgres -d shop -c "
CREATE TABLE products (
    product_id   SERIAL        PRIMARY KEY,
    name         VARCHAR(100)  NOT NULL,
    category     VARCHAR(50)   NOT NULL,
    price        NUMERIC(10,2) NOT NULL,
    stock        INT           NOT NULL DEFAULT 0,
    created_at   TIMESTAMP     DEFAULT CURRENT_TIMESTAMP
);"

Step 2: INSERT INTO — Single Row

MySQL:

📸 Verified Output (MySQL):

PostgreSQL:

📸 Verified Output (PostgreSQL):

💡 PostgreSQL's RETURNING clause is very useful — it lets you retrieve generated values (like auto-increment IDs) without a separate SELECT.


Step 3: INSERT INTO — Multiple Rows

📸 Verified Output (MySQL):

💡 Multi-row inserts are significantly faster than separate INSERT statements because they reduce round-trips and transaction overhead.


Step 4: SELECT * and SELECT Columns

📸 Verified Output (MySQL):


Step 5: Column Aliases with AS

📸 Verified Output:

💡 Aliases (AS) rename columns in the result set. They don't affect the underlying table. You can omit AS keyword but it's best practice to include it for readability.


Step 6: INSERT … SELECT (Copy Rows)

📸 Verified Output:


Step 7: REPLACE INTO (MySQL) vs INSERT … ON CONFLICT (PostgreSQL)

These handle upsert — insert if not exists, update if it does.

MySQL — REPLACE INTO:

📸 Verified Output (MySQL):

⚠️ REPLACE INTO first DELETEs the row then INSERTs. This resets auto-increment counters and triggers DELETE triggers. Prefer INSERT … ON DUPLICATE KEY UPDATE for fine-grained control.

PostgreSQL — INSERT … ON CONFLICT:

📸 Verified Output (PostgreSQL):

💡 EXCLUDED refers to the row that was attempted to be inserted. This is the standard PostgreSQL upsert pattern.


Step 8: Capstone — Verify Row Counts

📸 Verified Output:

Cleanup:


Summary

Operation
MySQL
PostgreSQL

Single INSERT

INSERT INTO t (cols) VALUES (...)

Same

Multi-row INSERT

INSERT INTO t VALUES (...),(...)

Same

Get inserted ID

LAST_INSERT_ID()

RETURNING id

Copy rows

INSERT INTO t2 SELECT ... FROM t1

Same

Upsert (delete+insert)

REPLACE INTO

N/A

Upsert (merge)

INSERT ... ON DUPLICATE KEY UPDATE

INSERT ... ON CONFLICT DO UPDATE

Count rows

SELECT COUNT(*) FROM t

Same

Next: Lab 04 — Filtering and Sorting

Last updated