DML Practice (INSERT, UPDATE, DELETE)
Tables
products — Products (name, price, stock, brand)
customers — Customers (grade, points, channel)
orders — Orders (status, amount, date)
order_items — Order items (qty, unit price)
Concepts
INSERT INTO, UPDATE SET, DELETE FROM, INSERT INTO SELECT, subquery DML, UPSERT, ON CONFLICT
1. Create a practice product table and insert one product.
Create a practice product table and insert one product.
Hint 1: CREATE TABLE temp_products AS SELECT * FROM products WHERE 1=0 — creates an empty table copying only the structure.
Answer
CREATE TABLE temp_products AS
SELECT * FROM products WHERE 1 = 0;
INSERT INTO temp_products (id, category_id, supplier_id, name, sku, brand, price, cost_price, stock_qty, is_active, created_at, updated_at)
VALUES (9001, 1, 1, '테스트 키보드', 'TEST-KB-001', 'TestBrand', 89000, 45000, 100, 1, '2025-01-01', '2025-01-01');
SELECT * FROM temp_products;
DROP TABLE temp_products;
2. Insert multiple rows into the practice product table at once
Insert multiple rows into the practice product table at once.
Hint 1: INSERT INTO ... VALUES (...), (...), (...) — SQLite supports multiple VALUES rows in one INSERT.
Answer
CREATE TABLE temp_products AS
SELECT * FROM products WHERE 1 = 0;
INSERT INTO temp_products (id, category_id, supplier_id, name, sku, brand, price, cost_price, stock_qty, is_active, created_at, updated_at)
VALUES
(9001, 1, 1, '테스트 마우스', 'TEST-MS-001', 'TestBrand', 35000, 18000, 200, 1, '2025-01-01', '2025-01-01'),
(9002, 1, 1, '테스트 패드', 'TEST-PD-001', 'TestBrand', 15000, 7000, 500, 1, '2025-01-01', '2025-01-01'),
(9003, 2, 1, '테스트 모니터', 'TEST-MN-001', 'TestBrand', 350000, 200000, 50, 1, '2025-01-01', '2025-01-01');
SELECT id, name, price FROM temp_products;
DROP TABLE temp_products;
3. Update the price of a specific product in the practice table
Update the price of a specific product in the practice table.
Hint 1: UPDATE temp_products SET price = ... WHERE id = ... — always include a WHERE clause.
Answer
CREATE TABLE temp_products AS
SELECT * FROM products WHERE 1 = 0;
INSERT INTO temp_products (id, category_id, supplier_id, name, sku, brand, price, cost_price, stock_qty, is_active, created_at, updated_at)
VALUES
(9001, 1, 1, '테스트 키보드', 'TEST-KB-001', 'TestBrand', 89000, 45000, 100, 1, '2025-01-01', '2025-01-01'),
(9002, 1, 1, '테스트 마우스', 'TEST-MS-001', 'TestBrand', 35000, 18000, 200, 1, '2025-01-01', '2025-01-01');
UPDATE temp_products
SET price = 79000, updated_at = '2025-06-01'
WHERE id = 9001;
SELECT id, name, price, updated_at FROM temp_products;
DROP TABLE temp_products;
4. Delete a specific product from the practice table.
Delete a specific product from the practice table.
Hint 1: DELETE FROM temp_products WHERE id = ... — running without WHERE deletes all data.
Answer
CREATE TABLE temp_products AS
SELECT * FROM products WHERE 1 = 0;
INSERT INTO temp_products (id, category_id, supplier_id, name, sku, brand, price, cost_price, stock_qty, is_active, created_at, updated_at)
VALUES
(9001, 1, 1, '테스트 키보드', 'TEST-KB-001', 'TestBrand', 89000, 45000, 100, 1, '2025-01-01', '2025-01-01'),
(9002, 1, 1, '테스트 마우스', 'TEST-MS-001', 'TestBrand', 35000, 18000, 200, 1, '2025-01-01', '2025-01-01'),
(9003, 1, 1, '테스트 패드', 'TEST-PD-001', 'TestBrand', 15000, 7000, 500, 1, '2025-01-01', '2025-01-01');
DELETE FROM temp_products WHERE id = 9002;
SELECT id, name FROM temp_products;
DROP TABLE temp_products;
5. Create a practice customer table and bulk-change all 'BRONZE
Create a practice customer table and bulk-change all 'BRONZE' grades to 'SILVER'.
Hint 1: UPDATE temp_customers SET grade = 'SILVER' WHERE grade = 'BRONZE' — all matching rows are changed.
Answer
CREATE TABLE temp_customers AS
SELECT id, name, email, grade, point_balance
FROM customers
LIMIT 50;
SELECT grade, COUNT(*) AS cnt FROM temp_customers GROUP BY grade;
UPDATE temp_customers
SET grade = 'SILVER'
WHERE grade = 'BRONZE';
SELECT grade, COUNT(*) AS cnt FROM temp_customers GROUP BY grade;
DROP TABLE temp_customers;
6. Delete all customers with zero points from the practice tabl
Delete all customers with zero points from the practice table. Compare counts before and after deletion.
Hint 1: Run SELECT COUNT(*) before deletion, execute DELETE, then run SELECT COUNT(*) after.
Answer
7. Increase all product prices by 10% in the practice table.
Increase all product prices by 10% in the practice table.
Hint 1: UPDATE temp_products SET price = ROUND(price * 1.1, 2) — use ROUND to clean up decimal places.
Answer
CREATE TABLE temp_products AS
SELECT id, name, price
FROM products
WHERE is_active = 1
LIMIT 20;
SELECT name, price FROM temp_products ORDER BY price DESC LIMIT 5;
UPDATE temp_products
SET price = ROUND(price * 1.1, 2);
SELECT name, price FROM temp_products ORDER BY price DESC LIMIT 5;
DROP TABLE temp_products;
8. Use INSERT OR REPLACE (UPSERT) to insert a product, updating
Use INSERT OR REPLACE (UPSERT) to insert a product, updating price if it already exists.
Hint 1: The table needs a UNIQUE constraint. Create with UNIQUE(sku) then use INSERT OR REPLACE.
Answer
CREATE TABLE temp_products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
sku TEXT NOT NULL UNIQUE,
price REAL NOT NULL
);
INSERT INTO temp_products VALUES (1, '무선 마우스', 'WM-001', 35000);
INSERT INTO temp_products VALUES (2, '기계식 키보드', 'MK-001', 89000);
SELECT * FROM temp_products;
INSERT OR REPLACE INTO temp_products VALUES (1, '무선 마우스 v2', 'WM-001', 39000);
SELECT * FROM temp_products;
DROP TABLE temp_products;
9. Write a more precise UPSERT using ON CONFLICT. Only update t
Write a more precise UPSERT using ON CONFLICT. Only update the price on conflict.
Hint 1: ON CONFLICT(sku) DO UPDATE SET price = excluded.price — excluded references the new values being inserted.
Answer
CREATE TABLE temp_products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
sku TEXT NOT NULL UNIQUE,
price REAL NOT NULL,
updated_at TEXT
);
INSERT INTO temp_products VALUES (1, '무선 마우스', 'WM-001', 35000, '2025-01-01');
INSERT INTO temp_products VALUES (2, '기계식 키보드', 'MK-001', 89000, '2025-01-01');
INSERT INTO temp_products (id, name, sku, price, updated_at)
VALUES (1, '무선 마우스 NEW', 'WM-001', 42000, '2025-06-01')
ON CONFLICT(sku) DO UPDATE SET
price = excluded.price,
updated_at = excluded.updated_at;
SELECT * FROM temp_products;
DROP TABLE temp_products;
10. Conditional UPDATE: Increase prices by 5% only for products
Conditional UPDATE: Increase prices by 5% only for products with stock below 10.
Hint 1: UPDATE ... SET price = ROUND(price * 1.05, 2) WHERE stock_qty < 10 — price increase only for low-stock products.
Answer
CREATE TABLE temp_products AS
SELECT id, name, price, stock_qty
FROM products
WHERE is_active = 1
LIMIT 30;
SELECT name, price, stock_qty
FROM temp_products
WHERE stock_qty < 10
ORDER BY stock_qty;
UPDATE temp_products
SET price = ROUND(price * 1.05, 2)
WHERE stock_qty < 10;
SELECT name, price, stock_qty
FROM temp_products
WHERE stock_qty < 10
ORDER BY stock_qty;
DROP TABLE temp_products;
11. Use INSERT...SELECT to copy VIP customers into a separate ta
Use INSERT...SELECT to copy VIP customers into a separate table.
Hint 1: INSERT INTO temp_vip SELECT ... FROM customers WHERE grade = 'VIP' — use SELECT instead of VALUES.
Answer
CREATE TABLE temp_vip (
id INTEGER,
name TEXT,
email TEXT,
grade TEXT,
point_balance INTEGER
);
INSERT INTO temp_vip
SELECT id, name, email, grade, point_balance
FROM customers
WHERE grade = 'VIP';
SELECT COUNT(*) AS vip_count FROM temp_vip;
SELECT name, point_balance FROM temp_vip ORDER BY point_balance DESC LIMIT 10;
DROP TABLE temp_vip;
12. Use INSERT...SELECT to create a 2025 monthly revenue summary
Use INSERT...SELECT to create a 2025 monthly revenue summary table.
Hint 1: CREATE TABLE AS SELECT creates the table and inserts data simultaneously.
Answer
CREATE TABLE temp_monthly_sales AS
SELECT
SUBSTR(ordered_at, 1, 7) AS month,
COUNT(*) AS order_count,
COUNT(DISTINCT customer_id) AS customer_count,
ROUND(SUM(total_amount), 2) AS revenue,
ROUND(AVG(total_amount), 2) AS avg_order
FROM orders
WHERE ordered_at LIKE '2025%'
AND status NOT IN ('cancelled')
GROUP BY SUBSTR(ordered_at, 1, 7);
SELECT * FROM temp_monthly_sales ORDER BY month;
DROP TABLE temp_monthly_sales;
13. Use CASE in a conditional UPDATE: award bonus points by grad
Use CASE in a conditional UPDATE: award bonus points by grade.
Hint 1: Use CASE in SET for tiered bonus by grade.
Answer
CREATE TABLE temp_customers AS
SELECT id, name, grade, point_balance
FROM customers
LIMIT 50;
SELECT grade, ROUND(AVG(point_balance)) AS avg_point
FROM temp_customers
GROUP BY grade;
UPDATE temp_customers
SET point_balance = point_balance +
CASE grade
WHEN 'VIP' THEN 5000
WHEN 'GOLD' THEN 3000
WHEN 'SILVER' THEN 1000
ELSE 500
END;
SELECT grade, ROUND(AVG(point_balance)) AS avg_point
FROM temp_customers
GROUP BY grade;
DROP TABLE temp_customers;
14. Use a subquery in UPDATE: deduct stock based on order quanti
Use a subquery in UPDATE: deduct stock based on order quantities.
Hint 1: Use COALESCE for NULL handling when the subquery returns no rows.
Answer
CREATE TABLE temp_products AS
SELECT id, name, stock_qty
FROM products
WHERE is_active = 1
LIMIT 20;
SELECT name, stock_qty FROM temp_products ORDER BY name LIMIT 5;
UPDATE temp_products
SET stock_qty = stock_qty - COALESCE(
(SELECT SUM(oi.quantity)
FROM order_items AS oi
INNER JOIN orders AS o ON oi.order_id = o.id
WHERE oi.product_id = temp_products.id
AND o.status NOT IN ('cancelled')
AND o.ordered_at LIKE '2025%'),
0
);
SELECT name, stock_qty FROM temp_products ORDER BY name LIMIT 5;
DROP TABLE temp_products;
15. Product catalog copy and cleanup: perform a 3-step process o
Product catalog copy and cleanup: perform a 3-step process of copy, mark, delete.
Hint 1: Step 1: Copy, Step 2: Mark discontinued, Step 3: Delete marked. Verify after each step.
Answer
CREATE TABLE temp_products AS
SELECT id, name, price, is_active, discontinued_at
FROM products;
SELECT COUNT(*) AS total FROM temp_products;
UPDATE temp_products
SET is_active = 0
WHERE discontinued_at IS NOT NULL;
SELECT
SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) AS active,
SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END) AS inactive
FROM temp_products;
DELETE FROM temp_products WHERE is_active = 0;
SELECT COUNT(*) AS remaining FROM temp_products;
DROP TABLE temp_products;
16. Safe delete pattern: verify deletion targets before deleting
Safe delete pattern: verify deletion targets before deleting.
Hint 1: Run a SELECT with the same WHERE condition as your DELETE first to verify targets and count.
Answer
CREATE TABLE temp_orders AS
SELECT id, order_number, customer_id, status, total_amount, ordered_at
FROM orders
WHERE ordered_at LIKE '2024%'
LIMIT 200;
SELECT COUNT(*) AS to_delete
FROM temp_orders
WHERE status = 'cancelled';
SELECT order_number, total_amount, ordered_at
FROM temp_orders
WHERE status = 'cancelled'
LIMIT 10;
DELETE FROM temp_orders WHERE status = 'cancelled';
SELECT COUNT(*) AS remaining FROM temp_orders;
SELECT status, COUNT(*) FROM temp_orders GROUP BY status;
DROP TABLE temp_orders;
17. Use INSERT...SELECT with aggregation to create a per-custome
Use INSERT...SELECT with aggregation to create a per-customer purchase statistics table.
Hint 1: Materialize the aggregation result into a table.
Answer
CREATE TABLE temp_customer_stats AS
SELECT
c.id AS customer_id,
c.name,
c.grade,
COUNT(o.id) AS order_count,
ROUND(SUM(o.total_amount), 2) AS total_spent,
ROUND(AVG(o.total_amount), 2) AS avg_order,
MAX(o.ordered_at) AS last_order_at
FROM customers AS c
INNER JOIN orders AS o ON c.id = o.customer_id
WHERE o.status NOT IN ('cancelled')
GROUP BY c.id, c.name, c.grade;
SELECT name, grade, order_count, total_spent, last_order_at
FROM temp_customer_stats
ORDER BY total_spent DESC
LIMIT 10;
DROP TABLE temp_customer_stats;
18. Combine multiple conditions in a bulk UPDATE: deactivate cus
Combine multiple conditions in a bulk UPDATE: deactivate customers with no orders in the past year.
Hint 1: Use a subquery to find customers with no recent orders.
Answer
CREATE TABLE temp_customers AS
SELECT id, name, grade, is_active, created_at
FROM customers;
SELECT
SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) AS active,
SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END) AS inactive
FROM temp_customers;
UPDATE temp_customers
SET is_active = 0
WHERE id NOT IN (
SELECT DISTINCT customer_id
FROM orders
WHERE ordered_at >= DATE('now', '-1 year')
AND status NOT IN ('cancelled')
);
SELECT
SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) AS active,
SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END) AS inactive
FROM temp_customers;
DROP TABLE temp_customers;
19. Perform multi-step DML like a transaction: refund points and
Perform multi-step DML like a transaction: refund points and restore stock on order cancellation.
Hint 1: 1) Change order status to 'cancelled', 2) Refund used points to customer, 3) Restore stock. Perform three steps in order.
Answer
CREATE TABLE temp_orders AS
SELECT id, order_number, customer_id, status, total_amount, point_used
FROM orders
WHERE status = 'paid'
LIMIT 5;
CREATE TABLE temp_customers AS
SELECT id, name, point_balance
FROM customers
WHERE id IN (SELECT customer_id FROM temp_orders);
CREATE TABLE temp_products AS
SELECT id, name, stock_qty
FROM products
WHERE id IN (
SELECT product_id FROM order_items
WHERE order_id IN (SELECT id FROM temp_orders)
);
UPDATE temp_orders
SET status = 'cancelled'
WHERE id = (SELECT MIN(id) FROM temp_orders);
UPDATE temp_customers
SET point_balance = point_balance + COALESCE(
(SELECT point_used FROM temp_orders
WHERE id = (SELECT MIN(id) FROM temp_orders WHERE status = 'cancelled')
AND status = 'cancelled'),
0
)
WHERE id = (
SELECT customer_id FROM temp_orders
WHERE status = 'cancelled' LIMIT 1
);
UPDATE temp_products
SET stock_qty = stock_qty + COALESCE(
(SELECT SUM(oi.quantity)
FROM order_items AS oi
WHERE oi.order_id = (SELECT MIN(id) FROM temp_orders WHERE status = 'cancelled')
AND oi.product_id = temp_products.id),
0
);
SELECT '주문' AS table_name, order_number, status FROM temp_orders
UNION ALL
SELECT '고객', name, CAST(point_balance AS TEXT) FROM temp_customers LIMIT 3;
DROP TABLE temp_orders;
DROP TABLE temp_customers;
DROP TABLE temp_products;
20. Data normalization: split a denormalized table into two norm
Data normalization: split a denormalized table into two normalized tables.
Hint 1: 1) Create denormalized table with sample data. 2) Extract brand master using DISTINCT. 3) Link product table with brand_id.
Answer
CREATE TABLE temp_raw_products (
id INTEGER PRIMARY KEY,
name TEXT,
brand_name TEXT,
price REAL
);
INSERT INTO temp_raw_products
SELECT id, name, brand, price
FROM products
LIMIT 30;
CREATE TABLE temp_brands (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE
);
INSERT INTO temp_brands (name)
SELECT DISTINCT brand_name
FROM temp_raw_products
ORDER BY brand_name;
SELECT * FROM temp_brands ORDER BY id LIMIT 10;
CREATE TABLE temp_norm_products (
id INTEGER,
name TEXT,
brand_id INTEGER,
price REAL
);
INSERT INTO temp_norm_products
SELECT r.id, r.name, b.id, r.price
FROM temp_raw_products AS r
INNER JOIN temp_brands AS b ON r.brand_name = b.name;
SELECT np.id, np.name, b.name AS brand, np.price
FROM temp_norm_products AS np
INNER JOIN temp_brands AS b ON np.brand_id = b.id
ORDER BY b.name, np.name
LIMIT 10;
DROP TABLE temp_raw_products;
DROP TABLE temp_brands;
DROP TABLE temp_norm_products;