mardi 7 juillet 2015

MySql multiple where conditions - only match first correct condition

With data similar to the table below:

|  id  |    e_date    |  e_time |  place | person| ref  |ref_type| 
|  10  |  2015-08-03  |  10:30  |  work  |  tony | 1234 |   A    |
|  25  |  2015-08-03  |  10:30  |  work  |  NULL | NULL |   A    |
|  37  |  2015-08-03  |  NULL   |  work  |  tony | NULL |   A    |
|  99  |  2015-08-03  |  10:30  |  work  |  fred | 1234 |   B    |

What's the best method to get only the 1st match of a series of conditions (of desc importance) in a MySQL WHERE clause ?

  • match the ref field
  • if no matches in ref field, then match on e_date+e_time+place fields
  • if no matches on ref or e_date+e_time+place then match on e_date+place+person

The aim here is to get the best single row match - based on a descending series of criteria - and only use the criteria if the preceding criteria isn't fulfilled.

My first attempt at query looked like:

SELECT id FROM my_table 
WHERE ref_type = 'A' AND (
  ref = '1234'
  OR
  (e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work')
  OR
  (e_date = '2015-08-03' AND place = 'work' AND person = 'tony')
)

but since OR is inclusive (not sequential), this returns rows 10, 25 and 37 - see this sqlfiddle

I could ORDER BY ref DESC and LIMIT 1 but that doesn't help me if I have no ref value and have to use either of the 2nd or 3rd conditions

My next attempt uses nested IF conditions in the WHERE clause like :

SELECT id FROM my_table 
WHERE ref_type = 'A' AND (
  IF(ref = 1234, 
    ref = 1234,
    IF(e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work', 
       e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work',
       e_date = '2015-08-03' AND place = 'work' AND person = 'tony'
    )
  )
)

However, this returns also rows 10, 25 and 37 - see this sqlfiddle

Also tried using IFNULL :

SELECT id FROM my_table 
WHERE ref_type = 'A' AND 
  IFNULL(ref = '1234', 
    IFNULL(e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work',
      e_date = '2015-08-03' AND place = 'work' AND person = 'tony')
  )

Which returns rows 10 and 25 - see this sqlfiddle

What's the best way to write this query ?

I'm using php - and I could run 3 separate sequential queries and use php conditionals on each result - but I'd like to use a single db query given the millions of times this code will be run per hour.

Aucun commentaire:

Enregistrer un commentaire