質問

ウェブサイトにタグ付けシステムを実装しています。オブジェクトごとに複数のタグがあり、タグごとに複数のオブジェクトがあります。これは、レコードごとに2つの値を持つオブジェクトを保持することで実現されます。1つはオブジェクトのID用、もう1つはタグ用です。

特定のタグのセットに一致するオブジェクトを見つけるためのクエリを作成しようとしています。次のデータ([オブジェクト]-<!> gt; [タグ] *形式)があったとします

apple -> fruit red food
banana -> fruit yellow food
cheese -> yellow food
firetruck -> vehicle red

マッチさせたい場合(赤)、リンゴと消防車を手に入れる必要があります。 (果物、食べ物)を一致させたい場合は、(リンゴ、バナナ)を手に入れる必要があります。

SQLクエリを作成して、必要なことを行うにはどうすればよいですか

@Jeremy Ruten、

ご回答ありがとうございます。使用された表記は、サンプルデータを提供するために使用されました-データベースには、レコードごとに1つのオブジェクトIDと1つのタグを持つテーブルがあります。

第二に、私の問題は、すべてのタグに一致するすべてのオブジェクトを取得する必要があることです。 ORをANDに置き換えるには:

SELECT object WHERE tag = 'fruit' AND tag = 'food';

実行しても結果は得られません。

役に立ちましたか?

解決

指定:

  • オブジェクトテーブル(プライマリキーID)
  • objecttagsテーブル(外部キーobjectId、tagid)
  • tagsテーブル(プライマリキーID)

    SELECT distinct o.*
      from object o join objecttags ot on o.Id = ot.objectid
                    join tags t on ot.tagid = t.id
     where t.Name = 'fruit' or t.name = 'food';
    

これはあなたが望むので後方に思えますが、問題は2つのタグが同じ行になく、したがって、1つの行は果物でも食べ物でもないため、anとandは何も生成しません。 タグごとに各オブジェクトの1行を取得するため、このクエリは通常、重複を生成します。

実際に実行したい場合、この場合、たとえばクエリにgroup byhaving count = <number of ors>が必要になります。

  SELECT distinct o.name, count(*) as count
    from object o join objecttags ot on o.Id = ot.objectid
                  join tags t on ot.tagid = t.id
   where t.Name = 'fruit' or t.name = 'food'
group by o.name
  having count = 2;

他のヒント

おっと、元のコメントを誤って解釈した可能性があります。

SQLでこれを行う最も簡単な方法は、3つのテーブルを持つことです。

1) Tags ( tag_id, name )
2) Objects (whatever that is)
3) Object_Tag( tag_id, object_id )

その後、データに対して必要な事実上すべての質問を迅速、簡単、効率的に行うことができます(適切にインデックス付けされている場合)。おしゃれにしたい場合は、マルチワードタグも許可できます(エレガントな方法と、それほどエレガントではない方法が考えられます)。

これがあなたの持っているものだと思うので、以下のSQLは動作します:

文字通りの方法:

    SELECT obj 
      FROM object
     WHERE EXISTS( SELECT * 
                     FROM tags 
                    WHERE tag = 'fruit' 
                      AND oid = object_id ) 
       AND EXISTS( SELECT * 
                     FROM tags 
                    WHERE tag = 'Apple'
                      AND oid = object_id )

次のような他の方法もあります:

SELECT oid
  FROM tags
 WHERE tag = 'Apple'
INTERSECT
SELECT oid
  FROM tags
 WHERE tag = 'Fruit'

@Kyle:クエリは次のようになります。

SELECT object WHERE tag IN ('fruit', 'food');

クエリは、タグが果物と食品の両方である行を探していましたが、フィールドには同時に両方の値を含めることはできません。

スティーブMの提案とジェレミーの提案を組み合わせると、探しているものを含む単一のレコードが得られます。

select object
from tblTags
where tag = @firstMatch
and (
       @secondMatch is null 
       or 
       (object in (select object from tblTags where tag = @secondMatch)
     )

今、それはあまりうまくスケールしませんが、あなたが探しているものを手に入れるでしょう。コードに大きな影響を与えることなく、N個の一致するアイテムを簡単に取得できるように、これを実行するためのより良い方法があると思いますが、現在は私を免れています。

次のスキーマをお勧めします。

Objects: objectID, objectName
Tags: tagID, tagName
ObjectTag: objectID,tagID

次のクエリを使用します。

select distinct
    objectName
from
    ObjectTab ot
    join object o
        on o.objectID = ot.objectID
    join tabs t
        on t.tagID = ot.tagID
where
    tagName in ('red','fruit')

次のように、テーブルにレコードごとに1つのタグを付けることをお勧めします:

 apple -> fruit
 apple -> red
 apple -> food
 banana -> fruit
 banana -> yellow
 banana -> food

その後、あなただけで

 SELECT object WHERE tag = 'fruit' OR tag = 'food';

本当に自分のやり方でやりたい場合は、次のようにすることができます:

 SELECT object WHERE tag LIKE 'red' OR tag LIKE '% red' OR tag LIKE 'red %' OR tag LIKE '% red %';
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top