2011-06-24 19 views
15

que quieren producir el siguiente código SQL mediante Active Records en CodeIgniter:Agrupación cláusulas WHERE en CodeIgniter

WHERE name != 'Joe' AND (age < 69 OR id > 50) 

haciendo lo siguiente parece ser la medida de lo que puedo conseguir, no puedo encontrar la manera de agruparlos

$this->db->select()->from('users')->where('name !=', 'Joe')->where('age <', 69)->or_where('id <', $id); 

¿Alguna idea? Mi consulta SQL es demasiado compleja, por lo que no quiero volver a escribir todo en SQL tradicional.

ACTUALIZACIÓN

Mi código SQL se genera dinámicamente en función de los valores de ciertos parámetros pasados ​​al método de modelo. El problema de no poder usar paréntesis causa un problema porque la precedencia del operador es tal que AND se evalúa primero antes de OR.

* Aquí está una parte de mi activa código de registros, donde hay algún otro código antes y después de que:

  ... some $this->db->where() ... 
      ... some $this->db->where() ... 

    if($price_range) { 
     $price_array = explode('.', $price_range); 
     for($i = 0; $i < count($price_array); $i++) { 
      if($i == 0) { 
       $this->db->where('places.price_range', $price_array[$i]); 
      } else { 
       $this->db->or_where('places.price_range', $price_array[$i]); 
      } 
     } 

    } 

      ... some $this->db->where() ... 
      ... some $this->db->where() ... 

El problema viene porque estoy utilizando $this->db->or_where() que introduce una cláusula OR que lanza el operador prioridad en el desorden sin poder usar () para cambiar el orden.

** ¿Hay alguna manera de solucionar esto? **

+0

Eso no' parece ser demasiado compleja como para no deje que su escritura en SQL llanura – dynamic

+0

@ yes123: el ejemplo anterior es sólo un ejemplo, mis registros activos solos generan hasta 60 + líneas de código SQL real generado dinámicamente de las cuales muchas son sentencias SQL condicionales. – Nyxynyx

+1

Esta es una limitación desafortunada de la clase Activerecord en Codeigniter. – timw4mail

Respuesta

-9

Resuelto. Genere dinámicamente la consulta SQL y conéctela al $this->db->where(). ¡Gracias chicos!

+0

baaad, pierdes validación de cadena –

14

Puede usar una cadena grande.

$this->db->select()->from('users')->where("name != 'Joe' AND (age < 69 OR id > 50) ");

+0

He actualizado la pregunta original con un código real de mi proyecto ... Como puede ver, no puedo usar paréntesis '()' como lo hace en su respuesta – Nyxynyx

+0

@Nyxynyx Así que al final su solución fue crear una cadena grande? – Jrod

+0

Sí, creé una cadena de consulta SQL parcial simple para la parte problemática que requiere paréntesis) y la inserté en '$ this-db-> donde()' – Nyxynyx

6

Lo que he hecho es duplicar la cláusula y después el dónde, que es efectivamente el mismo que el de selección de cadena larga.

$this->db->select() 
    ->from('users') 
    ->where('name !=', 'Joe') 
    ->where('age <', 69) 
    ->or_where('id <', $id) 
    ->where('name !=', 'Joe'); 

La única cadena larga es probablemente mejor.

+0

Después de intentar en vano obtener los paréntesis correctos como se describe en la solución de @Jrod , ¡Tomé este enfoque que funcionó para mí! Gracias. – user1072910

13

La agrupación de cláusulas where no está en CI por defecto. Tienes que extender el núcleo y agregar la habilidad. Lo he hecho por hacer algo de la siguiente manera:

class MY_DB_mysql_driver extends CI_DB_mysql_driver 
{  
    public function __construct($params) 
    { 
    parent::__construct($params); 
    } 
    /** 
    * This function will allow you to do complex group where clauses in to c and (a AND b) or (d and e) 
    * This function is needed as else the where clause will append an automatic AND in front of each where Thus if you wanted to do something 
    * like a AND ((b AND c) OR (d AND e)) you won't be able to as the where would insert it as a AND (AND (b...)) which is incorrect. 
    * Usage: start_group_where(key,value)->where(key,value)->close_group_where() or complex queries like 
    *  open_bracket()->start_group_where(key,value)->where(key,value)->close_group_where() 
    *  ->start_group_where(key,value,'','OR')->close_group_where()->close_bracket() would produce AND ((a AND b) OR (d)) 
    * @param $key mixed the table columns prefix.columnname 
    * @param $value mixed the value of the key 
    * @param $escape string any escape as per CI 
    * @param $type the TYPE of query. By default it is set to 'AND' 
    * @return db object. 
    */ 
    function start_group_where($key,$value=NULL,$escape,$type="AND") 
    { 
     $this->open_bracket($type); 
     return parent::_where($key, $value,'',$escape); 
    } 

    /** 
    * Strictly used to have a consistent close function as the start_group_where. This essentially callse the close_bracket() function. 
    */ 
    function close_group_where() 
    { 
     return $this->close_bracket(); 
    } 

    /** 
    * Allows to place a simple (in a query and prepend it with the $type if needed. 
    * @param $type string add a (to a query and prepend it with type. Default is $type. 
    * @param $return db object. 
    */ 
    function open_bracket($type="AND") 
    { 
     $this->ar_where[] = $type . " ("; 
     return $this; 
    } 

    /** 
    * Allows to place a simple) to a query. 
    */ 
    function close_bracket() 
    { 
     $this->ar_where[] = ")"; 
     return $this;  
    } 
} 

de uso:

group_where_start(key,value)->where(key,value)->group_where_close() 

o

consultas complejas como

open_bracket()->start_group_where(key,value)->where(key,value)->close_group_where()->start_group_where(key,value,'','OR')->close_group_where()->close_bracket() would produce AND ((a AND b) OR (d)) 
+0

¡¡¡Excelente !!! Personalizo mi controlador. ¿Lo sugirió a CI? ¿Puedo poner esto en activeRec? –

+0

¡Genial! ¡Realmente me ayudó! Quizás desee leer esto para que funcione: https://github.com/bcit-ci/CodeIgniter/wiki/Extending-Database-Drivers – f4der

+0

Hola a todos, lo siento, hace mucho tiempo. No, no lo he sugerido a CI. Acabo de salir de la necesidad de mí. Siéntase libre de ponerlo en activeRec @NicolasThery. Establezca esta como la respuesta correcta para que pueda comenzar a publicar más soluciones. Saludos :) –

16

en CodeIgniter 3.0.3 puede hacerlo simple como este:

$this->db->select() 
    ->from('users') 
    ->where('name !=', 'Joe') 
    ->group_start() // Open bracket 
    ->where('age <', 69) 
    ->or_where('id <', $id) 
    ->group_end(); // Close bracket 

Tal vez puede ayudar

+0

Esto funciona como un encanto – Gpak

Cuestiones relacionadas