Zum Inhalt springen

ID-Listen abfragen

Erstellt am 17. Juli 2008 · 15 Antworten · letzte Antwort am 18. Juli 2008

Tags: Datenbank, Frage

TheRisingSun ·

Hallo!

Ich habe die zwei DB-Tabellen artikel und kategorie, die miteinander verknüpft sind. In der Tabelle artikel gibt es ein Feld Namens kategorie, welches die IDs der Tabelle kategorie in einer kommaseparierte Liste aufnimmt.

Meine Frage ist jetzt wie ich es am Besten anstelle, wenn ich einen bestimmten Artikel suche, der eine bestimmte ID in seinem Feld kategorie hat.

Ich bin SQL-Starter und kenne bislang nur die LIKE- und MATCH-AGAINST-Abfrage-Kommandos. Für letztere muss ich allerdings die minimale Wortlänge für die Volltextsuche (ft min word len) auf 1 setzen und die LIKE-Variante erfordert zur eindeutigen Bestimmung 4 Wiederholungen (kategorie LIKE 'ZAHL' OR kategorie LIKE '%,ZAHL' ('ZAHL,%' und '%,ZAHL,%')).

Gibt es noch andere Möglichkeiten für 1:n-Relationen?

MfG Rising

TheRisingSun ·

Naja es ist doch ein String aus kommaseparierten IDs, beispielsweise 3,1,12,43,5.
Wenn ich so (kategorie = 3) abfrage, bekomme ich doch gar kein Ergebnis.

Rising

digedag ·
TheRisingSun schrieb

(kategorie LIKE 'ZAHL' OR kategorie LIKE '%,ZAHL' ('ZAHL,%' und '%,ZAHL,%')).

Gibt es noch andere Möglichkeiten für 1:n-Relationen?

Ja gibt es! 🙂 Du kannst z.B. dafür die MySQL-Funktion FIND_IN_SET verwenden:

$sql = 'SELECT artikel.* FROM artikel WHERE FIND_IN_SET(' . $kategorieUID . ', artikel.kategorie);'
TheRisingSun ·

Danke für den Tipp digedag aber mit FIND IN SET bekomme ich bei der Suche nach beispielsweise einer 2 auch Ergebnis die eine 21, 22 oder 12 enthalten. Also keine eindeutige Bestimmung!

digedag ·

Dann machst du aber irgendetwas falsch. 😉

SELECT *
FROM `artikel`
WHERE FIND_IN_SET( '2', kategorie )

Das findet nur Artikel, wo wirklich eine 2 drin steht. Die Funktion FIND_IN_SET wäre sonst auch absolut nutzlos, weil sie sich ja wie ein LIKE verhalten würde.

Ich hab's auch grad nochmal mit deinem Beispiel "21,22,12" ausprobiert. Dieser Datensatz wird mit obiger Abfrage nicht gefunden.

TheRisingSun ·

Hmmm ich habe es über phpmyadmin ausprobiert und ich erhielt alle Datensätze in denen der Wert irgendwie vorkam. Ich werde es nochmal probieren und dann berichten. Danke jedenfalls für Deine Antwort!!!!

TheRisingSun ·

LOL! Ich glaube Du hast wirklich Recht!!! Habs gerade nochma probiert und es ging wie ich es mir vorgestellt habe bzw. wie Du es versprochen hattest.

Schon merkwürdig, weil ichs gestern mehrmals anders erlebt habe. Muss wohl wirklich was verkehrt gemacht haben.

THX! Jetzt komme ich um die 4 LIKE-Varianten herum.

Gibt es zu FIND_IN_SET eigentlich Benchmarks im Vergleich zu LIKE oder MATCH ..AGAINST was Geschwindigkeit betrifft?

steffenk ·

kleine Korrektur

FIND_IN_SET( '2', kategorie )>0

sonst gibts auch ein Ergebnis wenn 2 nicht vorkommt.

TheRisingSun ·

Das konnte ich bei mir nicht nachvollziehen. Kann man FIND_IN_SET und COUNT(*) zusammen benutzen.

SELECT artikel.uid, short, category
FROM artikel
WHERE pid IN (33)
AND artikel.deleted=0
AND artikel.t3ver_state!=1
AND artikel.hidden=0
AND (artikel.starttime<=1216383478-)
AND (artikel.endtime=0 OR artikel.endtime>1216383478-)
AND FIND_IN_SET ('3', category)

geht bei mir aber

SELECT COUNT(*)
FROM artikel
WHERE pid IN (33)
AND artikel.deleted=0
AND artikel.t3ver_state!=1
AND artikel.hidden=0
AND (artikel.starttime<=1216383478-)
AND (artikel.endtime=0 OR artikel.endtime>1216383478-)
AND FIND_IN_SET ('3', category)

funktioniert nicht. Warum?

digedag ·

Beide Statements sollten eigentlich funktionieren. Bekommst du eine Fehlermeldung oder einfach 0 beim count() als Ergebnis? Wenn du ne alte MySQL-Version hast, kann es vielleicht auch daran liegen...
Probier auch mal count(uid) anstatt von count(*). Man weiß ja nie. 😉

TheRisingSun ·

Also es ist wirklich zum verzweifeln!

Dies hier geht in phpmyadmin:

SELECT artikel.*
FROM artikel
WHERE pid
IN ( 33 )
AND artikel.deleted =0
AND artikel.t3ver_state !=1
AND artikel.hidden =0
AND (
artikel.starttime <=1216390539
)
AND (
artikel.endtime =0
OR artikel.endtime >1216390539
)
AND (
FIND_IN_SET( '3', artikel.category )
OR FIND_IN_SET( '1', artikel.category )
OR FIND_IN_SET( '2', artikel.category )
OR FIND_IN_SET( '4', artikel.category )
)
GROUP BY uid
ORDER BY artikel.starttime DESC

=====================================
und dies hier nicht
(Fehlermeldung in phpmyadmin: #1305 - FUNCTION t3_testcmsdb.FIND_IN_SET does not exist):

SELECT artikel.*
FROM artikel
WHERE pid
IN ( 33 )
AND artikel.deleted =0
AND artikel.t3ver_state !=1
AND artikel.hidden =0
AND (
artikel.starttime <=1216390539
)
AND (
artikel.endtime =0
OR artikel.endtime >1216390539
)
AND (
FIND_IN_SET( '3', artikel.category )
OR FIND_IN_SET( '1', artikel.category )
OR FIND_IN_SET( '2', artikel.category )
OR FIND_IN_SET( '4', artikel.category )
)
GROUP BY uid
ORDER BY artikel.starttime DESC
LIMIT 0 , 3

phpymadmin setzt dann ein eigenes LIMIT und zeigt ein valides Ergebnis.
Auch mit COUNT(*) funktioniert die obere Abfrage!

Hat jemand ne Idee?

digedag ·

Also zu den pi_...-Funktionen kann ich dir nichts hilfreiches sagen. Die verwende ich nicht. Aber mit den Methoden aus t3lib_DB funktioniert FIND_IN_SET auf jeden Fall. Kann aber sein, daß sich das Statement bei aktivierten DBAL verschluckt.

Warum setzt du in deinem Statement eigentlich ein GROUP BY? Wenn du in deiner Abfragemenge keine Summenfunktionen verwendest, dann ist das überflüssig. Falls du doppelte Ergebnisse vermeiden willst, dann wäre ein DISTINCT besser geeignet. Aber bei dieser Abfrage ohne JOIN auf andere Tabellen sollten keine Datensätze doppelt angezeigt werden.

Ansonsten hilft hier nur probieren. Fange mit einer einfachen Abfrage an und erweitere sie schrittweise, damit du erstmal das Problem genau lokalisierst. LIMIT und FIND_IN_SET funktionieren aber normalerweise miteinander.
Ach und mach das erstmal im phpMyAdmin. Bevor es dort nicht klappt, brauchst du dir um deinen PHP-Code keine Gedanken zu machen. 🙂

TheRisingSun ·

Erstmal Danke für die rege Unterstützung.

Das GROUP BY habe ich aus der MySQL-Doku. Hatte anfänglich vermutet, dass es damit zutun haben könnte. Ich habe auch die t3lib_DB-Funktionen (exec_Selectqurey()) versucht aber damit auch nichts erreichen können.
DBAL ist auch nicht aktiv. Naja ich schaue mal. Jetzt muss ich erstmal die LIKE-Varianten in Kauf nehmen.