I want to query something from my database and DB has multiple answers for various scenarios.
Question: find the type of triangle based on the length of sides. DB has these columns with Numeric datatype:
Side A | Side B | Side C |
---|---|---|
20 | 20 | 23 |
20 | 20 | 20 |
My dummy MySQL code:
SELECT IF( A = B = C, 'Equilateral', NULL) OR IF( A = B != C OR B = C != A OR A = C != B, 'Isosceles', NULL) OR IF( A != B AND B != C AND A != C , 'Scalene', NULL) OR IF( A + B < C OR A + C < B OR C + B < A , 'Not A Triangle', NULL) FROM TRIANGLES;
I get this unexpected output:
NULL
NULL
NULL
I expect the query code to give me only one correct response for each row. I don't know how to do this without using other programming languages.
You won't get an if
in pure SQL (which is not a procedural language), unless with RDBMS-specific extensions (SQL extensions, like MySQL's IF
, or procedural extensions, like in PL/pgSQL),
but you will get a CASE WHEN … THEN … ELSE … END
(equivalent of a switch(…) { case …: …; break; }
in C-like languages),
which more nicely fits your need, and improves readability of your expression (… and thus debugging, as you will see in the example).
It works by returning the expression that follows the first matching WHEN
(see Optimization below for the implications).
So your example could be written:
SELECT
CASE
WHEN A = B AND B = C THEN 'Equilateral'
WHEN A = B OR B = C OR A = C THEN, 'Isosceles' -- Note that no need to write != C (after A = B), as the Equilateral case ate the A = B = C case, we are guaranteed to only have the != C case left in this WHEN.
ELSE 'Scalene' -- Same here: the two preceding cases ate all cases having an equality.
-- And so here, wanting to add another ELSE makes us understand the logic error, as the test for 'Not a Triangle' should have been place before all other ones or at least the Isosceles.
END
FROM TRIANGLES;
Similarly to the switch
and the if
too in other languages,
CASE WHEN
allows the RDBMS to optimize the execution by short-circuiting the later WHEN
s as soon as a former WHEN
succeeds.
This is not guaranteed,\but you won't loose anything by always starting with the simplest tests or more common cases, for example in a post office:
CASE
WHEN dest_zipcode = here_zipcode THEN 'local' -- This one is more common than the next one
WHEN dest_country <> 'USA' THEN 'foreign' -- … but this one is easier to compute than the next one.
WHEN EXISTS (SELECT 1 FROM us_cities WHERE ZIPCODE = dest_zipcode) THEN 'usa'
ELSE 'unknown'
END AS distribution