2010-08-21 25 views
9

¿Alguien sabe una buena manera de hacer una consulta de UNIÓN en CakePHP? Me gustaría evitar el uso de $this->query();.Sintaxis de UNION en Cakephp

Con dos tablas t1, t2:

SELECT * FROM t1 
LEFT JOIN t2 ON t1.id = t2.id 
UNION 
SELECT * FROM t1 
RIGHT JOIN t2 ON t1.id = t2.id 

Con tres tablas t1, t2, t3:

SELECT * FROM t1 
LEFT JOIN t2 ON t1.id = t2.id 
LEFT JOIN t3 ON t2.id = t3.id 
UNION 
SELECT * FROM t1 
RIGHT JOIN t2 ON t1.id = t2.id 
LEFT JOIN t3 ON t2.id = t3.id 
UNION 
SELECT * FROM t1 
RIGHT JOIN t2 ON t1.id = t2.id 
RIGHT JOIN t3 ON t2.id = t3.id 
+0

¿Hay alguna razón por la que desea evitar $ this-> consulta? – Stoosh

+3

Bueno, por un lado, se frustra el propósito de usar un marco si no vas a tratar de escribir una aplicación en el estilo nativo del marco. Y la mayoría de las consultas 'SELECT' se pueden llevar a cabo utilizando' find() 'en 1.3.Además, 'find()' se beneficia de la protección incorporada de los controladores de fuente de datos contra las inyecciones de SQL, mientras que 'query()' es una consulta directa de la que tendría que escapar usted mismo. Dicho esto, 'UNION' es probablemente una de las pocas clases de consultas que no puedes ejecutar usando' find() '. –

+0

¿Tiene un ejemplo válido de unión MySQL que está ejecutando? El que está en la lista no funciona. –

Respuesta

12

Demasiados codificadores intentan limitarse a la funcionalidad de un marco. NO. Use lo que proporciona el marco. Si no tiene la funcionalidad que buscar, entonces:

  • Código la funcionalidad que necesita en una extensión de clase

o

  • personalizada girar el código en el marco para adaptarse tus necesidades.

A menudo, los desarrolladores intentan clavar una clavija cuadrada en un agujero redondo y terminan haciendo demasiado trabajo extra que realmente solo complica el código. Da un paso atrás y pregunta por qué estás usando el marco para empezar. Trae la estructura a un lenguaje no estructurado. Proporciona una base reutilizable sólida para construir su aplicación. No pretende ser una caja para ponerse y ser limitado.

ACTUALIZACIÓN: Me tomó un minuto para leer Complex Find Conditions y encontró su respuesta:

$joins = array(
    array(
     'table' => 'test_twos', 
     'alias' => 'TestTwo', 
     'type' => 'LEFT', 
     'conditions' => array(
      'TestTwo.id = TestOne.id', 
     ) 
    ), 
    array(
     'table' => 'test_threes', 
     'alias' => 'TestThree', 
     'type' => 'LEFT', 
     'conditions' => array(
     'TestThree.id = TestOne.id', 
    ) 
    ) 
); 

$dbo = $this->getDataSource(); 
$subQuery = $dbo->buildStatement(
    array(
     'fields' => array('*'), 
     'table' => $dbo->fullTableName($this), 
     'alias' => 'TestOne', 
     'limit' => null, 
     'offset' => null, 
     'joins' => $joins, 
     'conditions' => null, 
     'order' => null, 
     'group' => null 
    ), 
    $this->TestOne 
); 
$query = $subQuery; 

$query .= ' UNION '; 
$joins = array(
    array(
     'table' => 'test_twos', 
     'alias' => 'TestTwo', 
     'type' => 'LEFT', 
     'conditions' => array(
      'TestTwo.id = TestOne.id', 
     ) 
    ), 
    array(
     'table' => 'test_threes', 
     'alias' => 'TestThree', 
     'type' => 'RIGHT', 
     'conditions' => array(
     'TestThree.id = TestOne.id', 
     ) 
    ) 
); 

$dbo = $this->getDataSource(); 
$subQuery = $dbo->buildStatement(
    array(
    'fields' => array('*'), 
    'table' => $dbo->fullTableName($this), 
    'alias' => 'TestOne', 
    'limit' => null, 
    'offset' => null, 
    'joins' => $joins, 
    'conditions' => null, 
    'order' => null, 
    'group' => null 
    ), 
    $this->TestOne 
); 

$query .= $subQuery; 

pr($query); 
+3

Lo primero que debe hacer es verificar si es posible resolver un problema con la funcionalidad del marco. Por supuesto, el marco no debe limitar a un programador. – bancer

+0

+1 para la actualización. Esa es la dirección correcta. Voy a echar un vistazo más de cerca al código más adelante. – bancer

+1

Thumbs up para recomendar que los desarrolladores no se limiten a la funcionalidad proporcionada por el marco. Veo demasiadas veces en que las personas descartan una solución perfectamente válida porque "No es la forma de pastel". – UncaAlby

3

Utilizar una vista, a continuación, seleccionar de que:

create view my_union as 
SELECT * FROM t1 
LEFT JOIN t2 ON t1.id = t2.id 
LEFT JOIN t3 ON t2.id = t3.id 
UNION 
SELECT * FROM t1 
RIGHT JOIN t2 ON t1.id = t2.id 
LEFT JOIN t3 ON t2.id = t3.id 
UNION 
SELECT * FROM t1 
RIGHT JOIN t2 ON t1.id = t2.id 
RIGHT JOIN t3 ON t2.id = t3.id 

En su código:

select * from my_union 
+1

Esta es una buena solución posible, pero vea este descargo de responsabilidad sobre el uso de vistas en Cake: http://www.mail-archive.com/[email protected]/msg43116.html –

+0

Me temo que no funcionaría en otras bases de datos como SQLlite. – bancer

+0

@bancer: ¿estás seguro de eso? La documentación de SQLite indica que admite vistas y usa la misma sintaxis 'create view'. –

3

Una forma sencilla de hacer esto, que utilizamos en la actualidad, es la creación de una vista en MySQL o cualquier base de datos que utiliza. Luego, en lugar de usar una tabla en su modelo, usa su vista. Puede leer sobre la sintaxis de creación de vista aquí: http://dev.mysql.com/doc/refman/5.6/en/create-view.html. También puede usar software como HeidiSQL para ayudarlo con la creación de vistas.

A continuación, tendría algo como esto en su modelo:

class Contenu extends AppModel { 
    public $useTable = 'v_contenu'; 

Esto le permite seguir utilizando el método find() en CakePHP, que es muy bueno tener.

Para obtener el mejor rendimiento con vistas, debe actualizar MySQL al menos a la versión 5.6.

+0

Esta es una solución realmente agradable – Will

0

usar un código como este:

$friendsPosts= $this->Posts->find('all') 
       ->contain(['Users', 'Languages', 'PostStates']) 
       ->innerJoinWith('Users.Dusers', function ($q) { 
        return $q->where(['Dusers.id' => $this->Auth->user('id')]); 
       }); 

     $posts= $this->Posts->find('all') 
       ->where(['Posts.post_state_id' => 3]) 
       ->contain(['Users', 'Languages', 'PostStates']); 

    $posts->union($friendsPosts);