2010-08-21 10 views
9

Qualcuno conosce un buon modo per eseguire query UNION in CakePHP? Vorrei evitare di usare $this->query();.Sintassi UNION in Cakephp

con due tavoli 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 tre tabelle 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

C'è qualche motivo per cui si desidera evitare $ this-> ricerca? – Stoosh

+3

Beh, per uno, sconfigge lo scopo di usare un framework se non hai intenzione di provare a scrivere un'applicazione nello stile nativo del framework. E la maggior parte delle query 'SELECT' possono infatti essere eseguite usando' find() 'in 1.3.Inoltre, 'find()' trae vantaggio dalla protezione integrata dei driver dei sorgenti di dati contro le iniezioni SQL, mentre 'query()' è una query diretta che dovrete sfuggire a voi stessi. Detto questo, 'UNION' è probabilmente una delle poche classi di query che non è possibile eseguire usando' find() '. –

+0

Hai un esempio di unione MySQL valida in esecuzione? Quello elencato non funziona. –

risposta

12

Troppi codificatori cercano di limitarsi alla funzionalità di un framework. NON FARE. Usa ciò che offre il framework. Se non ha la funzionalità che cercate, allora:

  • codice le funzionalità necessarie in un'estensione di classe

o

  • personalizzato girare il codice nel quadro per soddisfare I tuoi bisogni.

Spesso gli sviluppatori cercano di battere un piolo quadrato in un buco rotondo e finiscono per fare troppo lavoro extra che rende davvero complicato il codice. Fai un passo indietro e chiedi perché stai usando la struttura per cominciare. Porta la struttura a un linguaggio non strutturato. Fornisce solide fondamenta riutilizzabili su cui costruire la tua applicazione. Non è destinato a essere una scatola per mettersi ed essere limitato.

UPDATE: ho preso un minuto per leggere Complex Find Conditions e ha trovato la risposta:

$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

La prima cosa da fare è verificare se è possibile risolvere un problema con le funzionalità del framework. Ovviamente, il framework non deve limitare un programmatore. – bancer

+0

+1 per l'aggiornamento. Questa è la giusta direzione. Vedrò più da vicino il codice. – bancer

+1

Pollice in alto per raccomandare che gli sviluppatori non si limitino alla funzionalità fornita dal framework. Vedo troppe volte in cui le persone respingono una soluzione perfettamente valida perché "Non è la via della torta". – UncaAlby

3

Utilizzare una vista, quindi selezionare da questo:

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 

Nel tuo codice:

select * from my_union 
+1

Questa è una buona soluzione possibile, ma vedi questo disclaimer sull'uso delle viste in Cake: http://www.mail-archive.com/[email protected]/msg43116.html –

+0

Ho paura che non funzionerebbe altri database come SQLlite. – bancer

+0

@bancer: ne sei sicuro? La documentazione di SQLite indica che supporta le viste e utilizza la stessa sintassi 'create view'. –

3

Un modo semplice per fare questo, che attualmente usiamo, è quello di creare una vista in MySQL o qualsiasi database utilizzato. Quindi, invece di usare una tabella nel tuo modello, usi la tua vista. Puoi leggere la sintassi sulla creazione di viste qui: http://dev.mysql.com/doc/refman/5.6/en/create-view.html. Puoi anche utilizzare software come HeidiSQL per aiutarti nella creazione di viste.

si dovrebbe quindi avere qualcosa di simile nel modello:

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

Questo consente di utilizzare ancora il metodo find() in CakePHP, che è davvero bello avere.

Per ottenere le prestazioni migliori con le visualizzazioni, è necessario aggiornare MySQL almeno alla versione 5.6.

+0

Questa è davvero una bella soluzione – Will

0

utilizzare un codice come questo:

$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);