Question

This query has been a lot of trouble for me:

/* Looking for a machine already attributed to a site:
       *      - Date_started is in the given period
       *  OR  - Date_ended is in the giver period
       *  OR  - Date_started is before the period's end AND date_ended is null
       *  AND - Que l'on parle de la même machine
       */                     
$dsql = $tmp->_dsql();
$machine = $tmp->selectQuery(array('site'))
           ->where($dsql->andExpr()
             ->where($dsql->orExpr()
               ->where('date_started BETWEEN "'
                         .$dsql->escape($this['date_started']).
                       '" AND "'
                         .$dsql->escape($this['date_ended']).
                       '"') 
               ->where('date_ended BETWEEN "'
                         .$dsql->escape($this['date_started']).
                       '" AND "'
                         .$dsql->escape($this['date_ended']).
                       '"')
               ->where($tmp->_dsql()->andExpr()
                 ->where('date_started < "'.$dsql->escape($this['date_ended']).'"')
                 ->where('date_ended IS null')
               )
             )
             ->where('machine_id = '.$dsql->escape($this['machine_id']))
             ->where('id != '.$dsql->escape($this['id']))
           )
           ->getOne();

Lot of problems first due to parentheses that's why there is so much orExpr and andExpr. Then because of the BETWEEN which prevents to use where($field, $cond, $value) which escape the values.

If I do not escape values, it works but as usual I should not trust data. I know I could wrote down the full query in $dsql->expr() and then setCustom but it is not the point of using such a great framework.

EDIT:

Additional information:

pdo_error: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound
mode: select
params:
query: select (select concat(`site`.`emplacement`, " (", (select `nom` from `region` where `site`.`region_id` = `region`.`id` ), ")") `designation` from `site` where `site_machine`.`site_id` = `site`.`id` ) `site`,`id`,`machine_id`,`site_id` from `site_machine` where ((date_started BETWEEN ":a" AND ":a_2" or date_ended BETWEEN ":a_3" AND ":a_4" or (date_started < ":a_5" and date_ended IS null)) and machine_id = :a_6 and id != :a_7)
Was it helpful?

Solution

You can slightly simplify conditions. This should be the same as you wrote in your question:

date_started < period_end
AND (date_ended is null OR date_ended >= period_start)

and yes, no more BETWEEN issue too :)

If you don't have a lot of data, then you can even do like this and get rid of OR completely. But keep in mind, that ifnull(date_ended) will not use indexes and probably will work slower (check execution plan of SELECT):

date_started < period_end
AND IFNULL(date_ended, period_start) >= period_start
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top