SQL-Abfrage bei Kategoriesuche

TribunM

Erfahrenes Mitglied
Hallo Freunde,

also ich bin dabei eine Suche mit Kategorien und der Anzeige der Anzahl der Ergebnisse pro Kategorie zu programmieren. Die steht auch und funktioniert soweit, allerdings frage ich mich, ob man das nicht eleganter lösen kann. Hier mein Aufbau:

1. SQL: Abfrage der Gesamtergebnisse der Oberkategorien
Action: 23
Komödie: 18

Das speicher ich in einem Array der ungefär so aussieht:
PHP:
$category[] 	=  array( "oberkategorie_id" 			=> $row['okat_id'], 
						"oberkategorie_name" 		=> $row['fkat_name'], 
						"oberkategorie_amount" 		=> $row['ukat_count'],
						 "unterkategorie"		                => $this->unterkategorie($row["okat_id"], $Suchtext)
	   	   				);

Dann eine neue funktion unterkategorie in der ich die passenden Unterkategorien in einem neuen Array ausgebe samt gefundener Ergebnisse. SIeht z.b. im Fall Musik etwa so aus:

SQL 2: mit Übergabe der ID der Oberkategorie (wird also pro gefundener Unterkategorie mit Ergebnisse ausgeführt)
- DVD 16
- Blue Ray 7


Das speicher ich dann wieder in einem Array der dem obigen ähnelt.

Wie gesagt das klappt alles und man erhält einen prima Baum mit den gewünschten Ergebnissen.
Also praktisch:

Action 23
- DVD 16
- Blue Ray 7

Aber gleichzeitig erzeugt das bei mehreren Treffern ziemlich viele SQL Abfragen. Logisch für jede gefundene Unterkategorie. Außerdem sind die SQL Anweisungen beide sehr ähnlich, was mich stört. Die erste ist praktisch nur ein weiterer Count der zweiten, um die Ergebnisse der Oberkategorien zu bekommen. Und die SQL ist wegen den vielen Filtern nicht gerade klein.

Nun meine Idee war nur eine, die zweite SQL zu nutzen. Allerdings wie kriege ich den Array dann so hin wie den oben? Denn so bekomme ich die Oberkategorie immer doppelt und die Anzahl der Unterkategorie.
Filme 16
- DVD 16

Filme 7
- Blue Ray 7

Die Gesamtanzahl könnte ich auch per php zählen, wobei das noch nicht so will. Vielleicht gibt es da auch eine Möglichkeit das in einer SQL zu lösen? Ich wußte nicht, ob das Thema mehr SQL ist oder PHP. Wenn es die falsche Sektion ist, bitte verschieben.

Über ein wenig Hilfe wäre ich sehr erfreut.

Schon einmal vielen Dank im voraus.
 
Zuletzt bearbeitet:
Sind das 2 verscheidene Tabellen? Oder ist es eine Tabelle?

Gib doch mal die Tabellenstruktur, dann finden wir schon was heraus.

Ps: MySQL?
Oder Oracle?
Oder MS SQL?
oder ....?
 
Ne das sind schon mehrere Tabellen, die ich verbinde. So sieht die erste SQL (mySQL) aus, welche die Anzahl der Ergebnisse in der Oberkategorie ausgibt. Die zweite für die Unterkategorie entsprechend ohne den obigen counter:

Sieht etwa so aus:

Code:
SELECT *, SUM(okat_count) FROM 
						(SELECT *, count(*) as ukat_count FROM 
							(SELECT result.*, fkat.name AS fkat_name FROM 
								(
								SELECT F.ID as film_id, F.kat_ID AS fkat_id, K.NAME as kat_name, okat.ID AS okat_id
								MATCH(F.TITEL) AGAINST('{$suche}' IN BOOLEAN MODE) AS Relevanz 
								FROM Filme AS F 
								LEFT JOIN Filmkategorien AS K ON (F.ID = K.ID) 
								WHERE MATCH(F.Titel) AGAINST('{$suche}' IN BOOLEAN MODE) 
								{$Filter}
								) as result
							LEFT JOIN Filmkategorien as fkat
								ON (result.okat_id = fkat.id)
							) as kat_rel
						group by fkat_id) as fkat_count
					group by okat_id

Ja ich weiß. Das lässt sich kürzen, aber darum geht es mir nicht. Es geht eben darum, dass diese Abfrage pro Unterkategorie nochmal ausgeführt wird und das ist auch in der gekürzten Fassung nicht wirklich performant.
 
Sorry, hab grad keine Lust aus einem Query eine Tabellenstruktur herauszulesen.

[Hochnäsigkeitmodus]Ich arbeite weiter wenn ich die Tabellenstruktur sehe[/Hochnäsigkeitmodus]
 
Ach soooooo das habe ich falsch verstanden ;)

Das sind die Tabellen mit Spalten:

Filme (ID, Titel, kat_ID)
Filmkategorien (ID, okat_ID, Name)

Hoffe das ist gemeint? Ich bin gerade am überlegen, wie ich das Ganze sortieren und FIltern kann und dann wiederum in einen neuen array ausgebe, der ähnlich aufgebaut ist zum letzten. Mit den Filtern der Oberkategorie mit array-unique klappt aber schonmal nicht wirklich.
 
Zuletzt bearbeitet:
Frage zu Kategorien.
okat_id ist die id der Oberkategorie die ebenfalls in der Tabelle Kategorienen liegt?

Und du hast MySQL? (Ist eine sehr wichtige Frage!)
 
Hi yaslaw,

erst einmal danke für deine schnellen Antworten.
Ja ich habe die ID der Oberkategorie mit in die Tabelle geschrieben. Ist für den Aufbau im "Adminpanel". Ich benutze mySQL richtig. Das steht aber auch in einem oberen Post.
 
Ich liebe solche Herausforderungen *g*

Ich habe ein SQL erstellt, dass die folgenden Felder beinhaltet
Code:
kat_id						# Id der Kategorie
tree_level					# Level der Kategorie (Haubtkategorien = Level 1)
name						# Name der Kategorie
count_film_rekursive		# Anzahl Filme in der Kategorie total = [count_film_from_children]+[count_film_only_this_kat]
count_film_from_children	# Anzahl Filme aus den Unterkategorien
count_film_only_this_kat	# Anzahl Filme nur aus dieser Kategorie

Und hier das herzige SQL *g*
SQL:
SELECT
	pid AS kat_id,
	tree_levels.tree_level,
	kat.name,	
	sum(count_film) AS count_film_rekursive,
	sum(IF(pid <> dat.id, count_film, 0)) AS count_film_from_children,
	sum(IF(pid <> dat.id, 0, count_film)) AS count_film_only_this_kat
FROM 
	(
	SELECT
	        tree.id,
	        tree.pid,
	        film.count_film
	FROM
	    (
		SELECT  
	        @rownum := @rownum+1 AS rownum,
	        mylist.id AS id,
	        IF(@lastl <> mylist.id, @id := mylist.id, @id) AS pid,
	        @lastl := mylist.id AS setVarLast,
	        @id := (SELECT okat_id FROM kategorien  WHERE id = @id) AS okat_id
	    FROM
	        (SELECT @id := 0, @lastl := 0, @rownum := 0) AS vars,
	        (SELECT id FROM kategorien) AS myloop,
	        (SELECT id FROM kategorien) AS mylist  
		HAVING pid IS NOT NULL
	    ) AS tree
	    LEFT JOIN (SELECT kat_id, COUNT(id) AS count_film FROM filme GROUP BY kat_id) AS film
	    	ON tree.id = film.kat_id
	) AS dat
	INNER JOIN (SELECT id, okat_id, name FROM kategorien) AS kat
		ON kat.id = dat.pid
	INNER JOIN (SELECT
					id, 
					count(*) AS tree_level
				FROM
					(
					SELECT  
				        mylist.id AS id,
				        IF(@lastl <> mylist.id, @id := mylist.id, @id) AS pid,
				        @lastl := mylist.id AS setVarLast,
				        @id := (SELECT okat_id FROM kategorien  WHERE id = @id) AS okat_id
				    FROM
				        (SELECT @id := 0, @lastl := 0) AS vars,
				        (SELECT id FROM kategorien) AS myloop,
				        (SELECT id FROM kategorien) AS mylist
					HAVING pid IS NOT NULL
					) AS d
				GROUP BY id
				) AS tree_levels
		ON dat.pid = tree_levels.id
GROUP BY dat.pid, tree_levels.tree_level

Viel Spass....
 
Zuletzt bearbeitet von einem Moderator:
wow und ich dachte ich kann halbwegs SQL. Aber schön, dass man immer wieder was dazulernen kann.

Es wäre außerdem sehr nett, wenn du mir diesen SELECT ein wenig erklären könntest. Ich finde dazu auch nix in den mysql docs.
Zumindest das @ und := sind mir nicht geläufig:

SQL:
SELECT  
            @rownum := @rownum+1 AS rownum,
            mylist.id AS id,
            IF(@lastl <> mylist.id, @id := mylist.id, @id) AS pid,
            @lastl := mylist.id AS setVarLast,
            @id := (SELECT okat_id FROM kategorien  WHERE id = @id) AS okat_id
        FROM
            (SELECT @id := 0, @lastl := 0, @rownum := 0) AS vars,
            (SELECT id FROM kategorien) AS myloop,
            (SELECT id FROM kategorien) AS mylist  
        HAVING pid IS NOT NULL
        ) AS tree

Was ich bemerkt habe ist, dass es doch sehr lange dauert, bis die Abfrage durch ist. Sind ja auch relativ viele Kategorien und Datensätze. Der SQL ist auch schon zweimal abgestürzt. Kann das daran liegen? Muss man da etwas umstellen, damit das schneller geht oder ist das einfach so?

Ansonsten klappt es perfekt.

Vielen Dank
 
Zuletzt bearbeitet von einem Moderator:
Dieses SQL ist fast zwangsläufig langsam, da es zwei mal alle Kategoriene mit allen Kategorien mischt und dauerns Variablen neu schreibt...
Ich persönlich würde das nicht direkt so lösen sondern mit mehreren SQLs arbeiten.
Es hat mir mehr Spass gemacht um es hinzukriegen als dass es Sinnvoll währe *g*

Zu den @variable := value
Das läuft unter dem Begriff "Benutzerdefinierte Variablen"
http://dev.mysql.com/doc/refman/5.1/de/user-variables.html
 
Zurück