如何从一个类别中获取书籍(不包括其他类别)(通过交叉表格)

时间:2012-11-15 09:17:05

标签: cakephp cakephp-2.1

目前我正在使用以下代码来获取特定类别的图书:

$options['conditions']['Category.id'] = $category_id;
$options['joins'] = array(
    array(
        'table' => 'books_categories',
        'alias' => 'BookCategory',
        'type' => 'inner',
        'conditions' => array('Book.id = BookCategory.id_book'),
    ),
    array(
        'table' => 'categories',
        'alias' => 'Category',
        'type' => 'inner',
        'conditions' => array('BookCategory.kat = Category.id'),
    ),
);

$this->Book->find('all',$options);

这只是查找给定category_id的所有书籍。

所以有3个表:categoriesbooksbooks_categories。 books_categories有两个文件:book_idcategory_id所以基本上它只是HABTM关系。问题是,一本书可能属于许多类别,我想例如找到第5类的所有书籍,但不包括第5,6和7类的书籍。我怎么能这样做?

编辑---------------------------------------------- ---------------------------------

好的,所以我想出它应该在纯SQL中看起来 - 条件应该是这样的:

where
  category_id = <given category>
  and books.book_id not in
(
 select book_id from book_categories
  where category_id in (<given set of cat>)
)
order by books.inserted

这将获得一个类别的所有书籍,但不包括来自其他类别的书籍。 现在我想强制Cake生成类似的SQL查询。 我到目前为止尝试过:

$options['conditions']['Category.id'] = $category_id;       
$options['conditions']['AND'][] = 'Book.id NOT IN (SELECT id_book FROM book_categories WHERE kat IN (133,134))';

$options['order'] = array('Book.inserted' => 'desc');
$options['joins'] = array(
            array(
                'table' => 'book_categories',
                'alias' => 'BookCategory',
                'type' => 'inner',
                'conditions' => array('Book.id = BookCategory.id_book'),
            ),
            array(
                'table' => 'categories',
                'alias' => 'Category',
                'type' => 'inner',
                'conditions' => array('BookCategory.kat = Category.id'),
            ),
        );

这会生成此查询(sory - 表名略有点不同):

SELECT `Book`.`id`, `Book`.`OK`, `Book`.`price`, `Book`.`link`, `Book`.`title`, 
`Book`.`author`, `Book`.`img`, `Book`.`inserted`, `Book`.`checked`, `Book`.`big_img`, `Book`.`lang`, `Book`.`asin`, `Book`.`description`, `Book`.`last_update`, `Book`.`review`, `Book`.`changed` 
FROM `amazon`.`linki` AS `Book` 
inner JOIN `amazon`.`cross_kategorie_full` AS `BookCategory` ON (`Book`.`id` = `BookCategory`.`id_book`) 
inner JOIN `amazon`.`kategorie` AS `Category` ON (`BookCategory`.`kat` = `Category`.`id`) 
WHERE `Category`.`id` = 4 
AND `Book`.`OK` = 'OK' 
AND ((`Book`.`big_img` NOT LIKE '%no-image%') 
AND (`Book`.`id` NOT IN (SELECT id_book FROM cross_kategorie_full WHERE kat IN (133,134)))) 
ORDER BY `Book`.`inserted` desc LIMIT 20

但是有错误:超过30秒的最大执行时间 - 所以在这个sql语句中有些东西没有结束(循环?)...

2 个答案:

答案 0 :(得分:1)

相对于更新的问题更新
为了使sql能够产生正确的结果(在可接受的时间内),您需要再次与Categories一起加入另一个别名。由于这会导致另一个问题,因此我建议您使用mysqlquery-optimization发布标记 结束更新

实际上, HABTM关系有点狡猾(因为它确实不是HABTM)。如果books_categories中每个图书类别匹配只有一行,则您无法知道某本书属于哪些其他类别,因此您无法确切地知道您真正想要哪些类别(即不属于在其他类别)。这是CakePHP的数据层和模型,可以在幕后为您解决这个问题:)

我看到的唯一解决方案是使用Set::extract进一步查询您获得的结果,并过滤掉您不想包含的类别的图书。 (如:

// returns all books not belonging to categories 3,4
$new_result = Set::extract('/Books/Category[id!=3][!=4]', $results); 

在旁注中,我发现在这样的情况下它非常有用,可以查询数据库并可视化SQL查询的复杂性,从而获得所需的结果。此外,您应该激活CakePHP调试工具栏以查看发送到数据库的SQL查询,以便您更好地了解幕后发生的情况。

CakePHP书,在"Associations: Linking models together"部分(强调我的)结尾处建议以下内容。

  

使用连接可以让您在CakePHP处理关联和获取数据方面具有最大的灵活性,但是在大多数情况下,可以使用其他工具来实现相同的结果,例如正确定义关联,绑定动态模型并使用Containable行为。 应谨慎使用此功能,因为在某些情况下,如果与用于关联模型的任何前述技术相结合,它可能会导致错误的SQL查询。

答案 1 :(得分:0)

我认为那里有一个错字。您想获得第5类但不是第5,6和7类的所有书籍吗?

没关系。 Cake convensions声明HABTM表中应该始终存在主键,因此您可以添加“id”列。有了这个,接下来的步骤就容易多了,或者我应该说:“他们正在变得可能”。

您接下来要做的是,创建一个名为“BooksCategory”的关联模型。 使用此处说明的“with”索引将Book和Category模型相互链接在该新模型上。如果链接模型属于插件,请不要忘记使用插件语法(PluginName.ModelName)。 您现在在链接模型中为要链接的每个模型放置两个belongsTo关联。这确保在查找时获取它们。

接下来你要做的是:

$this->Book->BooksCategory->find(
    'all',
    array(
        'conditions' => array(
            'BooksCategory.category_id' => 5
        )
    )
);

已完成;)不,您只能获得第5类的书籍。

问候 func0der