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 からすべての本を検索するだけです。

したがってcategories、 、booksおよび の 3 つのテーブルがありbooks_categoriesます。books_categories には 2 つのフィールドがあります。つまりbook_id、基本的にはcategory_id単なる HABTM 関係です。問題は、1 つの本が多くのカテゴリに属している可能性があることです。たとえば、カテゴリ 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

これにより、1 つのカテゴリからすべての本が取得されますが、他の一連のカテゴリからの本は除外されます。ここで、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 ではないため)。書籍カテゴリの一致ごとに 1 行しかない場合books_categories、特定の書籍が他のどのカテゴリに属しているかを知ることができないため、本当に必要な書籍 (つまり、他のカテゴリに属していない) を実際に判断することはできません。 . 舞台裏でこの問題を解決するのは、CakePHP のデータ層とモデルです :)

私が見る唯一の解決策はSet::extract、取得した結果をさらにクエリし、含めたくないカテゴリに属する​​本を除外することです。(何かのようなもの:

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

余談ですが、このような場合、DB にクエリを実行し、必要な結果を得る SQL クエリの複雑さを視覚化することは非常に便利です。また、CakePHP デバッグ ツールバーをアクティブにして、DB に送信される SQL クエリを表示し、舞台裏で何が起こっているかをよりよく理解する必要があります。

CakePHP の本では、「関連付け: モデルを相互にリンクする」セクションの最後で次のようにアドバイスされています (強調は私のものです)。

結合を使用すると、CakePHP が関連付けを処理してデータをフェッチする方法を最大限に柔軟に設定できますが、ほとんどの場合、関連付けを正しく定義したり、モデルをオンザフライでバインドしたり、Containable 動作を使用したりするなど、他のツールを使用して同じ結果を得ることができます。この機能は、モデルを関連付けるために説明した以前の手法のいずれかと組み合わせると、場合によっては不適切な形式の SQL クエリにつながる可能性があるため、注意して使用する必要があります。

于 2012-11-15T10:27:23.437 に答える
0

そこにはタイプミスがあると思います。カテゴリ5からではなく、カテゴリ5、6、7からすべての本を取得したいですか?

どうでも。Cake convensionsは、HABTMテーブル内に常に主キーが存在する必要があると述べているため、「id」列を追加できます。これにより、次のステップははるかに簡単になります。または、「彼らは可能になりつつある」と言うべきです。

次に行うことは、「BooksCategory」と呼ばれる関連付けモデルを作成することです。ここで説明されている「with」インデックスを使用して、BookモデルとCategoryモデルをその新しいモデル上で相互にリンクします。リンクモデルがプラグインに属している場合は、プラグイン構文(PluginName.ModelName)を使用することを忘れないでください。これで、リンクしているモデルごとに、リンクモデルに2つのbelongsToアソシエーションを配置しています。これにより、検索中にそれらを確実にフェッチできます。

次に行うことは次のとおりです。

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

終了しました;)いいえ、カテゴリ5の本しか入手できません。

あいさつfunc0der

于 2012-11-15T21:55:20.993 に答える