Decisions inside a query: CASE and IIF
Turn values into labels, bands and custom sort orders with CASE. Learn the two forms, why the order of WHENs matters, what a missing ELSE does, and the shortcuts IIF and CHOOSE.
CASE is SQL’s if-then-else. It is an expression: it produces one value per row, so it can go anywhere a value can: in SELECT, ORDER BY, WHERE, even inside other functions.
Searched CASE
SELECT Name, Stock, CASE WHEN Stock = 0 THEN N'Out of stock' WHEN Stock < 20 THEN N'Low' WHEN Stock < 100 THEN N'OK' ELSE N'Plenty' END AS StockLevelFROM dbo.ProductsWHERE ProductId <= 6 OR Stock = 0;Name Stock StockLevel ---------------- ----- ------------ Claw hammer 40 OK Cordless drill 12 Low Tape measure 8 m 65 OK Cement 25 kg 300 Plenty Sand 25 kg 220 Plenty Timber 2x4 2.4 m 500 Plenty Wall plugs (100) 0 Out of stock Safety goggles 0 Out of stock
Simple CASE
=, the simple form is shorter. It cannot test ranges or NULL (because = NULL is never true):
SELECT OrderId, Status, CASE Status WHEN 'Shipped' THEN N'On its way or delivered' WHEN 'Pending' THEN N'Waiting to be packed' WHEN 'Cancelled' THEN N'Cancelled by customer' ELSE N'Check status' END AS ForCustomerFROM dbo.OrdersWHERE OrderId IN (5, 6, 8);OrderId Status ForCustomer
------- --------- -----------------------
5 Shipped On its way or delivered
6 Cancelled Cancelled by customer
8 Pending Waiting to be packedCASE in ORDER BY: a custom sort
SELECT OrderId, OrderDate, StatusFROM dbo.OrdersORDER BY CASE Status WHEN 'Pending' THEN 1 WHEN 'Shipped' THEN 2 ELSE 3 END, OrderDate DESC;OrderId OrderDate Status
------- ---------- ---------
9 2024-06-01 Pending
8 2024-05-18 Pending
10 2024-06-12 Shipped
7 2024-05-05 Shipped
5 2024-04-02 Shipped
4 2024-03-15 Shipped
3 2024-03-01 Shipped
2 2024-02-10 Shipped
1 2024-02-03 Shipped
6 2024-04-20 CancelledOne result type
SELECT Name, CASE WHEN Stock > 0 THEN Stock ELSE 'none' END AS StockShownFROM dbo.Products;Msg 245, Level 16, State 1, Line 1 Conversion failed when converting the varchar value 'none' to data type int.
CASE WHEN Stock > 0 THEN CAST(Stock AS varchar(10)) ELSE 'none' END. Type precedence is the subject of the next lesson.
IIF and CHOOSE
IIF(test, ifTrue, ifFalse) is shorthand for a CASE with one WHEN and an ELSE. CHOOSE(n, a, b, c, …) picks the nth item of a list (counting from 1). Both are rewritten into CASE behind the scenes.
SELECT Name, Price, IIF(Price >= 40, N'Big ticket', N'Everyday') AS Kind, CHOOSE(CategoryId, N'Tools', N'Building', N'Timber', N'Fixings', N'Paint', N'Safety') AS CategoryFROM dbo.ProductsWHERE ProductId IN (2, 5, 7, 11);Name Price Kind Category ------------------- ----- ---------- -------- Cordless drill 89.00 Big ticket Tools Sand 25 kg 4.10 Everyday Building Plywood sheet 18 mm 42.00 Big ticket Timber Paint roller set 12.50 Everyday Paint
Budget, under 20 is Standard, under 60 is Premium, anything else is Trade only. Show Name, Price and Band, sorted by price.
Show a hint
Show the solution
SELECT Name, Price, CASE WHEN Price < 5 THEN N'Budget' WHEN Price < 20 THEN N'Standard' WHEN Price < 60 THEN N'Premium' ELSE N'Trade only' END AS BandFROM dbo.ProductsORDER BY Price;Name Price Band ------------------- ----- ---------- Sand 25 kg 4.10 Budget Wall plugs (100) 4.50 Budget Timber 2x4 2.4 m 6.80 Standard Safety goggles 6.80 Standard Cement 25 kg 7.20 Standard Tape measure 8 m 9.75 Standard Wood screws (200) 11.90 Standard Paint roller set 12.50 Standard Claw hammer 18.50 Standard Plywood sheet 18 mm 42.00 Premium Masonry paint 10 L 54.00 Premium Cordless drill 89.00 Trade only
Remember
CASE is an expression: one value per row, usable in SELECT, ORDER BY, WHERE and inside functions. Searched CASE ( CASE WHEN cond THEN …) tests conditions; simple CASE (CASE x WHEN value THEN …) compares one expression for equality.WHENs are tried top to bottom and the first true one wins: put the narrowest first. No ELSE means NULL for unmatched rows; all branches must share one type. IIF and CHOOSE are shortcuts that become CASE.