Frage

Ich bin ein Tagging-System für eine Website zu implementieren. Es gibt mehrere Tags pro Objekt und mehr Objekte pro Tag. Dies wird erreicht, indem Sie eine Tabelle mit zwei Werten pro Datensatz beibehalten wird, eine für die Iden des Objekts und dem Tag.

Ich suche eine Abfrage zu schreiben, um die Objekte zu finden, die einen bestimmten Satz von Tags entsprechen. Angenommen, ich hatte die folgenden Daten (in [object] -> [tags] * Format)

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

Wenn ich (rot) übereinstimmen soll, sollte ich Apfel und Feuerwehrauto bekommen. Wenn ich will (Obst, Lebensmittel) entsprechen soll ich (Apfel, Banane).

Wie kann ich eine SQL-Abfrage schreiben Sie das tun, was ich will?

@ Jeremy Ruten,

Vielen Dank für Ihre Antwort. Die Notation verwendet wurde verwendet, um einige Beispieldaten zu geben -. Meine Datenbank eine Tabelle mit 1 Objekt-ID und 1 Tag pro Datensatz hat

Zweitens, mein Problem ist, dass ich alle Objekte erhalten müssen, die alle Tags entsprechen. Setzen Sie dabei OR für eine UND etwa so:

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

Die Renditen keine Ergebnisse bei der Ausführung.

War es hilfreich?

Lösung

Gegeben:

  • Objekttabelle (Primärschlüssel id)
  • objecttags Tabelle (Fremdschlüssel objectId, MarkierungslD)
  • -Tags Tabelle (Primärschlüssel 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';
    

Dies scheint nach hinten, da Sie wollen und, aber das Problem ist, 2-Tags sind nicht in der gleichen Zeile, und daher ein und liefert nichts, da 1 einreihig nicht sowohl eine Frucht und ein Lebensmittel sein kann. Diese Abfrage wird Duplikate in der Regel ergeben, da Sie 1 Zeile jedes Objekt erhalten wird, pro Tag.

Wenn Sie wollen wirklich eine tun und in diesem Fall erhalten Sie eine group by benötigen, und eine having count = <number of ors> in Ihrer Abfrage zum Beispiel.

  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;

Andere Tipps

Oh Gott kann ich Ihre ursprünglichen Kommentar-mis interpretiert.

Der einfachste Weg, dies in SQL zu tun wäre, um drei Tabellen zu haben:

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

Dann können Sie praktisch jede Frage stellen Sie die Daten wollen einfach schnell und effizient (Sie Index in angemessener Weise zur Verfügung gestellt). Wenn Sie Lust bekommen möchten, können Sie Multi-Wort-Tags können auch (es gibt eine elegante Art und Weise, und eine weniger elegante Art und Weise, kann ich mir vorstellen).

Ich gehe davon aus, dass das, was du hast, so dass diese SQL wird im folgenden arbeiten:

Die wörtliche Weise:

    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 )

Es gibt auch andere Möglichkeiten, wie Sie es tun können, wie zum Beispiel:

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

@ Kyle: Ihre Abfrage sollte wie:

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

Ihre Anfrage wurde für die Zeilen, wo der Tag sowohl Obst und das Essen war, das als das Feld nicht möglich ist, zu sehen, nur einen Wert haben kann, nicht beide gleichzeitig.

Kombinieren Steve M. Vorschlag mit Jeremys Sie einen einzelnen Datensatz bekommen mit, was Sie suchen:

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

Nun, das nicht sehr gut skalieren, aber es wird bekommen, was Sie suchen. Ich denke, dass es einen besseren Weg, dies zu gehen zu tun, so können Sie leicht N Anzahl passender Artikel ohne viel Einfluss auf den Code haben, aber es entgeht mir zur Zeit.

Ich empfehle das folgende Schema.

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

Mit der folgenden Abfrage.

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')

Ich würde Tisch haben 1 Tag pro Datensatz schlagen vor, wie folgt aus:

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

Dann konnte man nur

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

Wenn Sie es wirklich Ihre Art und Weise zu tun, wollen aber Sie es wie folgt tun könnte:

 SELECT object WHERE tag LIKE 'red' OR tag LIKE '% red' OR tag LIKE 'red %' OR tag LIKE '% red %';
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top