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 / Insert One Row or Multiple Rows with INSERT

MariaDB Tutorial / Insert One Row or Multiple Rows with INSERT

Practice single-row and multi-row INSERT statements, inspect stored values and defaults, and test duplicate keys, mismatched value counts and required inputs without changing existing product tables.

MariaDB Tutorial / Query Hierarchies and Prevent Cycles with Recursive CTEs

MariaDB Tutorial / Query Hierarchies and Prevent Cycles with Recursive CTEs

Traverse a complete category tree with WITH RECURSIVE, depth, and path tracking. Change the traversal bound, introduce a controlled cycle, and distinguish a finite result from a complete and valid hierarchy.

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 / What MariaDB Is: Databases, SQL, and Its Relationship to MySQL

MariaDB Tutorial / What MariaDB Is: Databases, SQL, and Its Relationship to MySQL

Understand the roles of the MariaDB server and client, the structure of relational data, and the purpose of SQL. Learn how MariaDB relates to MySQL and prepare for a small product-database exercise.

MariaDB Tutorial / Build a Local MariaDB Lab with Docker Compose

MariaDB Tutorial / Build a Local MariaDB Lab with Docker Compose

Configure a local MariaDB container with Compose, file-based secrets, a healthcheck, and a named volume. Verify connections and distinguish container replacement from deleting persistent data.

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 / Choose Conditional Values and Aggregates with CASE

MariaDB Tutorial / Choose Conditional Values and Aggregates with CASE

Use CASE for stock labels and conditional reports. Compare branch order, ELSE and NULL behavior, and understand why COUNT with ELSE 0 counts every non-NULL result.

MariaDB Tutorial / Import and Export CSV with Correct Paths, Types, and Encoding

MariaDB Tutorial / Import and Export CSV with Correct Paths, Types, and Encoding

Stage and validate a UTF-8 CSV before converting IDs and prices, then export through a server-side path. Review quoting, warnings, normalized duplicates, numeric bounds and field-level round-trip checks.

MariaDB Tutorial / Identify Rows with PRIMARY KEY, AUTO_INCREMENT, and UNIQUE

MariaDB Tutorial / Identify Rows with PRIMARY KEY, AUTO_INCREMENT, and UNIQUE

Use primary keys, generated identifiers, and unique constraints for different purposes. Practice nullable unique email values, composite keys, duplicate failures, and the identifier gap left by a rolled-back insert.

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.