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:
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:
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
One row per product, with price, cost, and inventory levels.
Lookup table of product categories.
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.
Related
A checklist for changing the right rows.
Searched and simple CASE, plus conditional aggregation.
Change existing rows safely.
Add if/else logic to query results.
Wrap risky changes so you can undo them.