Datenbankabfrage Problem

Mauf

Aktives Mitglied
Hallo Community,

vielleicht kann mir hier jemand helfen, komm einfach nicht drauf wie ich die Mysql-Abfrage bei folgender Konstelation stellen soll:

Tabelle A: (hier sind Objekte gespeichert)

ID | Name
1 abc
2 cde
3 fgh
... ...

Tabelle B: (hier sind mögliche Eigenschaften der Objekte gespeichert)
ID | Name
1 blau
2 rund
3 gross
... ...

Tabelle C: (hier wird gespeichert welches Objekt welche Eigenschaft besitzt)
A_ID | B_ID
1 1
1 2
2 2
2 3
3 1
... ...

Nun würde ich gerne alle Objekte mit bestimmten Eigenschaften erhalten, d.h. ich habe ein Array mit den IDs der gewünschten Eigenschaften (z.B. [2, 3] -> gibt nur das Objekt mit ID 2 zurück, also ein rundes, großes Objekt)

Kann mir da jemand helfen? Wichtig wäre auch eine möglichst performante Abfrage, da es sich um Tausende Objekte, ca. 100 Eigenschaften und ca. 100.000 Verknüpfungen in Tabelle C handelt, Tendenz steigend.
 
Na Hallo, als ich würde jetzt die ganze Sache spontan so abfragen:

SELECT a.name
FROM TabA a, TabB b, TabC c
WHERE a.id=c.a_id AND c.b_id=b.id

Geht allerdings nicht bei mehreren Eigenschaften...ich denk da mal darüber nach...
 
Probiers damit:

Das Array zuerst mit asort() sortieren (und mit array_unique() die doppelten Einträge löschen) und dann mit implode(',',$array) zu einem String zusammensetzen.

GROUP_CONCAT(DISTINCT c.b_id ORDER BY c.b_id ASC SEPARATOR ',') macht genau dasselbe mit den Datensätzen.

CODE SELECT
 a.name
FROM
 tablea a,
 tablec c
WHERE
 GROUP_CONCAT(DISTINCT c.b_id ORDER BY c.b_id ASC SEPARATOR ',') = '$string' AND
 c.a_id = a.id
GROUP BY
 c.a_id


Ich habe keine Ahnung wie schnell oder langsam diese Abfrage ist. Aber ich hoffe, Du hast bei dieser Menge an Datensätzen die Indizes nicht vergessen.
 
Vielen Dank erstmal für die Antworten.

@Marcus: bei mir kommt da ein Syntaxfehler near: "( DISTINCT c . b_id ORDER BY c . b_id ASC SEPARATOR ',' ) ="
 
Kleine Korrektur:

CODE SELECT
a.name
FROM
tablea a,
tablec c
WHERE
c.a_id = a.id
GROUP BY
c.a_id
HAVING
GROUP_CONCAT(DISTINCT c.b_id ORDER BY c.b_id ASC SEPARATOR ',') = '$string'



GROUP-Funktionen haben ja eigentlich in der WHERE-Klausel nichts verloren
wink.gif


Nun zu Deiner Fehlermeldung. So wie es aussieht, kennt Dein MySQL diese GROUP-Funktion nicht.
 
Damit sollte es auch ohne ORDER_CONCAT funktionieren:

QUOTE SELECT
  a.name
FROM
  tablea a,
  (
   SELECT
     a_id
   FROM
     tablec
   WHERE
     b_id = '2' OR
     b_id = '3'
   GROUP BY
     a_id
   HAVING
     COUNT(*) = 'Anzahl Eigenschaften'
  )
  AS c
WHERE
  a.id = c.a_id 


Wie schnell das ganze ist, kann ich nicht sagen (OR ist nicht optimal für so eine Abfrage).
 
in der Form kommt bei mir auch ein Syntax-Fehler. Nach Umänderung scheint jedoch das falsche Ergebnis rauszukommen. OR ist in diesm Fall auch falsch, da nicht eine der Eigenschaften, sondern beide bzw. alle gesucht sind. Es kann sein dass 20 Eigenschaften übereinstimmen müssen nicht nur 2.
 
Wäre hilfreich, wenn Du den Fehler hier mitteilen könntest.

Das OR stimmt schon. Damit werden zuerst alle Eigenschaften einzeln ausgelesen. Mit GROUP und COUNT wird dann überprüft, bei welchem Objekt alle Eigenschaften vorhanden sind.
 
das ist der Fehler, wenn ich deine letzte Version nehme:
CODE #1064 - You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT b_id FROM tablec WHERE b_id = '2' OR
 
In dem Fall funktionieren Subselects bei Dir nicht. Was hast Du denn für eine MySQL-Version?

Wenn es gar nicht anders geht, musst Du die beiden Abfragen eben nacheinander ausführen:

CODE SELECT
 a_id
FROM
 tablec
WHERE
b_id = 'Eigenschaft 1' OR
b_id = 'Eigenschaft 2' OR
b_id = 'Eigenschaft 3' OR
b_id = 'Eigenschaft 4' OR
usw....
GROUP BY
 a_id
HAVING
 COUNT(*) = 'Anzahl Eigenschaften'


Und dann


CODE SELECT
 name
FROM
 tablea
WHERE
 id = 'Ergebnis aus der 1. Abfrage'
 
CODE
SELECT a.ID ObjektID, a.Name ObjektName, b.ID EigenschaftID, b.Name EigenschaftName
FROM (
  SELECT * FROM c WHERE B_ID IN(2,3) GROUP BY A_ID HAVING count(*)=2
) cfiltered
LEFT JOIN a ON a.ID=cfiltered.A_ID
LEFT JOIN c ON c.A_ID=a.ID
LEFT JOIN b ON b.ID=c.B_ID



sehr umständlich, aber so ginge das...

EDIT: Die Query sucht nach bestimmten Eigenschaften eines Objekts, aber liefert am Ende das Objekt mit ALLEN seiner Eigenschaften zurück... wenn man nur die Eigenschaften gelistet haben will, die man auch sucht muss man am Ende noch ein " WHERE c.B_ID IN(2,3)" was nicht optimal wäre, aber funktionieren müsste
 
ja sorry, ist Mysql 4.0, da gehen scheinbar keine subqueries.

CODE SELECT
a_id
FROM
tablec
WHERE
b_id = 'Eigenschaft 1' OR
b_id = 'Eigenschaft 2' OR
b_id = 'Eigenschaft 3' OR
b_id = 'Eigenschaft 4' OR
usw....
GROUP BY
a_id
HAVING
COUNT(*) = 'Anzahl Eigenschaften'


die IDs reichen vollkommen, die kann ich dann schon weiterverarbeiten. Hat super funktioniert! Müsste auch performant genug sein, da keine Joins verwendet werden.


@Maik: Danke dir auch. Das mit "Group by" und "Having" war das entscheidende, dann gehts auch ohne Joins. Die Namen der Eigenschaften werden natürlich nicht benötigt, die kennt man ja von der Anfrage her.
 
Die Mischung der beiden:

CODE SELECT a_id
FROM tablec
WHERE
b_id IN (2,3)
GROUP BY a_id
HAVING COUNT(*) = '2'
 
Zurück
Oben