2010-08-12 25 views
7

Tengo que crear una consulta basada en ciertas condiciones. ¿Hay una forma mejor de hacerlo que la que he hecho a continuación? Funciona bien, pero puedo ver que se va de las manos con bastante rapidez si hay más condiciones desde que compruebo si se han cumplido las condiciones previas cada vez que reviso una nueva.Creando una consulta larga y muchas declaraciones if: ¿hay una manera más elegante?

$sql = "SELECT DISTINCT fkRespondentID FROM tblRespondentDayTime"; 

    if (!empty($day) || !empty($time) || !empty($sportID)) { 

     $sql .= " WHERE"; 

     if (!empty($day)) { 
      $sql .= " fldDay='$day'"; 
     } 

     if (!empty($time)) { 
      if (!empty($day)) { 
       $sql .= " AND"; 
      } 
      $sql .= " fldTime='$time'"; 
     } 

     if (!empty($sportID)) { 
      if (!empty($day) || !empty($time)) { 
       $sql .= " AND"; 
      } 
      $sql .= " fkRespondentID IN (SELECT fkRespondentID FROM tblRespondentSport WHERE fkSportID='$sportID')"; 
     } 

    } 
+0

Es una buena pregunta :) – dmp

Respuesta

6

Usaría el viejo truco "WHERE 1=1"; agregue esto como la primera condición, y luego puede asumir la condición "Y" en cada declaración que sigue.

+0

@Palpie ha demostrado el uso práctico de este método en su respuesta. – DanP

0

puede intentar poner sus variables en una matriz y tener un booleano que indique si necesita agregar la "Y" antes de su siguiente frase. Esto acortaría sus instrucciones de control a un foreach y un if anidado.

0

Aquí está mi solución:

$sql = "SELECT * FROM table"; 
$conditions = array(
    'fldDay' => $day, 
    'fldTime' => $time, 
); 

if (count(array_filter($conditions))) { 
    $sql .= ' WHERE '; 
    $sql .= implode(' AND ', array_map(function($field, $value) { 
    return $field . '=\'' . pg_escape_string($value) . '\''; 
    }, array_keys($conditions), $conditions)); 
} 

Tenga en cuenta, que debido a los cierres, esto no va a trabajar por debajo de PHP 5.3. Si está utilizando un PHP anterior, realice el cierre como una función separada o sustitúyalo por un foreach.

+0

Este código es difícil de leer. –

1

Crea una lista/conjunto de condiciones, donde cada condicional es opcional (es decir, si la condición es válida, presiónala en la lista).

Si esta lista es> 0, agregue "donde" y luego agregue la lista unida por "y".

0

Desafortunadamente, crear SQL dinámico es una experiencia tediosa e incluso si puede cambiar algunas cosas en su lógica (que en realidad parece relativamente limpia), seguirá siendo fea.

Afortunadamente, existe Object-relational mapping. No estoy muy familiarizado con PHP, pero Perl tiene varios módulos de CPAN como SQL :: Abstract, que te permitirán crear sentencias SQL bastante complejas utilizando estructuras de datos básicas.

+0

No sabemos el tamaño del sistema que birderic está creando. Puede estar involucrando ORMs y constructores de SQL no es óptimo aquí. –

1

En lugar de hacer los cheques como if (!empty($day) || !empty($time)) puede crear una variable $whereClause y comprobar que funciona de esta manera:

$sql = "SELECT DISTINCT fkRespondentID 
     FROM tblRespondentDayTime"; 

$whereClause = ''; 

// fldDay 
if (!empty($day)) { 
    $whereClause .= " fldDay='$day'"; 
} 

// fldTime 
if (!empty($time)) { 
    if (!empty($whereClause)) { 
     $whereClause .= ' AND '; 
    } 
    $whereClause .= " fldTime='$time'"; 
} 

// fkRespondentID 
if (!empty($sportID)) { 
    if (!empty($whereClause)) { 
     $whereClause .= ' AND '; 
    } 
    $whereClause .= " fkRespondentID IN (SELECT fkRespondentID 
             FROM tblRespondentSport 
             WHERE fkSportID='$sportID')"; 
} 

if (!empty($whereClause)) { 
    $whereClause = ' WHERE '.$whereClause; 
} 

$sql .= $whereClause; 

Esto también funciona si es necesario, por ejemplo, cambiar un poco a un truco OR (1 = 1 no funcionará en ese caso e incluso podría ser bastante peligroso).

4
$sql = "SELECT DISTINCT fkRespondentID FROM tblRespondentDayTime WHERE 1=1"; 

if (!empty($day)) 
    $sql .= "AND fldDay='$day'"; 

if (!empty($time)) { 
    $sql .= "AND fldTime='$time'"; 

if (!empty($sportID)) 
    $sql .= "AND fkRespondentID IN (SELECT fkRespondentID FROM tblRespondentSport WHERE fkSportID='$sportID')"; 
+0

Gracias por la implementación de ejemplo + 1 – DanP

0

Si utiliza procedimientos almacenados, puede hacer algo como esto:

CREATE PROCEDURE `FindRespondents` (
    IN `_day` varchar(255), 
    ... 
) 
BEGIN 
    SELECT DISTINCT fkRespondentID 
    FROM tblRespondentDayTime 
    WHERE (_day Is Null OR fldDay = _day) 
     AND ... 
END; 
| 

Pasando en null para _day significa cualquier fldDay está bien. Cualquier otro valor para _day, y debe coincidir. Supuse fldDay es texto, pero por supuesto puede escribir todo correctamente aquí.

Sé que algunas personas no son entusiastas de los procedimientos almacenados, pero puede ser práctico encapsular la lógica de consulta de esta manera.

+0

Supongo que también funcionaría con sentencias preparadas, si escribe la cláusula where de esta manera, y enlaza cada uno de esos parámetros a '?' S. – grossvogel

Cuestiones relacionadas