AD JB Toolbox 01 EN

MariaDB Tutorial / Choose Conditional Values and Aggregates with CASE

CASE is an SQL expression that chooses a result according to conditions. Use it for display states or conditional aggregation, and define branch order, ELSE behavior and NULL handling because each changes which result is produced.

Distinguish an expression from procedural control

This CASE produces one value inside a SELECT expression. It is distinct from a stored-program CASE statement controlling execution of SQL statements. Searched CASE chooses the first true condition, so overlapping ranges require deliberate ordering. A correct condition can still summarize the wrong unit. Compare COUNT/SUM semantics in Summarize Rows with COUNT, SUM, AVG, MIN, and MAX and the report reconciliation in Build and Reconcile Monthly Sales, Customer Totals, and Unsold Products.

Form Purpose Important part
CASE value WHEN value THEN result Map equal codes to values Equality-based alternatives
CASE WHEN condition THEN result Ranges or compound conditions First true condition wins
ELSE result Default for unmatched cases Omission can yield NULL
END Close the expression An output alias can follow

Check the MariaDB documentation for the syntax and conditions used here: case operator.

Prepare products with different stock states

Connect to the learning server as course_user and select shopcourse. The command-line and UTF-8 SQL-file guide explains how to save the code as a UTF-8 file and execute it with SOURCE C:/mariadb-lab/lesson.sql;, replacing the path with the actual file. Run SQL inside the MariaDB client, rather than at the operating-system prompt.

Check SELECT VERSION(), DATABASE(); and SHOW TABLES; before creating products_24_lab. These names belong only to this exercise. If they exist, inspect their definitions and rows first; remove them only when you have established that they are disposable exercise objects. Do not replace existing application tables.

USE shopcourse;
CREATE TABLE products_24_lab (
  product_id INT NOT NULL AUTO_INCREMENT,
  product_name VARCHAR(100) NOT NULL,
  category VARCHAR(30) NOT NULL,
  price DECIMAL(10,2) NOT NULL,
  stock INT NOT NULL DEFAULT 0,
  note VARCHAR(100) NULL DEFAULT NULL,
  PRIMARY KEY (product_id),
  CONSTRAINT ck_p24_price CHECK (price >= 0),
  CONSTRAINT ck_p24_stock CHECK (stock >= 0)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO products_24_lab (product_id,product_name,category,price,stock,note) VALUES (1, '노트', '문구', 3500.00, 20, NULL),
  (2, '볼펜', '문구', 1500.00, 0, ''),
  (3, '머그컵', '생활', 8000.00, 12, '선물 포장'),
  (4, '스탠드', '생활', 25000.00, 5, NULL),
  (5, '파일', '문구', 1500.00, 50, ''),
  (6, '케이블', '전자', 8000.00, 0, '호환 확인');

The SQL retains the original Korean sample strings to exercise UTF-8 consistently. Product identifiers 1–6 represent a notebook, pen, mug, lamp, folder and cable; their category strings mean stationery, household and electronics. Enter the string literals as shown, use the identifiers when comparing results, and save the file with UTF-8 encoding.

There are two zero-stock products, one with stock from one through nine and three with at least ten. These are practice categories, not a complete sales-availability policy; reservations, incoming supply and disabled products may require additional states.

Put narrower overlapping conditions first

SELECT product_id,product_name,stock,
 CASE WHEN stock=0 THEN '품절'
      WHEN stock<10 THEN '재고 적음'
      ELSE '판매 가능' END AS stock_label
FROM products_24_lab ORDER BY product_id;

IDs 2 and 6 receive the out-of-stock label, ID 4 the low-stock label, and 1, 3 and 5 the available label. These output labels remain Korean in the unchanged SQL. If stock < 10 is tested first, zero qualifies there and never reaches the out-of-stock branch. Reverse only the branch order to observe the difference, then restore it.

When ELSE is omitted and no condition qualifies, CASE returns NULL. Distinguish a missing input from an undefined output branch when investigating an apparently blank result.

Compare conditional SUM with conditional COUNT

SELECT SUM(CASE WHEN stock=0 THEN 1 ELSE 0 END) AS out_of_stock,
 COUNT(CASE WHEN stock=0 THEN 1 END) AS also_out_of_stock,
 COUNT(CASE WHEN stock=0 THEN 1 ELSE 0 END) AS all_non_null,
 SUM(CASE WHEN category='문구' THEN price*stock ELSE 0 END) AS stationery_value
FROM products_24_lab;
Expression pattern Result Reason
SUM of 1 / 0 2 Adds one for each zero-stock row
COUNT of 1 / NULL 2 Other rows have NULL expressions
COUNT of 1 / 0 6 Zero is non-NULL and is counted
Stationery inventory value 145000.00 Adds price × stock only for the chosen category

COUNT does not count only numeric ones. It counts non-NULL expression results, including zeros. Choose the SUM 1/0 or COUNT 1/NULL pattern intentionally, and remember the empty-input aggregate rules if no rows qualify at all.

Keep result types and missing-value policy explicit

Mixing arbitrary strings and numeric amounts across branches makes subsequent calculations and sorting harder to reason about. Return a numeric amount separately from a display label. Whether an unknown price should become zero is a business decision.

SELECT category,
 SUM(CASE WHEN stock>0 THEN 1 ELSE 0 END) AS available_products
FROM products_24_lab GROUP BY category ORDER BY category;

The in-stock counts are stationery two, household two and electronics zero. Filtering stock > 0 with WHERE first would remove the electronics group entirely. Conditional aggregation can retain that group with a zero, so choose the method according to the report’s required shape.

Inspect the row-level branches before trusting a total

Display the primary key, stock and CASE output before summing them. Check equality versus range boundaries, AND/OR parentheses and missing ELSE branches. This SELECT computes a result without changing the stored stock value.

Before repeating the exercise, inspect the selected database, actual table definitions and stored rows, and back up anything that must be kept. Drop only this article’s disposable practice objects, with child tables before their referenced parents. DROP TABLE removes both definitions and rows and cannot be undone by an ordinary ROLLBACK; keep cleanup separate from transaction experiments.

DROP TABLE shopcourse.products_24_lab;
More in This Category
MariaDB Tutorial / Break Queries into Named Steps with WITH and CTEs

MariaDB Tutorial / Break Queries into Named Steps with WITH and CTEs

Build a readable multi-step query with WITH, verify paid orders and per-order totals independently, and understand CTE scope, naming and execution-plan limitations.

MariaDB Tutorial / Use Subqueries, EXISTS, and NOT EXISTS

MariaDB Tutorial / Use Subqueries, EXISTS, and NOT EXISTS

Choose scalar and existence subqueries according to the result needed. Compare paid-order customers and absent-order customers, inspect correlation keys and avoid NULL-related exclusion assumptions.

MariaDB Tutorial / Build and Reconcile Monthly Sales, Customer Totals, and Unsold Products

MariaDB Tutorial / Build and Reconcile Monthly Sales, Customer Totals, and Unsold Products

Create three related MariaDB reports from one order fixture, retain nonbuyers and find products without paid sales. Reconcile monthly and customer amounts and inspect join, status and date boundaries.

MariaDB Tutorial / Choose String Types: CHAR, VARCHAR, and TEXT

MariaDB Tutorial / Choose String Types: CHAR, VARCHAR, and TEXT

Compare CHAR, VARCHAR, and TEXT with runnable Unicode and trailing-space examples. Check character counts versus byte counts, length errors, comparison rules, and the optional TEXT(M) syntax.

MariaDB Tutorial / Create Users and Grant Only Required Privileges

MariaDB Tutorial / Create Users and Grant Only Required Privileges

Create a table-scoped MariaDB reader, inspect its real account identity, test allowed reads and denied operations, then verify revocation and review account dependencies before cleanup.

MariaDB Tutorial / Compare Isolation Levels, Locks, and Deadlocks with Two Connections

MariaDB Tutorial / Compare Isolation Levels, Locks, and Deadlocks with Two Connections

Follow explicit A/B steps to compare isolation, row-lock waits and deadlocks. Complete blocks cover resetting values, rereading, cleaning up failures and restoring each connection’s settings.

MariaDB Tutorial / Sort and Paginate Results with ORDER BY and LIMIT

MariaDB Tutorial / Sort and Paginate Results with ORDER BY and LIMIT

Create deterministic top lists, compare OFFSET and keyset pagination, and control NULL placement in MariaDB. Observe tied prices and understand concurrency and large-offset limitations.

MariaDB Tutorial / Build, Secure, Back Up, and Verify an Order Database

MariaDB Tutorial / Build, Secure, Back Up, and Verify an Order Database

Complete an order-database workflow using constrained tables, a limited app account and a checked stock transaction. Define and compare committed-state backup and restoration criteria, including denied operations.

MariaDB Tutorial / Filter Rows with WHERE, AND, OR, IN, BETWEEN, and LIKE

MariaDB Tutorial / Filter Rows with WHERE, AND, OR, IN, BETWEEN, and LIKE

Build clear MariaDB filters using comparisons, grouped AND/OR conditions, IN lists, inclusive ranges and escaped LIKE patterns. Check expected product IDs and investigate missing or extra rows.

MariaDB Tutorial / Read Related Rows with INNER JOIN

MariaDB Tutorial / Read Related Rows with INNER JOIN

Join customer names to orders with explicit relationship keys, interpret repeated customers correctly and compare filtered INNER JOIN results with an unrestricted Cartesian product.