2013-01-20 28 views
6

Der Versuch, eine verschachtelte Auswahl unter Verwendung von Zend\Db\Sql\Select zu erhalten und in der Dokumentation oder bei Google überhaupt nichts zu sehen.Verschachtelte Auswahl mit ZF2

Zu wollen, so etwas zu tun:

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

Ohne die Auswahl verschachtelt ist, würde es in etwa so aussehen:

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

ZF1 sah sich um einen subselect Artikel erstellen und sie dann als eine Zugabe Ausdruck in der Liste der Spalten, aber in ZF2 beschwert er sich über einen Ausdruck, der eine Zeichenkette sein muss.

Bearbeiten: Die geschachtelte Auswahl muss als eine Spalte sein, wie ich mit multipliziert Zeilen enden, wenn Sie GROUP BY für den gleichen Spaltennamen verwenden. Dies ist die richtige Abfrage Ich versuche, in Zend\Db\Sql\Select zu bekommen:

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 

Antwort

4

Ich würde vorschlagen, dass Sie Ihre SQL-Abfrage restrukturieren. Ich bin mir nicht sicher, welche Datenbank Sie verwenden, aber wenn Sie MySQL verwenden, kann die Funktion COUNT das Schlüsselwort DISTINCT verwenden. Auf diese Weise zählen Sie die doppelten IDs nicht. Ich habe Ihre SQL-Abfrage an das angepasst, was ich verwenden würde. Auf diese Weise beseitigen Sie die Notwendigkeit einer inneren Auswahl.

Ich habe diese Abfrage nicht ausgeführt, aber ich bin sicher, es sollte funktionieren und Ihnen das gewünschte Ergebnis geben. Hoffentlich verstehe ich deine Situation nicht falsch. Unten ist das äquivalente 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

Ich hoffe, ich bin immer Ihr Problem richtig ...

mich noch nicht zu ZF2 aktualisiert, aber das ist eine der Art und Weisen Sie kann eine verschachtelte SELECT-Anweisung in ZF1 erstellen, wenn Sie MVC-Architektur verwenden (versuchen Sie es auch in ZF2).

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

Update:

dazu nach Ihrem Kommentar Got zurück und erkannte, dass der Code, den ich geschrieben habe, würde nicht funktionieren, da Sie nicht in der Lage sein werden, mehrere Spalten von einem anderen wählen Tabelle in eine einzelne Spalte (dh x, y, z in b).

Aber ja, es würde funktionieren, wenn Sie einige Agg durchführen müssen. Funktion auf der anderen Tabelle, die eine einzelne Spalte ausgibt. z.B.

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

Das würde also funktionieren. Auf diese Weise können Sie einige Spalten mit einer bestimmten Funktion aufrufen. Und den Rest der Spalten aus der anderen Tabelle (Tabelle2) können Sie mit einem Join erhalten.

+0

Dies ist derzeit, worauf ich zurück fiel, da ich es nicht tun konnte. Ich habe das SQL einfach roh geschrieben, wie du schon sagtest, aber die Hälfte ist abstrahiert und die andere Hälfte roh: D dachte, ZF2 würde es nur innerhalb des Spaltenbereichs erlauben. –

0

Was Sie beschreiben, ist als JOIN definiert. Es gibt einige verschiedene Join-Szenarien und ich werde nicht die Unterschiede von ihnen abdecken, aber die meisten Commons wären INNER JOIN oder LINKER JOIN.

Und das ist in der Tat in den ZF2-Documentation of Zend\Db\Sql#Join

Die Abfrage würde wie folgt aussehen gefunden werden:

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

an der Dokumentation von ZF2-Documentation of Zend\Db\Sql#Join Sehen, i denkt, die Select würde wie folgt aussehen:

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

Andere ich denke: Wenn Sie nicht die columns() verwenden, würden Sie SELECT * aber um Ihrer selbst willen beginnen, gute Abfragen zu schreiben;) Haben Sie mehr Kontrolle über Ihren Code!

Ich kann nicht versprechen, dass dieser Code funktioniert, da ich Zend \ Db nicht alleine benutze, aber die Dokumentation an der richtigen Stelle zu verwenden, sollte trotzdem funktionieren.

+0

Mmm, ich benutze auch andere Joins und kann da auch keinen anderen machen multipliziert die Zeilen, wenn ich multiple count() und sum() verwende. Ich gruppiere nach einem bestimmten Feld, aber das wird auch in der Joined-Tabelle verwendet, daher glaube ich nicht, dass es anders geht, als eine geschachtelte Auswahl zu haben. –

6

Ralph Schindler hat ein Repository von verschiedenen DB-Mustern, die er speziell in Zend \ Db implementiert hat. Ist hier ein für Subselects: https://github.com/ralphschindler/Zend_Db-Examples/blob/master/example-20.php

Der Inhalt ist dies:

<?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' 
); 

Grundsätzlich Sie eine auswählen, wenn der Wert des Prädikats eines anderen wählen können.

+0

Ist es möglich, eine SubSelect als zusätzliche Spalte auszuführen, ohne einen weiteren DB-Aufruf auszuführen? Ich bekomme multiplizierte Reihen, wenn ich mehr als 1 Zählung habe, also habe eine Unterauswahl, um das zu umgehen. Ich habe ein Beispiel SQL in meine ursprüngliche Frage geschrieben, um zu zeigen, was ich meine :) –