'Shorthand CASE with additional conditions

Up until today I held as true the notion that shorthand CASE doesn't accept additional conditions, as in

CASE evaluate_this
WHEN TRUE AND another_field ... THEN ...

would never work.

Today, as I was distractingly writing some code, I violated this rule just to realise that one CASE expression still worked as intended, the other didn't. Assuming the following data:

id boolean_one boolean_two field_one field_two
1 TRUE TRUE NULL 'a'
2 TRUE FALSE 2 'a'
3 FALSE TRUE 8 NULL
4 FALSE FALSE NULL NULL

The one that did not work looked like this:

CASE boolean_one
  WHEN TRUE AND field_one IS NOT NULL THEN field_one * UNIFORM(1, 10, RANDOM())
  ELSE field_one
END AS new_field_one

The idea is that in most circumstances the value for new_field_one should match field_one, the only exception being when boolean_one = TRUE AND field_one IS NOT NULL in which case it should be assigned the product of field_one and a random integer.

Below the desired and actual values for new_field_one based on the above

id desired actual
1 NULL NULL
2 20 20
3 8 8
4 NULL 5

So it applies the randomisation also when boolean_one = FALSE AND field_one IS NULL. Fixing the expression to

CASE
  WHEN boolean_one = TRUE AND field_one IS NOT NULL THEN...

solves the issue. What I find more interesting, and confusing, is that the second expression still did what it was meant to do:

CASE boolean_two
  WHEN TRUE AND field_two = 'b' THEN 'a'
  WHEN TRUE AND field_two = 'a' THEN 'b'
  ELSE field_two
END AS new_field_two

which in this case means that new_field_two = 'b' for the row with ID = 1, and all other remain equal to field_two.

So, this doesn't seem to be an issue of adding an extra condition to a shorthand CASE per se, I would guess it must have something to do specifically with the fact that the second condition is a NULL check. Am I on the right track?



Solution 1:[1]

Shawnt00 answer is good,

I like to think of the two forms as

chained If expression

CASE
   WHEN check1 THEN r1
   WHEN check2 THEN r2
   WHEN check3 THEN r3
END

if the same as

IF(check1) 
   r1
ELSE IF (check2)
   r2
...

where-as this "shortcut" version is the Switch statement form:

CASE expression
   WHEN val1 THEN r1
   WHEN val2 THEN r2
   WHEN val3 THEN r2
END

is the same as

SWITCH(expression){
    CASE val1: r1
    CASE val2: r2
    CASE val3: r3
}

which is to say the VAL things need to evaluate down, thus for you stumbled upon cases, you are writing extra boolean logic, which resolves down to a boolean answer. And as the doc's note, for a expression to match a value they need to be of the same type of can be auto converted.

thus this gives a SQL error:

select 
    case false
    when true then 1
    when 'bob' then 2
end;

Boolean value 'bob' is not recognized

because the second value cannot be auto converted to the same type as the case expression, which is a boolean value.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Simeon Pilgrim