2013-01-20 12 views
6

Cercando di ottenere una selezione nidificata utilizzando Zend\Db\Sql\Select e non riesci a vedere nulla nella documentazione o su Google.Nidificato Seleziona con ZF2

Volendo fare qualcosa di simile:

SELECT 
    table1.*, 
    (SELECT x,y,z FROM table2 WHERE table2.a = table1.a) as b 
FROM table1 

Senza la qualcosa SELECT nidificato, sarebbe simile a questa:

$select = new Zend\Db\Sql\Select; 
$select 
->columns(array(
    '*' 
)) 
->from('table1') 

ZF1 guardato sulla creazione di una voce di selezione secondaria e poi aggiungerlo come Espressione all'interno dell'elenco di colonne ma in ZF2 si lamenta di un'espressione che deve essere una stringa.

Modifica: la selezione nidificata deve essere come una colonna mentre si finisce con le righe moltiplicate quando si utilizza GROUP BY sullo stesso nome di colonna. Questa è la domanda corretta che sto cercando di entrare in Zend\Db\Sql\Select:

SELECT 
    users.id, 
    (SELECT count(explorations.id) FROM explorations WHERE user_id = users.id) as total_explorations, 
    count(villages.id) 
FROM 
    users 
INNER JOIN 
    villages 
     on (villages.user_id = users.id) 
GROUP BY 
    users.id 

risposta

4

Suggerirei di ristrutturare la query SQL. Non sono sicuro di quale database si sta utilizzando, ma se si utilizza MySQL, la funzione COUNT può utilizzare la parola chiave DISTINCT. In questo modo non conti gli id ​​duplicati. Ho adattato la tua query SQL a ciò che userei, in questo modo elimini la necessità di una selezione interiore.

SELECT 
    users.id, 
    COUNT(DISTINCT explorations.id) AS total_explorations, 
    COUNT(DISTINCT villages.id) AS total_villages 
FROM users 
    INNER JOIN villages ON villages.user_id = users.id 
    INNER JOIN explorations ON explorations.user_id = users.id 
GROUP BY users.id 

Non ho eseguito questa query, ma sono sicuro che dovrebbe funzionare e fornire il risultato desiderato. Spero di non fraintendere la tua situazione. Di seguito è riportato l'equivalente Zend Framework 2 select.

$select = $sql->select('users'); 
$select->columns(array('id')); 
$select->join('villages', 
       'villages.user_id = users.id', 
       array(
        'total_villages' => new Expression("COUNT(DISTINCT villages.id)") 
       ) 
); 
$select->join('explorations', 
       'explorations.user_id = users.id', 
       array(
        'total_explorations' => new Expression("COUNT(DISTINCT explorations.id)") 
       ) 
); 
0

Spero di ottenere il vostro problema in modo corretto ...

non mi ancora aggiornato a ZF2 ma questo è uno dei modi che si puoi creare un'istruzione Select nidificata in ZF1 se stai usando l'architettura MVC (provalo anche in ZF2).

$table1 = new table1(); 
    $table1->select()->from('table1',array('*', 
     'b' => '(SELECT x,y,z FROM table2 WHERE table2.a = table1.a)', 
    )); 

Aggiornamento:

tornati a questo dopo il tuo commento e si rese conto che il codice che ho scritto non funziona come non sarà in grado selezionare più colonne di un altro tabella in una singola colonna (cioè x, y, z in b).

Ma sì, avrebbe funzionato nel caso in cui devi eseguire alcuni agg. funzione sull'altra tabella che fornisce una singola colonna. per esempio.

$table1 = new table1(); 
    $table1->select()->from('table1',array('*', 
     'b' => '(count (*) FROM table2 WHERE table2.a = table1.a)', 
    )); 

Quindi questo funzionerebbe. In questo modo è possibile ottenere alcune delle colonne con alcune funzioni eseguite su di esse. E il resto delle colonne dall'altra tabella (tabella2) è possibile ottenere utilizzando un join.

+0

Questo è attualmente ciò a cui sono tornato da quando non ero in grado di farlo. Ho appena scritto l'SQL raw come hai detto, ma poi la metà è astratta e l'altra metà grezza: D Pensavo che ZF2 lo avrebbe semplicemente permesso all'interno della sezione colonne –

0

Quello che stai descrivendo è definito come JOIN. Ci sono alcuni diversi scenari di join e non ne coprirò le differenze, ma la maggior parte dei comuni sarà INNER JOIN o LEFT JOIN.

E questo è infatti quello di essere trovati all'interno del ZF2-Documentation of Zend\Db\Sql#Join

La query sarebbe simile a questa:

Select 
    t1.*, 
    t2.field1, 
    t2.field2, 
    t2.field3 
FROM 
    tablename1 t1, 
    tablename2 t2 
WHERE 
    t1.field = t2.field 

Guardando la documentazione di ZF2-Documentation of Zend\Db\Sql#Join, i che Select sarebbe simile a questa:

$select = new \Zend\Db\Sql\Select(); 

$select->columns(array(
    'id', 
    'title', 
    // List ALL Columns from TABLE 1 - * is bad/slow! 
), true)->from(array(
    't1' => 'tablename1' 
))->join(
    'tablename2', 
    'id = t1.id', 
    array(
     'username', 
     'email', 
     // List ALL Columns from TABLE 2 u want to select 
    ), 
    $select::JOIN_INNER 
) 

Altro penso: Se non si utilizza lo columns() si dovrebbe SELECT * ma per il proprio bene, iniziare a scrivere buone query;) Avere più controllo sul tuo codice!

Non posso promettere che questo codice funzioni, dal momento che non uso Zend \ Db da solo, ma usare la Documentazione al punto giusto dovrebbe farti comunque funzionare.

+0

Mmm, sto usando anche altri join e non posso fare altro perché moltiplica le file perché sto usando multiplo count() e sum(). Sto raggruppando per un campo particolare, ma è usato anche nella tabella unita, quindi non penso che ci sia un altro modo per aggirarlo, se non avere una selezione nidificata. –

6

Ralph Schindler ha un repository di diversi modelli di DB che ha specificamente implementato in Zend \ Db. Ecco uno per subselect: https://github.com/ralphschindler/Zend_Db-Examples/blob/master/example-20.php

Il contenuto è questo:

<?php 

/** @var $adapter Zend\Db\Adapter\Adapter */ 
$adapter = include ((file_exists('bootstrap.php')) ? 'bootstrap.php' : 'bootstrap.dist.php'); 
refresh_data($adapter); 

use Zend\Db\Sql; 
use Zend\Db\ResultSet\ResultSet; 

$sql = new Sql\Sql($adapter); 

$subselect = $sql->select(); 
$subselect->from('artist') 
    ->columns(array('name')) 
    ->join('album', 'artist.id = album.artist_id', array()) 
    ->where->greaterThan('release_date', '2005-01-01'); 


$select = $sql->select(); 
$select->from('artist') 
    ->order(array('name' => Sql\Select::ORDER_ASCENDING)) 
    ->where 
     ->like('name', 'L%') 
     ->AND->in('name', $subselect); 

$statement = $sql->prepareStatementForSqlObject($select); 

$result = $statement->execute(); 

$rows = array_values(iterator_to_array($result)); 

assert_example_works(
    count($rows) == 2 
    && $rows[0]['name'] == 'Lady Gaga' 
    && $rows[1]['name'] == 'Linkin Park' 
); 

In sostanza, è possibile utilizzare uno di selezione come il valore del predicato di un altro select.

+0

È possibile eseguire un SubSelect come una colonna aggiuntiva senza effettuare un'altra chiamata DB? Ho moltiplicato le righe se ho più di 1 conteggio, quindi ho una sotto-selezione per aggirare questo. Ho pubblicato un esempio SQL nella mia domanda originale per mostrare cosa intendo :) –