3

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

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

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

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

やりたいことを実行する SQL クエリを作成するにはどうすればよいですか?

@ジェレミー・ルーテン、

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

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

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

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

4

6 に答える 6

4

与えられた:

  • オブジェクト テーブル (主キー ID)
  • objecttags テーブル (外部キー objectId、tagid)
  • タグ テーブル (主キー 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';
    

and が必要なため、これは逆のように見えますが、問題は、2 つのタグが同じ行にないことです。したがって、1 つの行が果物と食品の両方になることはできないため、and は何も生成しません。タグごとに各オブジェクトの 1 行を取得するため、通常、このクエリは重複を生成します。

この場合、実際に and を実行したい場合は、たとえば、クエリにgroup by, および aが必要になります。having 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;
于 2008-08-24T01:02:22.747 に答える
4

ああ、元のコメントを誤解している可能性があります。

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'
于 2008-08-24T01:07:37.227 に答える
0

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

SELECT object WHERE tag IN ('フルーツ', '食品');

クエリは、タグが果物と食品の両方である行を探していましたが、フィールドが同時に両方ではなく 1 つの値しか持てないため、これを確認することは不可能です。

于 2008-08-24T00:49:59.890 に答える
0

Steve M. の提案と Jeremy の提案を組み合わせると、探しているレコードが 1 つ得られます。

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

さて、それはあまりうまくスケーリングしませんが、探しているものを取得します. コードに大きな影響を与えずにN個の一致するアイテムを簡単に持つことができるように、これを行うためのより良い方法があると思いますが、現在それは私を逃れています。

于 2008-08-24T01:11:25.517 に答える
0

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

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')
于 2008-08-24T01:15:31.857 に答える
-2

次のように、テーブルにレコードごとに 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 %';
于 2008-08-24T00:17:39.483 に答える