SQL-запрос (внутреннее объединение + количество + группировка по) с помощью Propel - PullRequest
1 голос
/ 03 августа 2009

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

РЕДАКТИРОВАТЬ: Что я хотел знать, как я могу написать вышеупомянутый запрос в Propel? Теперь я могу получить таблицу сообщений с внутренним соединением таблицы комментариев, а затем запустить doCount таблицы комментариев для каждого идентификатора записи. Это приводит к 1 запросу для таблицы сообщений и множеству запросов для таблицы комментариев. Я хочу сократить запросы SQL к минимуму. Спасибо:)

Ответы [ 4 ]

1 голос
/ 07 августа 2009

Если вы хотите упаковать дополнительные данные в ваши объекты, возвращаемые пользовательским запросом, вы можете переопределить метод 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;
}
1 голос
/ 03 августа 2009

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.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 голосов
/ 05 августа 2009

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

//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 ['title']" в шаблоне вместо "post_array [1]"? Кроме того, этот обходной путь безопасен? Любое лучшее предложение. Я использую Propel 1.3

0 голосов
/ 04 августа 2009

Вот Propel-версия вашего SQL-запроса.

$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. Так как. с внутренним соединением вы можете получить доступ только к тем сообщениям, которые содержат хотя бы один комментарий. При помощи левого соединения вы можете выбирать не комментируемые сообщения.

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

...