2011-02-02 9 views
2

と交差し、私はどのようにフレーズの質問には本当にわからないんだけど、そう私はちょうど問題の例をあげてみましょう:PHP/MySQLの:多対多/テーブルの質問

項目をマッピングするテーブルがありますと仮定カテゴリに。各項目は任意の数のカテゴリを持つことができ、各カテゴリは任意の数の項目を保持することができます。

items_categories

問題があるが、私は特定のカテゴリのIDを持つすべてのアイテムのIDを選択するようにしたいのidのitem_id CATEGORY_ID:だから、このようになりますテーブルを持っています。たとえば、category_idが1と2のitem_idをすべて選択します。1と2の両方のカテゴリに関連付けられているすべての項目を検索したいと思います。明らかにAND文は使用できません。また、OR文はどちらのカテゴリ必ずしも両方である必要はない。

これは私の考えであり、私が考えることができる最高のものです:category_idが1または2に等しいすべてのitem_idsを選択してください。 PHPの結果を繰り返し、category_idに関連付けられているitem_idの数を追跡します。指定された数のカテゴリを持たない結果のitem_idをすべて解除します。ここに私のコードの抜粋です:

// 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 

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

ありがとうございます!

編集:ここでははテーブルと私はそれから必要な情報の例です:

​​

だから、私はどのように私は、カテゴリ1とすべての項目を得ることに興味があると言うと2カテゴリ#1 #2のアイテムのみを欲しいとすれば、サンプルテーブルからアイテム#1を取得しますか?上記の例のようにカテゴリ1 または 2をすべて選択すると、カテゴリ1とカテゴリ2の両方に関連付けられていないため、この場合はテーブル全体を選択してitem_id 2と3を手動で削除する必要があります。カテゴリ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」は検索しているカテゴリの数で置き換えられます。

したがって、各アイテムの基準に一致するカテゴリの数がわかります。すべてのカテゴリが一致するアイテムのみが必要なので、カテゴリの数が探しているカテゴリの数と等しいものだけを選択します。これはもちろん、重複したカテゴリやそのようなものがないと仮定しています。

ありがとうございました!

答えて

1

あなたが悩んでいるのは、もちろんO(n)時間かかる線形検索を余儀なくされているようですが、ソート順でデータベースから要素を選択すると、 O(lg n)時間のバイナリ検索?

私はこれが役立つことを願っています。そうでなければ、私はあなたの質問を誤解しているかもしれません。私はそれを少し明確にしたいと思います。

+0

感謝。つまり、私は結果から特定の価値を探しているわけではありません。結果から各項目がどのように関連しているかを知りたいだけです。その番号が検索しているカテゴリの数と異なる場合は、そのカテゴリにすべてのカテゴリが含まれていないことがわかります。私がこれを正しく理解しているならば、バイナリ検索は実際にはこれを達成できないと思います。特定の値を探しているわけではないからです。 – user599599

+0

ところで、元の投稿を編集して、もう少し明確にすることを願っています。 – user599599

0
SELECT 
foo 
FROM 
bar 
WHERE 
foo IN (1,2) 

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

+0

これは、基本的にはfoo = 1またはfoo = 2を選択することで実現します。つまり、よりきれいですが、PHPで配列処理を同じ量だけ行う必要があります。 (もちろん、これは可能ではありません。なぜなら、特定の行に対して "foo"は1つの値を持ちますが、私の場合は同じitem_idとcategory_idを持つ複数の行が必要です)。 – user599599

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は、それぞれのカテゴリーと項目テーブルの有効なエントリを指している他の言葉で、正確であることを前提としていません。外部キーをサポートしているデータベース(MySQL、Postgres用のInnoDBエンジンなど)を使用している場合、外部キーを強制するのは難しくありません。

各カテゴリの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; 
+0

応答してくれてありがとう - それはあなたがそれを与えるカテゴリの* *にあるアイテムを返します。カテゴリの* all *にあるアイテムに興味があります。いずれにしても、あなたのカウントクエリは私に考えさせて、問題を解決しました。私はちょうど各項目が一致するカテゴリの数を数え、それが私が探しているカテゴリの数と等しいことを確認しなければなりませんでした。 – user599599

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) 
+0

これはまさに私がやりたいことです!しかし、私がテストデータベース(1000以上のアイテム)に対して実行したところ、少し遅くなったようです。元の投稿の私の最後のクエリは同じことをしますが、私はそれをより速くする方法を考え出しました。 – user599599

関連する問題