CRUD Basics

CRUD Basics

CRUD stands for Create, Read, Update, and Delete - the basic operations for database data.

0. Practice Setup

-- Create practice table
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    age INTEGER,
    city VARCHAR(100),
    created_at TIMESTAMP DEFAULT NOW()
);

1. INSERT - Data Insertion

Insert Single Row

-- Specify all columns
INSERT INTO users (name, email, age, city)
VALUES ('John Kim', 'kim@email.com', 30, 'Seoul');

-- Specify only some columns (others will be DEFAULT or NULL)
INSERT INTO users (name, email)
VALUES ('Jane Lee', 'lee@email.com');

Insert Multiple Rows

INSERT INTO users (name, email, age, city) VALUES
('Michael Park', 'park@email.com', 25, 'Busan'),
('Sarah Choi', 'choi@email.com', 28, 'Daejeon'),
('Emma Jung', 'jung@email.com', 35, 'Seoul');

Using DEFAULT Values

-- Use DEFAULT for specific column
INSERT INTO users (name, email, age, city, created_at)
VALUES ('David Hong', 'hong@email.com', 40, 'Incheon', DEFAULT);

-- All columns DEFAULT (id auto-generated only)
INSERT INTO users DEFAULT VALUES;  -- Error: NOT NULL columns

RETURNING - Return Inserted Data

-- Return generated ID after insert
INSERT INTO users (name, email, age, city)
VALUES ('Tommy Shin', 'shin@email.com', 5, 'Springfield')
RETURNING id;

-- Return multiple columns
INSERT INTO users (name, email, age, city)
VALUES ('Mary Kim', 'mikim@email.com', 32, 'Seoul')
RETURNING id, name, created_at;

-- Return all columns
INSERT INTO users (name, email)
VALUES ('Test User', 'test@email.com')
RETURNING *;

2. SELECT - Data Querying

Query All Data

-- All columns
SELECT * FROM users;

-- Specific columns only
SELECT name, email FROM users;

Column Aliases

SELECT
    name AS user_name,
    email AS user_email,
    age AS user_age
FROM users;

-- AS can be omitted
SELECT name user_name, email user_email FROM users;

Remove Duplicates (DISTINCT)

-- Remove duplicate cities
SELECT DISTINCT city FROM users;

-- Remove duplicates of column combinations
SELECT DISTINCT city, age FROM users;

Calculations and Expressions

-- Calculations
SELECT name, age, age + 10 AS age_after_10_years FROM users;

-- String concatenation
SELECT name || ' (' || email || ')' AS user_info FROM users;

-- CONCAT function
SELECT CONCAT(name, ' - ', city) AS name_city FROM users;

Conditional Queries (Brief)

-- WHERE clause (details in next chapter)
SELECT * FROM users WHERE city = 'Seoul';
SELECT * FROM users WHERE age >= 30;

3. UPDATE - Data Modification

Basic UPDATE

-- Update specific row
UPDATE users
SET age = 31
WHERE name = 'John Kim';

-- Update multiple columns
UPDATE users
SET age = 26, city = 'Daegu'
WHERE email = 'park@email.com';

UPDATE Without Condition (Caution!)

-- All rows will be updated!
UPDATE users SET city = 'Seoul';  -- Dangerous!

-- Always check WHERE clause

UPDATE with Calculations

-- Increment all users' age by 1
UPDATE users SET age = age + 1;

-- Only specific condition users
UPDATE users SET age = age + 1 WHERE city = 'Seoul';

RETURNING to Check Updated Data

UPDATE users
SET age = 32
WHERE name = 'Jane Lee'
RETURNING *;

UPDATE users
SET city = 'Gwangju'
WHERE age < 30
RETURNING id, name, city;

Set to NULL

UPDATE users
SET city = NULL
WHERE name = 'Test User';

4. DELETE - Data Deletion

Basic DELETE

-- Delete specific row
DELETE FROM users WHERE name = 'Test User';

-- Multiple conditions
DELETE FROM users WHERE city IS NULL AND age IS NULL;

DELETE Without Condition (Caution!)

-- Delete all data!
DELETE FROM users;  -- Dangerous!

-- Table remains

RETURNING to Check Deleted Data

DELETE FROM users
WHERE email = 'test@email.com'
RETURNING *;

TRUNCATE - Empty Table

-- Faster than DELETE (no logging, delete entire table)
TRUNCATE TABLE users;

-- Restart SERIAL
TRUNCATE TABLE users RESTART IDENTITY;

-- With related tables (foreign keys)
TRUNCATE TABLE users CASCADE;

DELETE vs TRUNCATE

Feature DELETE TRUNCATE
WHERE condition Possible Not possible
Speed Slow Fast
Transaction rollback Possible Limited
RETURNING Possible Not possible
Trigger execution Executes Doesn't execute
SERIAL reset No Optional

5. UPSERT (ON CONFLICT)

Insert or update if conflict occurs.

Ignore on Conflict

-- Do nothing if already exists
INSERT INTO users (name, email, age, city)
VALUES ('John Kim', 'kim@email.com', 35, 'Busan')
ON CONFLICT (email) DO NOTHING;

Update on Conflict

-- Update if already exists
INSERT INTO users (name, email, age, city)
VALUES ('John Kim', 'kim@email.com', 35, 'Busan')
ON CONFLICT (email)
DO UPDATE SET
    age = EXCLUDED.age,
    city = EXCLUDED.city;

EXCLUDED Keyword

EXCLUDED references the data that was attempted to be inserted.

INSERT INTO users (name, email, age, city)
VALUES ('John Kim', 'kim@email.com', 35, 'Busan')
ON CONFLICT (email)
DO UPDATE SET
    age = EXCLUDED.age,           -- New value (35)
    city = users.city,            -- Keep existing value
    name = EXCLUDED.name;         -- New value (John Kim)

Conditional UPSERT

INSERT INTO users (name, email, age, city)
VALUES ('John Kim', 'kim@email.com', 35, 'Busan')
ON CONFLICT (email)
DO UPDATE SET
    age = EXCLUDED.age,
    city = EXCLUDED.city
WHERE users.age < EXCLUDED.age;  -- Only update if new age is greater

6. INSERT with Subquery

Insert SELECT Results

-- Copy from another table
CREATE TABLE users_backup AS SELECT * FROM users;

-- Or
INSERT INTO users_backup SELECT * FROM users;

-- Conditional copy
INSERT INTO users_backup
SELECT * FROM users WHERE city = 'Seoul';

Insert Calculated Values

INSERT INTO statistics (city, user_count)
SELECT city, COUNT(*) FROM users GROUP BY city;

7. Practice Examples

Prepare Practice Data

-- Reset table
TRUNCATE TABLE users RESTART IDENTITY;

-- Insert sample data
INSERT INTO users (name, email, age, city) VALUES
('John Kim', 'kim@email.com', 30, 'Seoul'),
('Jane Lee', 'lee@email.com', 25, 'Busan'),
('Michael Park', 'park@email.com', 35, 'Seoul'),
('Sarah Choi', 'choi@email.com', 28, 'Daejeon'),
('Emma Jung', 'jung@email.com', 32, 'Seoul'),
('David Hong', 'hong@email.com', 40, 'Incheon'),
('Kevin Kang', 'kang@email.com', 27, 'Busan'),
('Lisa Son', 'son@email.com', 33, 'Seoul');

Practice 1: Basic CRUD

-- 1. Add new user
INSERT INTO users (name, email, age, city)
VALUES ('New User', 'new@email.com', 22, 'Gwangju')
RETURNING *;

-- 2. Query Seoul users
SELECT * FROM users WHERE city = 'Seoul';

-- 3. Change city to 'Metropolitan' for users age 30+
UPDATE users
SET city = 'Metropolitan'
WHERE age >= 30
RETURNING name, age, city;

-- 4. Delete Gwangju users
DELETE FROM users
WHERE city = 'Gwangju'
RETURNING *;

Practice 2: UPSERT

-- Update age and city if email already exists
INSERT INTO users (name, email, age, city)
VALUES ('John Kim', 'kim@email.com', 31, 'Gyeonggi')
ON CONFLICT (email)
DO UPDATE SET
    age = EXCLUDED.age,
    city = EXCLUDED.city
RETURNING *;

-- Insert if email doesn't exist
INSERT INTO users (name, email, age, city)
VALUES ('New Member', 'newuser@email.com', 29, 'Jeju')
ON CONFLICT (email)
DO UPDATE SET age = EXCLUDED.age, city = EXCLUDED.city
RETURNING *;

Practice 3: Bulk Data Processing

-- Create backup table and copy data
CREATE TABLE users_backup AS
SELECT * FROM users WHERE 1=0;  -- Copy structure only

INSERT INTO users_backup
SELECT * FROM users;

-- Backup only specific condition users
INSERT INTO users_backup
SELECT * FROM users WHERE city IN ('Seoul', 'Busan');

-- Check backup
SELECT COUNT(*) FROM users_backup;

8. Precautions and Tips

Prevent SQL Injection

-- Bad example (direct string concatenation)
-- "SELECT * FROM users WHERE name = '" + userInput + "'"

-- Good example (use parameter binding - in application)
-- "SELECT * FROM users WHERE name = $1"

Verify Before UPDATE/DELETE

-- 1. First check with SELECT
SELECT * FROM users WHERE city = 'Seoul';

-- 2. Execute UPDATE/DELETE after confirmation
UPDATE users SET age = age + 1 WHERE city = 'Seoul';

Use Transactions

-- Use transactions for important operations
BEGIN;
UPDATE users SET age = age + 1 WHERE city = 'Seoul';
-- Check results then
COMMIT;  -- or ROLLBACK;

Next Steps

Learn about WHERE clauses and ORDER BY in detail in 05_Conditions_and_Sorting.md!

to navigate between lessons