2012-05-13 3 views
0

나는 다음과 같은 MySQL의 테이블이 있습니다페이스 북은 CakePHP의 2.1 대화 목록처럼 (그룹 현명한 최대, 하위 쿼리에 조인과 관련한)

CREATE TABLE IF NOT EXISTS `conversations` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `user1_id` int(11) NOT NULL, 
    `user2_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `user1_id_2` (`user1_id`,`user2_id`) 
); 

CREATE TABLE IF NOT EXISTS `messages` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `conversation_id` int(11) NOT NULL, 
    `sender_id` int(11) NOT NULL, 
    `recipient_id` int(11) NOT NULL, 
    `subject` varchar(64) NOT NULL, 
    `body` text NOT NULL, 
    `created` datetime DEFAULT NULL, 
    `is_deleted_by_sender` tinyint(3) unsigned NOT NULL DEFAULT '0', 
    `is_deleted_by_recipient` tinyint(3) unsigned NOT NULL DEFAULT '0', 
    PRIMARY KEY (`id`) 
); 

참고 : 테이블 user1_id이 작거나 같은 user2_id하는 대화에서를 .

사용자 X의 대화 목록을 가져오고 싶습니다. 여기서 각 대화는 해당 대화에서 사용자 X가 삭제하지 않은 마지막 메시지로 표시되며 결과에 페이지 매김을 적용합니다. (페이 스북 메시지와 마찬가지로, 마지막 메시지가 X 또는 다른 사용자에 의해 보내 졌는지 여부에 관계없이 디스플레이 메시지로 표시됩니다.

다음 하위 쿼리를 생성하는 데 도움이 된 group-wise maximum solution까지 왔습니다.

SELECT m1.id, m1.conversation_id, m1.body, m1.sender_id, m1.recipient_id 
FROM messages m1 
INNER JOIN (THE_SUB_QUERY_ABOVE) m2 
ON (m1.conversation_id = m2.conversation_id 
AND m1.id = m2.id) 
ORDER BY m1.id DESC 

:

SELECT MAX(SubTable.id) AS id, conversation_id 
FROM newtravel.messages AS SubTable 
WHERE (
((SubTable.sender_id = 9) AND (SubTable.is_deleted_by_sender = 0)) 
OR 
((SubTable.recipient_id = 9) AND (SubTable.is_deleted_by_recipient = 0)) 
) 
GROUP BY conversation_id 

우리는 등록을 마친 경우, 다음과 같은 쿼리를 생성한다 $ this-> Paginator-> 설정 배열에 조인 테이블로이 하위 쿼리를 사용할 수 이 최종 쿼리는 원하는 결과를 반환하지만, PaginatorComponent에서 올바른 옵션을 설정합니다. 이러한 종류의 쿼리에는 공식 문서가 부족합니다. 그렇다면이 상황에서 찾기 조건, 조인, 하위 쿼리 등을 어떻게 구성 할 수 있습니까?

답변

0

좋아.

$this->Message->Behaviors->attach('Containable'); 

$conditionsSubQuery = array(
    'OR' => array(
     array(
      'SubTable.sender_id' => $this->Auth->user('id'), 
      'SubTable.is_deleted_by_sender' => 0 
     ), 
     array(
      'SubTable.recipient_id' => $this->Auth->user('id'), 
      'SubTable.is_deleted_by_recipient' => 0 
     ) 
    ) 
); 

$db = $this->Message->getDataSource(); 
$subQuery = $db->buildStatement(
     array(
    'fields' => array('MAX(id)'), 
    'table' => $db->fullTableName($this->Message), 
    'alias' => 'SubTable', 
    'limit' => null, 
    'offset' => null, 
    'joins' => array(), 
    'conditions' => $conditionsSubQuery, 
    'order' => null, 
    'group' => 'conversation_id', 
     ), $this->Message 
); 

$subQuery = ' Message.id IN (' . $subQuery . ') '; 

$this->Paginator->settings = array(
    'Message' => array(
     'limit' => 5, 
     'maxLimit' => 5, 
     'contain' => array(
      'Sender' => array(
       'id', 'name', 'is_online', 'profile_image', 'thumbnail' 
      ), 
      'Recipient' => array(
       'id', 'name', 'is_online', 'profile_image', 'thumbnail' 
      ), 
      'Conversation' 
     ), 
     'order' => 'Message.id DESC' 
    ) 
); 

$this->set('conversations', $this->Paginator->paginate('Message', $subQuery)); 

참고이 "사용자"테이블에 대한 별칭이다 "메시지"belongsTo를 "보낸 사람"과 "받는 사람", 다음과 같이 나는이 문제를 해결했습니다.