2009-06-18 7 views
0

私は一意のアイテムIDを使用して参加しているテーブルをたくさん持っています。 where句の条件の大部分は、ユーザーが嫌うフォーム(検索ボックス)からプログラムで構築され、複数の条件が同じテーブル(この場合はitemタグ)に対してテストされることがよくあります。複数のwhere節を使用して複数の表を選択すると、自己結合よりも良い方法がありますか?

私のSQLの経験はほとんどありませんが、私は基本を理解しています。私は、値が "cats"と "kittens"で、特定のタイプのタグでタグ付けされたアクティブ(status = 1)アイテムのIDを探したいと思います。タグは(id、product_id、tag_type_id、value)として格納され、idは一意の値を必要とする唯一の列です。私の最初の試みは、

select 
     distinct p2c.product_id 
    from '.TABLE_PRODUCT_TO_CATEGORY.' p2c 
     inner join '.TABLE_PRODUCT.' p on p2c.product_id = p.id 
     inner join '.TABLE_PRODUCT_TAG.' pt on p.id = pt.product_id 
     inner join '.TABLE_TAG_TYPE.' tt on pt.tag_type_id = tt.id 
    where 
     tt.id = '.PRODUCT_TAG_TYPE_FREE_TAG.' 
     and p.status = 1 
     and lower(pt.value) = "cats" 
     and lower(pt.value) = "kittens" 

しかし、何も返されません。私は最終的なAND条件が問題であることを認識しました。代わりに自己結合を使用して試しました。

select 
     distinct p2c.product_id 
    from '.TABLE_PRODUCT_TO_CATEGORY.' p2c 
     inner join '.TABLE_PRODUCT.' p on p2c.product_id = p.id 
     inner join '.TABLE_PRODUCT_TAG.' pt on p.id = pt.product_id 
     inner join '.TABLE_PRODUCT_TAG.' pt2 on p.id = pt2.product_id 
     inner join '.TABLE_TAG_TYPE.' tt on pt.tag_type_id = tt.id 
    where 
     tt.id = '.PRODUCT_TAG_TYPE_FREE_TAG.' 
     and p.status = 1 
     and lower(pt.value) = "cats" 
     and lower(pt2.value) = "kittens" 

これですべてが正常に動作し、結果セットが正しいようになりました。だから私は何を知りたいのですか?反復処理を行うには、「cats」と「kittens」の値を持つ特定のタイプのタグでタグ付けされたアクティブ(status = 1)アイテムのIDです。

  1. 自己結合は、これらの結果を達成する最良の方法ですか?
  2. このクエリは巨大になる可能性があります(カテゴリ条件は省略されていますが、そのうちの300件が存在する可能性があります)。そうでない場合は、代替手段がありますか?
  3. ユーザーが複雑なタグ検索を指定できるようにすると、自己結合アプローチが最善の方法です(代替があると仮定して)。すなわち「猫」および「猫」(「子猫」または「犬」)は「オウム」ではない。
+0

値が同時に猫と子猫することはできませんので、あなたは何のレコードを得ませんでした。そのため、OR句を使用すると効果的です。 – HLGEM

+0

しかし、ORは私が何をしたのかではないので、私は "猫"と "子猫"の両方のアイテムが欲しいです。私の最初の誤ったSQL構文の使用に関する点。一度に値を2つにすることはできません。したがって、自己結合を使用して2番目の試み... – Mathew

+0

私は製品の "タグ"に使用されるスキーマを記述することができれば、多くの混乱が解消されると思います。 –

答えて

0

の操作を行います。値が両方とも「猫であるために何のタグが存在しない

and lower(pt.value) = "cats" 
    and lower(pt.value) = "kittens" 

"と"子猫 "、したがってレコードは返されません。 SQLMenaceとしてIN句を使用することで解決策が提案されます。つまり、「猫や子猫にタグ付けされたアクティブなアイテムを返す」ということです。

しかし、両方のタグを持つアクティブなアイテムが必要な場合は、2番目のクエリのようにする必要があります。それがあなたの後であるかどうかはあなたの質問から完全にはっきりしていません。

"猫" と( "子猫" や "犬")ではない "オウム":あなたの質問#3のようなものについては

あなたはPT1、PT2、及び(サブクエリ内)PT3、およびこのような何かしたいと思う:広く一般的なケースは非常に厄介でした

and lower(pt1.value) = "cats" 
and lower(pt2.value) in ("kittens", "dogs") 
and not exists (select * from '.TABLE_PRODUCT_TAG.' pt3 where pt3.product_id = p.id and lower(pt3.value) = "parrots") 

を...

+0

あなたは「あなたの2番目のクエリのようなもの」と言っていますが、これは同じ結果を達成する自己結合の代替手段があることを意味しますか?また、私はあなたが「広範に一般的なケースはかなり乱雑になる可能性があります...」という意味を理解していません。参考までに、物事を少しはっきりさせるために質問を編集しました。 – Mathew

+0

私は「あなたの2番目のクエリのようなもの」と思います。私は自己結合または副選択を意味します。 "厄介な"とは - たまには、タグテーブルへの複数の結合が必要な場合があります。ORまたはIN句が必要な場合もあります。存在しない場合は副選択が必要な場合もあります。それは一般化することは複雑です。 –

+0

Gotcha、ありがとう。 :) – Mathew

3
select 
    distinct p2c.product_id 
from '.TABLE_PRODUCT_TO_CATEGORY.' p2c 
    inner join '.TABLE_PRODUCT.' p on p2c.product_id = p.id 
    inner join '.TABLE_PRODUCT_TAG.' pt on p.id = pt.product_id 
    inner join '.TABLE_TAG_TYPE.' tt on pt.tag_type_id = tt.id 
where 
    tt.id = '.PRODUCT_TAG_TYPE_FREE_TAG.' 
    and p.status = 1 
    and (lower(pt.value) = "cats" or lower(pt.value) = "kittens") 
+0

完璧に動作しますが、私は"猫 "や"子猫 "の後ではなく、"猫 "や"子猫 "ではありません – Mathew

+0

MatW、あなたは非常に混乱していると思います。 「cats OR kittens」を検索すると、ORを持つ行がすべて取得されます。これは論理的には「cats」PLUSの「cattens」を持つすべての行と同じです。 – Svante

+0

いいえ、混乱はありません。私は、 "cats"と "kittens"の行が一致する項目だけでなく、両方に一致する行がある項目、つまりANDステートメントが必要な項目に対して、行一致がある項目は望みません。各項目には、複数のタグを割り当てることができます。 – Mathew

4

これは最初のクエリでは機能しませんか?

代わりの

and lower(pt.value) = "cats" 
and lower(pt.value) = "kittens" 

最初のクエリに問題がこのしたこの

and lower(pt.value) in ("cats","kittens") 
+0

素晴らしいですが、私はこの構文が存在することを認識していませんでした。私が間違っていない限り、この構文は省略形です。 " "と "lower(pt.value)=" cats "以下(pt.value)=" kittens ")" と私は "cats"や "kittens"の後にいます。 "cats"や "kittens"ではありません – Mathew

+0

あなたは同じ列に猫と子猫を持つことができますか? – SQLMenace

+0

これらは同じ行にありません。 – dkretz

0

あなたの答え「はい、それはスケーラブルなテクニックです」複雑さを加える限り、効率的なクエリの問題が発生する前に、ユーザーが何をしているのかを理解する能力を超えてしまうと思います。

0

もう1つのエンティティ属性値モデルを構築しています。スケーラビリティについて尋ねたので、ここに警告があります:EAVモデルは、通常、スケールされず、RDBMS上で実行されません。結局のところ、この「柔軟な」データ・モデルはオプティマイザを壊してしまい、数百万行をスキャンして少数の犬や子猫をフェッチします。ウィキペディアはtopic covering this model and some of the downsidesです。あなたのターゲットDBが何であるかわからない、例えばSQL Server CAT published a white paper、EAVモデルのよくある問題。

+0

リソースをありがとう(より多くの学習、phew!)。しかし、タグスキーマは正規化されていないものの、EAVでもありません。 PRODUCT_TAG_TYPE_FREE_TAGという条件定数は物事を混乱させ、EAV設計を推測したものだと仮定しますが、ユーザーはこの列のこの値を制御できません。定数の名前は確かに曖昧です! (あなたはそれのために前のコード猿を責めることができます;私はこのプロジェクトで非常に多くの "奇妙な"を継承しました...) – Mathew

0

[OK]を、私は理解しておいてくださいするには、私は再び状態質問してみましょう:

次の2個の異なる特定のタグ(「猫」と「子猫」)を持っているすべての製品を表示しようとしているが、タグが格納されています1対多のテーブルに格納されます。

二重結合が作業を行いますが、ここでは別の代替です:

SELECT ... 
FROM P 
WHERE p.status = 1 
    AND p.ProductID IN (SELECT Product_ID FROM tags WHERE value = "cats") 
    AND p.ProductID IN (SELECT Product_ID FROM tags WHERE value = "kittens") 

ただ、オプションのユーザ選択に応じて、追加の追加と文。

SQLオプティマイザは実際にはジョインを扱うのと同じ方法でこれを処理する必要があるため、パフォーマンスはより悪くなります。のバージョンよりもパフォーマンスが向上するとは思われません。あなたのデータセットでテストする価値があることは確かです。

0

のAIR CODE

select 
    distinct p2c.product_id 
from '.TABLE_PRODUCT_TO_CATEGORY.' p2c 
    inner join '.TABLE_PRODUCT.'  p on p2c.product_id = p.id 
where 
    and p.status = 1 
    and 2 = (
     SELECT COUNT(1) 
     FROM '.TABLE_PRODUCT_TAG.' pt 
     INNER JOIN '.TABLE_TAG_TYPE.' tt ON pt.tag_type_id = tt.id 
     WHERE tt.id = '.PRODUCT_TAG_TYPE_FREE_TAG.' 
     AND pt.product_id = p.id /* edit */ 
     lower(pt.value) IN("cats", "kittens") 
) 
関連する問題