Skip to content
/ Chapter 8 · Changing Data and Tables
Lesson 8.7 · garden_shop
Lesson 8.7

UPDATE with CASE in SQL

SET column = CASE ... END gives each row its own new value. The ELSE branch decides what happens to every row you did not mean to change.

A price review rarely changes one thing. Houseplants go up, discontinued stock is cleared at half price, and everything else stays put. Two UPDATE statements can do it, but they are easy to run in the wrong order or only half of. A CASE expression from Lesson 6.2 · Labeling rows with CASE in the SET clause does it in one statement:

Pattern
update orders
set status = case
               when shipped_date is not null then 'shipped'
               when status = 'pending' then 'processing'
               else status
             end
where status <> 'cancelled';

select status, count(*) as orders
from orders
group by status
order by status;

ELSE keeps the rest

The CASE runs for every row the UPDATE touches. A row that matches no WHEN gets the ELSE value, and with no ELSE that value is NULL. So an update without a WHERE and without else price wipes the price of every product it was not meant to change. Write the ELSE even when a WHERE already limits the rows; it costs nothing and survives someone deleting the WHERE later.

The first matching WHEN wins

Branches are checked top to bottom, and a row stops at the first one that matches. A discontinued houseplant would get the clearance price here, because that branch comes first. Put the rule that should win on top.

Preview the new values

The same CASE works in a SELECT, so you can see every old and new price side by side before anything changes:

Old price, new price
select product_id,
       price as old_price,
       case
         when discontinued then round(price * 0.5, 2)
         when category_id = 1 then round(price * 1.10, 2)
         else price
       end as new_price
from products
where category_id = 1 or discontinued
order by product_id
Schema · Garden Shop Tables · products, categories 2 tables
Table · products

One row per product, with price, cost, and inventory levels.

9 columns · 24 rows
product_id int product_name text category_id int supplier_id int price decimal cost decimal quantity_on_hand int reorder_level int discontinued bool
Table · categories

Lookup table of product categories.

2 columns · 8 rows
category_id int category_name text
Your task

In one UPDATE, cut the price of discontinued products by half and raise every other Houseplants product (category_id 1) by 10%, rounding new prices to two decimals and leaving every other product's price as it is. Then return category_name, avg_price (rounded to two decimals), and max_price for each category, sorted by category_name.

·

Run your query to inspect the result.

Expected answer
  • Columns: category_name, avg_price, max_price.
  • Rows: all 8 categories, by category_name.
  • Houseplants average 25.08 with a top price of 35.2, and Outdoor Decor drops to an average of 14 because Bird Feeder is now 8.5. Every other category is unchanged.