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_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'),
            ),
        );

这会生成这个查询(很抱歉 - 表名有点不同):

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 语句中有一些没有结束(循环?)的东西......

4

2 回答 2

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 书在“关联:将模型链接在一起”部分(重点是我的)的末尾提出了以下建议。

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

于 2012-11-15T10:27:23.437 回答
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

于 2012-11-15T21:55:20.993 回答