2009-08-03 4 views
1

Я хочу показать количество комментариев для каждого сообщения в блоге (наряду с категорией, датой, автором и т. Д.) На странице со списком сообщений в блоге. Как написать следующий запрос mysql в propel?Запрос Sql (внутреннее объединение + счет + группа) с использованием 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 

где пост таблицы и комментарии блога, таблица комментариев с POST_ID в качестве внешнего ключа для post.id. Кажется, я не могу получить «numofcomments» в качестве столбца в наборе результатов. В настоящее время я использую подход без ORM (который будет моим последним средством):

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

Как я могу получить доступ к «numofcomments» в результате Propel результирующем?

EDIT: Я хотел бы знать, как я могу написать вышеуказанный запрос в Propel? Теперь я могу получить стол столбец с внутренним соединением в таблице комментариев, а затем запустить doCount в таблице комментариев для каждого post-id. Это приводит к 1 запросу для таблицы Post и множеству запросов для таблицы комментариев. Я хочу свести запросы sql к минимуму. Спасибо :)

ответ

0

Ну, это то, что сработало, но его печальный способ сделать это: |

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

Затем в шаблоне я получения доступа к массиву как:

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

Как мне сделать ассоциацию массива в модели, так что я могу написать «post_array [„название“]» в шаблоне вместо " post_array [1] "? Кроме того, это обходное решение безопасно? Любое лучшее предложение. Я использую 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; и так далее, просто перечислить все отдельные столбцы в таблице после, так как вы выбираете почту. *, Вы должны перечислить их все, а не только 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; 

(Там в 3 и более простой способ, как хорошо, что я теперь забыл ..)

+0

Благодаря @nos ...это был фундаментальный надзор с моей стороны в том, что я неправильно писал запрос по группе, но вопрос другой. Я его отредактировал ... вы можете проверить еще раз? :) – fenderplayer

0

Вот версия передвижением вашего запроса.

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

Вы должны использовать LEFT JOIN вместо INNER JOIN. Потому как. с внутренним соединением вы можете получить доступ только к сообщениям, у которых есть хотя бы один комментарий. С левым соединением вы можете выбрать неуправляемые сообщения.

Надеюсь, это поможет.

+0

Я не могу получить доступ к 'numofcomments' в $ this-> сообщениях. Этот подход, вероятно, требует специальных методов увлажнения. Я не уверен, как это сделать. – fenderplayer

1

Если вы хотите упаковать дополнительные данные в объекты, возвращаемые настраиваемым запросом, вы можете переопределить метод doSelect() по умолчанию в своем одноранговом классе и добавить эти дополнительные данные из вашего запроса в каждый объект это возвращается.

В вашем классе сообщений вы можете добавить защищенную переменную, назовем ее «numComments».

class Post extends BasePost { 
    protected $numComments; 

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

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

, а затем в своем классе PostPeer в вашем методе статической doSelectWithCount():

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; 
}