The problem was ..
Statement:
CASE WHEN column_b = '123' THEN 1 WHEN column_b = '345' THEN 2 END;
.. just for:
CASE WHEN column_b = '123' THEN 1 WHEN column_b = '345' THEN 2 ELSE NULL END
Meaning, without a WHERE , your UPDATE not just βtryingβ, it actually updates every row in the table, most of them are NULL .
Perhaps the NOT NULL on the column prevented data loss ...
The best decision:
I will have several thousand updates at once, and I would prefer to put them in one operator.
Much faster (and shorter) for large sets:
UPDATE foobar f SET column_a = val.a FROM ( VALUES (123, 1) ,(345, 2) ) val(b, a) WHERE f.column_b = val.b
Joining a set is superior to iterating through a long list of CASE branches for each row. The difference will grow rapidly with longer listings.
Also, be sure to indicate the index on column_b anyway.
You can replace the VALUES expression with any table, view, or subquery, giving the appropriate rows.
Note:
I assume that column_a and column_b are of type integer . In this case, single quotes around '123' in your question have never been helpful. You are better off using a numeric literal instead of a string literal. (Even though it also works with string literals.)
A string literal of type '123' defaults to unknown .
A numeric literal, such as 123 , defaults to integer - or bigint / numeric if the number is too large.
If you were dealing with non-standard data types, you will have to explicitly specify. It will look like this:
... FROM ( VALUES ('123'::sometype, '1'::sometype) -- first row defines row type ,('345', '2') ) val(b, a) ...