SQL Objekt nach Tags auswählen

Penman

Lieutenant
Registriert
Feb. 2009
Beiträge
751
Ich hoffe, ich kann mein Problem verständlich beschreiben.
Also es geht um Folgendes:

Ich schreibe mir derzeit ein Programm, mit dem es mir möglich ist eine MySQL Datenbank nach Bildern anzuzapfen. Das ganze soll mit einem Tag System funktionieren, was heißt, dass ich Bilder finden kann indem ich sagen kann, was unbedingt in dem Bild sein soll und was auf keinen Fall in dem Bild sein soll.
Diese Tags sind beispielsweise Strand, Wald, Himmel, Sonne, Wolken, Personen usw.

Das ganze System besteht erst mal aus 3 Tabellen: Bilder, Tags und Bildertags.
Es sollte jedem sofort ins Auge springen, dass in Bildertags zu jedem Bild mehrere Tags reihenweise gespeichert werden können.
Ein Beispiel noch

Bilder [ID, Name, Ordner, Dateiname]
233, Sonnenuntergang, 510, dawn-123.jpg
244, Sonnenuntergang am Strand, 511, beachdawn.jpf

Tags [ID, Name]
5, Sonne
15, Sonnenuntergang
18, Strand

Bildertags [BildId, TagId]
233, 5
233, 15
244, 5
244, 15
244, 18

So nun zur Frage:
Wie bekomme ich es hin, dass ich z.B. nur nach Sonne und Sonnenuntergang suchen will und Strand dabei ausschließe?

Ich zerbreche mir derzeit den Kopf über WHERE x = y und IN(), aber es gibt einfach keine Lösung, da man scheinbar nur über Reihen hinweg abfragen kann.

Hat irgendwer einen Lösungsansatz für mich?
 
join der tabellen bilder und tags hast du ja scheinbar schon (Bildertags).

jetzt einfach SELECT * FROM Bildertags WHERE TagId = 5 AND TagId = 15

oder sind da meine laienhaften kenntnisse falsch?
 
Das reicht ja eben nicht. Wäre es so einfach, hätte ich nicht gefragt.
Das würde ein Bild wieder einbeziehen, sobald ein Tag wieder zutrifft. Man muss ja die Auswahl irgendwie gruppiert treffen oder so und alle Tags auf einmal durchsuchen und prüfen.
 
SELECT *
FROM bilder AS b
INNER JOIN tags ON b AS t
INNER JOIN bildertags ON b AS bt
WHERE bt.TagId <> 18

(kein gewähr)

vllt versteh ich das problem grad nicht so ganz, aber wenn du einen bestimmten wert nich willst, einfach mit <> ausschliessen. alternativ einfach im WHERE nur die TagIds mit AND = explizit auswählen.
 
Du verzichtest auf das in und fragst jeden Parameter mit einer Subquery einzeln ab. Das sieht dann etwa so aus:

Code:
SELECT * from Bilder WHERE
ID IN (SELECT BildId FROM Bildertags WHERE TagID=5) AND
ID IN (SELECT BildId FROM Bildertags WHERE TagID=15) AND
ID NOT IN (SELECT BildId FROM Bildertags WHERE TagID=18);

Damit kannst du beliebig komplexe Abfragen machen, hab ich in ner ähnlichen Anwendung auch gemacht

Den Kram generierst du natürlich dann im PHP oder wo du das abfragst.
Und lass diese bescheuerte Groß/Kleinschreibung, das gibt nur Probleme.


@thes33k:
Das funktioniert nicht, sobald du ne zweite Abfrage reinpackst kommen bei dir immer 0 Sätze raus weil bt.TagId immer genau einen Wert hat.
 
Zuletzt bearbeitet:
Wunderbar, Blutstrumpf, nach ein wenig rumprobieren und testen betrachte ich die Lösung als richtig für meinen Zweck.
Besten Dank
 
Hallo Penman,
durch mehre Unterabfragen wird die Abfrage bei großen Datenbanken sehr schnell langsam.
Statt mit Zahlen zu suchen die kein Anwender kennt, kann so per Suchbegriff gefiltert werden:
PHP:
Select Bilder.*
FROM Bildertags
INNER JOIN Bilder
		ON Bildertags.BildId = Bilder.Id
INNER JOIN Tags
		ON Bildertags.TagId = Tags.ID
WHERE Bilder.Name LIKE '%Sonne%'
AND Bilder.Name NOT LIKE '%Strand%'

Falls mehre konkrete Worte ein/ausgelossen werden sollen, kann auch diese Bedingung genutzt werden:
PHP:
WHERE Bilder.Name IN ('Sonne', 'Sonnenuntergang')
AND Bilder.Name NOT IN ('Strand')
Kombinationen sind selbstverständlich ebenfalls möglich.
 
Zuletzt bearbeitet:
Das klappt bei ner m:n Beziehung nicht, die Vorgehensweise ist ja im Endeffekt mit dem von thes33k identisch.

Der User wird ja nicht nach ner ID suchen, der bkommt ein Dropdown oder ne Checkbox über die die ID zugeordnet wird.
 
Sicher funktioniert dies auch bei n:m Beziehungen!
Wie geschrieben sind Kombinationen möglich.
Für den konkreten Fall:
PHP:
WHERE Bilder.Name LIKE ('%Sonne%') 
AND Bilder.Name NOT IN ('Strand')
im Select-Teil sollte noch "SELECT DISTINCT" stehen, damit Zeilen nur einmalig ausgegeben werden.
Die Abfrage von thes33k ist ein unfertiges (selbst Spalten fehlen in der "ON"-Verknüpfung) "Etwas".

Wo bitte hat Penman geschrieben, den Benutzer mit Dropdown/Checkbox-Auswahl einschränken zu wollen?
Schonmal daran gedacht, dass hier Freitextfelder viel praktischer sind?
So müssen Werte nicht unnötigerweise vorher aufgebaut und
der Benutzer keine ewig langen Listen durchforsten.
 
Zuletzt bearbeitet:
Filter mal nach 2 Tags die beide gesetzt sein müssen und einem der nicht gesetzt sein darf. Dann wirst du sehen, dass es nicht funktioniert.

Du suchst übrigens nach Bilder.Name, er möchte nach den Tags suchen.
Sprich an der Aufgabenstellung haust du eh komplett vorbei.

Wo bitte hat Penman geschrieben, den Benutzer mit Dropdown/Checkbox-Auswahl einschränken zu wollen?
Das war ein Beispiel wie man es machen müsste. Natürlich kann er auch nach Freitext oder nem Dtring im Tagnamen suchen, das hat aber mit der Problemstellung absolut nichts zu tun.
 
Zurück
Oben