Как написать запрос на объединение нескольких таблиц в CakePHP? - PullRequest
15 голосов
/ 30 апреля 2009

Может кто-нибудь сказать мне, как получить объединенный результат из нескольких таблиц в cakePHP (используя архитектуру cakePHP mvc). Например, у меня есть три таблицы для объединения (tbl_topics, tbl_items, tbl_votes. Их отношение определяется следующим образом: тема может иметь много элементов, а элемент может иметь много голосов. Теперь я хочу получить список тем с количеством все голоса по всем пунктам для каждой темы. SQL-запрос для этого написан ниже:

SELECT Topic.*, count(Vote.id) voteCount 
FROM 
tbl_topics AS Topic 
LEFT OUTER JOIN tbl_items AS Item 
ON (Topic.id = Item.topic_id)
LEFT OUTER JOIN tbl_votes AS Vote
ON (Item.id = Vote.item_id); 

Моя проблема в том, что я могу сделать это легко, используя функцию $this-><Model Name>->query, но для этого требуется, чтобы в контроллере был написан SQL-код, который мне не нужен. Я пытаюсь найти любой другой способ сделать это (например, find()).

Ответы [ 6 ]

40 голосов
/ 10 мая 2009
$markers = $this->Marker->find('all', array('joins' => array(
    array(
        'table' => 'markers_tags',
        'alias' => 'MarkersTag',
        'type' => 'inner',
        'foreignKey' => false,
        'conditions'=> array('MarkersTag.marker_id = Marker.id')
    ),
    array(
        'table' => 'tags',
        'alias' => 'Tag',
        'type' => 'inner',
        'foreignKey' => false,
        'conditions'=> array(
            'Tag.id = MarkersTag.tag_id',
            'Tag.tag' => explode(' ', $this->params['url']['q'])
        )
    )
))); 

как указано в статье Нэйта Абеля: текст ссылки

2 голосов
/ 09 мая 2009

Вы можете легко установить свойство "recursive" для запроса find ().

$result = $this->Topic->find('all', array('recursive' => 2));

Кроме того, вы можете использовать поведение Containable в вашей модели. Тогда вы можете использовать:

$this->Topic->contain(array(
    'Item',
    'Item.Vote',
));

$result = $this->Topic->find('all');

или

$result = $this->Topic->find('all', array(
    'contain' => array(
        'Item',
        'Item.Vote',
    ),
));
2 голосов
/ 30 апреля 2009

Я буду честен здесь и скажу, что вы, вероятно, будете намного счастливее, если просто создадите функцию в своей модели, что-то вроде getTopicVotes () и вызовите query () там. Любое другое решение, которое я могу придумать, только сделает его более сложным и, следовательно, более уродливым.

Edit:

В зависимости от размера ваших данных и при условии, что вы правильно настроили отношения модели (Тема имеет много элементов имеет много голосов), вы можете выполнить простой поиск («все»), содержащий все пункты и голоса, а затем сделать что-то вроде этого:

foreach ($this->data as &$topic)
{
    $votes = Set::extract('/Topic/Item/Vote', $topic);
    $topic['Topic']['vote_count'] = count($votes);
}

Здесь важны две вещи:

  1. Если у вас много данных, вы, вероятно, должны забыть об этом подходе, он будет чертовски медленным.
  2. Я написал это из моей памяти, и в реальной жизни это может выглядеть не так и / или вообще не работать: -)
1 голос
/ 01 мая 2009

Что вам нужно, так это поддержка рекурсивных ассоциаций, которая в настоящее время невозможна для стокового CakePHP.
Хотя это может быть достигнуто с помощью некоторого обманщика bindModel
или экспериментальное RecursiveAssociationBehavior .

Оба эти решения потребуют либо от вас использования дополнительного кода, либо от поведения в вашем приложении, но если вы будете сопротивляться искушению написать чистый код SQL, вы будете вознаграждены возможностью использовать разбиение на страницы Cake авто условия, модель магии и т.д ..

0 голосов
/ 29 мая 2019

Я думаю, что этот ответ уже отправлен, но я публикую здесь для кого-то, кто все еще ищет это. Объединения могут быть выполнены с помощью метода find (), как показано ниже

$result = $this->ModelName1->find("all",array(
'fields' => array('ModelName1.field_name','Table2.field_names'), // retrieving fileds 
'joins' => array(  // join array
    array(
        'table' => 'table_name',
        'alias' => 'Table2',
        'type' => 'inner',
        'foreignKey' => false,
        'conditions'=> array('ModelName1.id = Table2.id') // joins conditions array
    ),
    array(
        'table' => 'table_name3',
        'alias' => 'Table3',
        'type' => 'inner',
        'foreignKey' => false,
        'conditions'=> array('Table3.id = Table2.id')
    )
))); 
0 голосов
/ 30 апреля 2009

Вы должны изучать HaBTM (Имеет и принадлежит многим) http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...