目前我正在使用以下代码来获取特定类别的图书:
$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个表:categories
,books
和books_categories
。 books_categories有两个文件:book_id
和category_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语句中有些东西没有结束(循环?)...
答案 0 :(得分:1)
相对于更新的问题更新
为了使sql能够产生正确的结果(在可接受的时间内),您需要再次与Categories
一起加入另一个别名。由于这会导致另一个问题,因此我建议您使用mysql
和query-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