3

質問の言い方がよくわからないので、問題の例を挙げましょう。

項目をカテゴリにマップするテーブルがあるとします。各アイテムには任意の数のカテゴリを含めることができ、各カテゴリにはもちろん任意の数のアイテムを保持できます。したがって、次のようなテーブルがあります。

items_categories

id item_id カテゴリ ID

問題は、特定のカテゴリ ID を持つすべてのアイテム ID を選択したいということです。たとえば、category_id が 1 と 2 のすべての item_id を選択します。カテゴリ 1 と 2 の両方に関連付けられているすべてのアイテムを検索したいです。明らかに、AND ステートメントは使用できず、OR ステートメントはいずれかのカテゴリのすべての item_id を返します。 、必ずしも両方ではありません。

これが私の解決策であり、私が考えることができる最善の方法です。category_id が 1 または 2 のすべての item_id を選択します。PHP で結果を反復処理し、category_id に関連付けられている item_id の数を追跡します。次に、指定された数のカテゴリを持たない結果のすべての item_ids を設定解除します。これが私のコードのスニペットです:

// assume $results is an array of rows from the db
// query: SELECT * FROM items_categories WHERE category_id = 1 OR category_id = 2;
$out = array();
foreach ($results as $result)
{
    if (isset($out[$result['item_id']]))
        $out[$result['item_id']] ++;
    else
        $out[$result['item_id']] = 1;
}
foreach ($out as $key=>$value)
{
    if ($value != 2)
        unset($out($key));
}
return array_keys($out); // returns array of item_ids

明らかに、さまざまなカテゴリが多数ある場合、理論的に必要な情報よりも多くの情報を選択して処理していることになります。何か案は?

ありがとう!

編集:テーブルとそこから必要な情報の例を次に示します。

id item_id category_id
1 1 1
2 1 2
3 2 1
4 3 2

たとえば、カテゴリ 1 と 2 のすべてのアイテムを取得することに関心があるとします。カテゴリ #1と#2のアイテムのみが必要な場合、例のテーブルからアイテム #1 を取得するにはどうすればよいでしょうか? カテゴリ 1または2のすべてを選択する場合(上記の例のように)、この場合はテーブル全体を選択し、item_id の 2 と 3 を「手動で」削除する必要があります。これらはカテゴリ 1 とカテゴリ 2 の両方に関連付けられていないためです。これが少し明確になることを願っています。

最終編集:私がやろうとしていることを説明することが明らかにできないにもかかわらず、私はそれを理解しました. 記録のために、私が思いついたクエリは次のとおりです。

SELECT *
FROM
(
    SELECT item_id, COUNT(*) as count
        FROM items_categories
        WHERE category_id IN (1, 2)
    GROUP BY item_id
) table_count
WHERE count = 2;

この場合、"(1, 2)" は "( category_id1 , category_id2 , ...)" に置き換えられ、最後の "2" は検索するカテゴリの数に置き換えられます。

したがって、各アイテムの条件に一致するカテゴリの数がわかり、すべてのカテゴリが一致するアイテムのみが必要なため、探しているカテゴリの数と等しいカテゴリの数のみが選択されます。もちろん、これは重複するカテゴリなどがないことを前提としています。

回答ありがとうございます。

4

4 に答える 4

1

あなたを悩ませているのは、もちろんO(n)時間かかる線形検索を行うことを余儀なくされているようですが、データベースから要素をソートされた順序で選択すると、二分検索を使用することはできません. O(lg n) 時間?

これがお役に立てば幸いです。そうでない場合は、あなたの質問を誤解している可能性があります。少し明確にしていただきたいと思います。

于 2011-02-02T07:25:03.097 に答える
0
SELECT
 foo
FROM
 bar
WHERE
foo IN (1,2) 

これはあなたが探しているものですか?

于 2011-02-02T07:32:07.950 に答える
0

これは、PHP ではなくデータベースに実行させるべきものです。

SELECT item_id                 # We want a list of item ids
FROM cat_items                 # Gets the item ID list from the cat_items table
WHERE cat_id IN (1, 2, 7, 11)  # List of categories you want to search in
GROUP BY item_id;              # As the same item can appear in more than one category this line will eliminate duplicates

このクエリは、cat_items のデータが正確であること、つまり、カテゴリ ID とアイテム ID がそれぞれカテゴリ テーブルとアイテム テーブルの有効なエントリを指していることを前提としています。外部キーをサポートするデータベース (MySQL 用の InnoDB エンジン、Postgres など) を使用している場合、外部キーの強制は難しくありません。

必要な形式で各カテゴリの ID のリストを取得するには、SQL 側でも簡単に実行できます。

SELECT * 
FROM cat_items 
WHERE cat_id IN (1, 2, 7, 11)
GROUP BY cat_id, item_id;

各カテゴリに含まれるアイテムの数だけが必要な場合は、SQL でそれを行うこともできます

SELECT cat_id, COUNT(item_id) AS items
FROM cat_items 
WHERE cat_id IN (1, 2, 7, 11)
GROUP BY cat_id;

ID 以外のデータが必要な場合は、データが必要なテーブルに対して結合できます。

SELECT items.* 
FROM cat_items 
JOIN items ON cat_items.item_id = items.id 
WHERE cat_id IN (1, 2, 7, 11)
GROUP BY item_id;
于 2011-02-02T08:48:07.083 に答える
0
SELECT item_id FROM items_categories WHERE category_id = 1 AND item_id IN (SELECT item_id FROM items_categories WHERE category_id = 2)
于 2011-02-02T08:58:28.977 に答える