Postgresql – A flag (indicator) that shows for each row which conditions was used to select it

conditionpostgresql

Suppose I have the table foo. I want to filter the rows of this table using different conditions (cond_1, cond_2, …, cond_nthe order is important) combined in a disjunction, i.e.:

SELECT * FROM foo WHERE cond_1 OR cond_2 OR ... OR cond_n;
  1. Is it possible (in PostgreSQL 13) to distinguish for each row which condition cond_i was used to select it? Since I stated that the order is important the question may be reformulated as – I want to know the first cond_i that selected the row, for each row.

Now consider that I have in foo a column for this purpose, e.g. selected_by.

  1. Is it possible to distinguish for each row which condition cond_i was used to select it and store it in selected_by? (the same as 1st question but for an UPDATE statement)

Two things are important: the order of conditions (as it was highlighted earlier); performance (i.e. table foo may have many rows, the number of conditions is small, up to 5-10).

Best Answer

If your conditions are mutually exclusive (you you only care about matching the first of an order you control) then you could get away with a single column:

SELECT *,
  CASE 
    WHEN name = 'meatfeast' THEN 'name' 
    WHEN diet = 'vegan' THEN 'diet' 
  END as reason_for_appearing
FROM
  pizza
WHERE
  name = 'meatfeast' OR diet = 'vegan'

You repeat your where conditions as individual clauses of a case when, (in the order you care about them)


If they aren't mutually exclusive and you want to know all the reasons why it might have matched you'll either need multiple columns ..

SELECT *,
  CASE WHEN name = 'john' THEN 'yes' END as because_of_name,
  CASE WHEN city = 'Chicago' THEN 'yes' END as because_of_city
FROM
  person
WHERE 
  name = 'john' OR city = 'chicago'

.. unless you want to get really involved with a huge case when of all the conditions combinations (which is 2^N, as I'm sure you can imagine)

Or you might alternatively do some kind of concat you can pick apart programmatically or the user can read

SELECT *,
  CONCAT(
    CASE WHEN name = 'john' THEN 'name' END,
    CASE WHEN city = 'Chicago' THEN ' city' END 
  ) as because_of
FROM
  person
WHERE 
  name = 'john' OR city = 'chicago'

I suppose it rather depends on what you want to do with it after