I have a Postgres SELECT statement with these expressions:
,CASE WHEN (rtp.team_id = rtp.sub_team_id)
THEN 'testing'
ELSE TRIM(rtd2.team_name)
END AS testing_testing
,CASE WHEN (rtp.team_id = rtp.sub_team_id)
THEN 'test example'
ELSE TRIM(rtd2.normal_data)
END AS test_response
,CASE WHEN (rtp.team_id = rtp.sub_team_id)
THEN 'test example #2'
ELSE TRIM(rtd2.normal_data_2)
END AS another_example
In my particular query there are 5 fields whose output depends on whether rtp.team_id = rtp.sub_team_id evaluates true. I’m repeating CASE statements with the same condition over and over.
Is there any way I can combine these CASE expressions to toggle the output of multiple columns in one shot?
1. Standard-SQL:
LEFT JOINa single row of valuesYou could
LEFT JOINa row of values using the condition (thereby evaluating it once). Then you can add fallback values per column withCOALESCE().This syntax variant is shorter and slightly faster with multiple values – especially interesting for an expensive / lengthy condition:
Since the derived table
xconsists of a single row, joining without further conditions is fine.Explicit type casts are necessary in the subquery. I use
textin the example (which is the default for string literals anyway). Use your actual data types. The syntax shortcutvalue::typeis Postgres-specific, usecast(value AS type)for standard SQL.If the condition is not
TRUE, all values inxare NULL, andCOALESCEkicks in.Or, since all candidate values come from table
rtd2in your particular case,LEFT JOINtortd2using the originalCASEcondition andCROSS JOINto a row with default values:It depends on the join conditions and the rest of the query.
2. PostgreSQL-specific
2a. Expand an array
If your various columns share the same data type, you can use an array in a subquery and expand it in the outer
SELECT:It gets more complicated if the columns don’t share the same data type. You can either cast them all to
text(and optionally convert back in the outerSELECT), or you can …2b. Decompose a row type
You can use a custom composite type (row type) to hold values of various types and simply *-expand it in the outer
SELECT. Say we have three columns:text,integeranddate. For repeated use, create a custom composite type:Or if the type of an existing table matches, you can just use the table name as composite type.
Or if you only need the type temporarily, you can create a
TEMPORARY TABLE, which registers a temporary type for the duration of your session:You could even do this for a single transaction:
Then you can use this query:
Or even just (same as above, simpler, shorter, maybe less easy to understand):
The
CASEexpression is evaluated once for every column this way. If the evaluation is not trivial, the other variant with a subquery will be faster.