2009-08-03 14 views
1

Ich möchte die Anzahl der Kommentare für jeden Blog-Post (zusammen mit Kategorie, Datum, Autor usw.) auf einer Seite, die eine Liste von Blog-Posts hat. Wie schreibe ich die folgende mysql Abfrage in Antrieb?Sql-Abfrage (innerer Join + Anzahl + Gruppe von) mit Propel

SELECT post.id, post.title, post.more_columns , COUNT(comments.post_id) AS numofcomments FROM post INNER JOIN comments ON post.id = comments.post_id GROUP BY post.id, post.title, post.more_columns 

wo Post eine Blog-Tabelle und Kommentare, eine Tabelle von Kommentaren mit post_id als Fremdschlüssel post.id. Ich kann nicht scheinen, numofcomments als eine Spalte in der Ergebnismenge. Derzeit bin ich ein nicht-ORM-Ansatz (die mein letztes Mittel sein wird):

$con = Propel::getConnection(PostPeer::DATABASE_NAME); 

    $sql = "SELECT post.* , COUNT(comments.post_id) AS numcomments FROM post INNER JOIN comments ON post.id = comments.post_id GROUP BY post.id"; 
    $stmt = $con->prepare($sql); 
    $stmt->execute(); 

    $result = PostPeer::populateObjects($stmt); 
    return $result; 

Wie kann ich ‚numofcomments‘ Zugriff in der resultierenden Propel resultset?

EDIT: Was ich wissen wollte ist, wie ich die obige Abfrage in Propel schreiben kann? Was ich jetzt tun kann, ist, die Post-Tabelle mit innerem Join in der Kommentartabelle zu erhalten und dann doCount in der Kommentartabelle für jede Post-ID auszuführen. Dies führt zu 1 Abfrage für die Post-Tabelle und viele Abfragen für die Kommentartabelle. Ich möchte die SQL-Abfragen auf ein Minimum reduzieren. Thanks :)

Antwort

0

Nun, das hat funktioniert, aber es ist eine traurige Art, es zu tun: |

//inside a static function in class PostPeer: 
$c = new Criteria(); 
self::addSelectColumns($c); //add all columns from PostPeer 
$c->addJoin(PostPeer::ID, CommentPeer::POST_ID, Criteria::LEFT_JOIN); 
$cu->addAsColumn('numofcomments', 'COUNT('.CommentPeer::POST_ID.')'); 
$cu->addGroupByColumn(PostPeer::ID); 
$cu->addGroupByColumn(PostPeer::TITLE); 
: 
: 
//more group-by columns if needed 
return PostPeer::doSelectStmt($c); 

dann in Vorlage greife ich auf das Array als:

<div id="title"> 
    <?php echo post_array[1] ?> 
</div> 
//...and so on for other Post fields 

Wie ich einen Array Verein Modell machen, so dass ich "post_array [ 'title']" in Vorlage schreiben statt " post_array [1] "? Ist diese Problemumgehung auch sicher? Jeder bessere Vorschlag. Ich verwende Propel 1.3

1

SELECT post.* , COUNT(comments.post_id) AS numcomments FROM post INNER JOIN comments ON post.id = comments.post_id GROUP BY post.id,post.secondcol,post.thirdcol; und so weiter, nur eine Liste aller einzelne Spalten in Ihrer Post Tabelle, da Sie Post auswählen. *, Müssen Sie sie alle, die Liste nicht nur post.post_id.

Alternativly

SELECT post.*,sub.numcomments from post, 
(select post.post_id as post_id,COUNT(comments.post_id) AS numcomments 
    FROM post INNER JOIN comments ON post.id = comments.post_id GROUP BY post.id) as sub 
    where post.post_id = sub.post_id; 

(Es gibt einen 3. und einfachen Weg, als auch, was ich vergessen habe jetzt ..)

+0

Dank @nos ...das war ein grundlegender Fehler, die Group-by-Abfrage nicht korrekt zu schreiben, aber die Frage ist anders. Ich habe es bearbeitet ... kannst du das nochmal überprüfen? :) – fenderplayer

0

Hier ist die Propel-Version Ihrer SQL-Abfrage.

$c = new Criteria(); 
// count comments with 
$c->addAsColumn('numofcomments', 'COUNT('.CommentPeer::POST_ID.')'); 
$c->addJoin(PostPeer::ID, CommentPeer::POST_ID, Criteria::LEFT_JOIN); 
$c->addGroupByColumn(PostPeer::ID); 
$c->addGroupByColumn(PostPeer::TITLE); 
// you can add more groupby column here 
//$c->addGroupByColumn(...more); 
$this->posts = PostPeer::doSelect($c); 

Sie sollten LEFT JOIN statt INNER JOIN verwenden. Weil. Mit innerem Join können Sie nur auf die Beiträge zugreifen, die mindestens einen Kommentar haben. Mit linker Verknüpfung können Sie unkommentierte Beiträge auswählen.

Ich hoffe, das hilft.

+0

Ich kann nicht auf 'numofcomments' in $ this-> Beiträge zugreifen. Dieser Ansatz erfordert wahrscheinlich benutzerdefinierte Hydratisierungsmethoden. Ich bin mir nicht sicher, wie ich das machen soll. – fenderplayer

1

Wenn Sie zusätzliche Daten in Ihre Objekte einbinden möchten, die von einer benutzerdefinierten Abfrage zurückgegeben werden, können Sie die standardmäßige Methode doSelect() in Ihrer Peerklasse überschreiben und diese zusätzlichen Daten aus Ihrer Abfrage in jedes Objekt einfügen das ist zurückgegeben.

In Ihrer posts-Klasse können Sie eine geschützte Variable hinzufügen, nennen wir sie "numComments".

class Post extends BasePost { 
    protected $numComments; 

    public function setNumComments($v) 
    { 
    $this->numComments = $v; 
    } 

    public function getNumComments() 
    { 
    return $this->numComments; 
    } 
    ... 
} 

und dann in Ihrer PostPeer Klasse in Ihrem statischen doSelectWithCount() -Methode:

public static function doSelectWithCount() { 
    $c = new Criteria(); 
    self::addSelectColumns($c); //add all columns from PostPeer 
    $c->addAsColumn('numofcomments', 'COUNT('.CommentPeer::POST_ID.')'); 
    $c->addJoin(PostPeer::ID, CommentPeer::POST_ID, Criteria::LEFT_JOIN); 
    $c->addGroupByColumn(PostPeer::ID); 
    $c->addGroupByColumn(PostPeer::TITLE); 
    // ... 
    // more group-by columns if needed 
    $rs = PostPeer::doSelectRS($c); 

    $posts = array(); 
    while ($rs->next()) { 
    $post = new Post(); 
    $post->hydrate($rs); 
    $post->setNumComments($rs->getInt(PostPeer::NUM_COLUMNS + 1)); 
    $posts[] = $post; 
    } 

    return $posts; 
} 
Verwandte Themen