Dustin: Komplexe MySQL Abfrage

Hallo,

ich habe 3 MySQL Tabellen:

clips_user_in_group (id, groupid, userid) clips_groups (id, name, clip_limit, clip_length) clips_users (id, clip_limit, clip_length)

Kurz vorweg: Baue grad was auf, wo Users Clips hochladen können. Für jeden User kann man Limits setzen und für jede Gruppe. Ein User kann in mehreren Gruppen gleichzeitig sein!

Brauche nun eine Abfrage, die mir die besten Werte für ein User zurückgibt. Immer das größere soll genommen werden. Beispiel: Ein User ist in 2 Gruppen.

Gruppe A hat ein clip_limit von 1 und clip_length von 1000 Gruppe B: clip_limit 3 und clip_length 2000.

Dann soll er clip_limit 3 nehmen und clip_length 2000.

Keine Ahnung ob das überhaupt möglich ist, kann mir wer da Helfen?

Gruß

  1. Tach!

    Brauche nun eine Abfrage, die mir die besten Werte für ein User zurückgibt. Immer das größere soll genommen werden.

    Der Trick ist bei solchen komplexen Aufgabenstellung, selbige in kleine handhabbare Einzelheiten herunterzubrechen. Diese Teilaufgaben kann man dann auch wunderschön einzeln testen ohne dass irgendwelche Nebenwirkungen großer komplexer Abläufe stören.

    Erstelle zunächst einzelne Abfragen, die dir die jeweiligen Höchstwerte pro Tabelle liefern. Für die User-Gruppen wäre das ein SELECT * auf alle Datensätze, in denen der User Gruppenmitglied ist. Wenn das die richtigen Datensätze liefert, tauschst du den * gegen MAX() für limit und length aus.

    Die Abfrage auf clips_users ist noch etwas einfacher, da da kein MAX() benötigt wird. Es sei denn, da gibt es auch mehrere Datensätze pro User.

    Diese Teil-Querys kannst du mit UNION zusammenfassen. Die Union-Query kann als Subquery in eine FROM-Klausel und in dieser Query kannst du mit SELECT MAX() die Höchstwerte finden.

    Alternativ kannst du die zwei Querys allein laufen lassen und ermittelst den Höchstwert im PHP-Teil.

    dedlfix.

    1. Lieber dedlfix,

      da da kein MAX() benötigt wird.

      da da da SCNR

      Liebe Grüße,

      Felix Riesterer.

    2. Danke Dir! Habe erfolgreich was geschafft.

      Allerdings etwas anders, aber ist nur eine kleine Funktion geworden und läuft super.

      Gruß

      1. Hallo Dustin,

        Danke Dir! Habe erfolgreich was geschafft.

        Allerdings etwas anders, aber ist nur eine kleine Funktion geworden und läuft super.

        Magst du das vielleicht zeigen, damit die Nachwelt auch was davon hat?

        Bis demnächst
        Matthias

        --
        Rosen sind rot.
        1. Klar, sorry das ich jetzt erst schreibe.

          function getUserSettings($userid)
          {
          	$settings = [];
          
          	$settings["clip_length"] = -1;
          	$settings["clip_limit"] = -1;
          	$settings["wait_for_admin"] = -1;
          	$settings["play_other_clips"] = -1;
          
          	$sql = "SELECT `clip_length`,`clip_limit`,`wait_for_admin`,`play_other_clips` FROM `clips_groups` 
          	JOIN `clips_user_in_group` ON clips_user_in_group.userid='".$userid."' WHERE clips_groups.id=clips_user_in_group.groupid 
          	UNION SELECT `clip_length`,`clip_limit`,`wait_for_admin`,`play_other_clips` FROM `clips_users` WHERE id='".$userid."'";
          	$result = mysql_query($sql);
          
          	while ($row = mysql_fetch_assoc($result)) 
          	{ 
          		$field = array_keys($row);
          		for($i = 0; $i < sizeof($field); $i++)
          		{
          			if ($settings[$field[$i]] < $row[$field[$i]])
          			{
          				$settings[$field[$i]] = $row[$field[$i]];
          			}
          		}
          	}
          
          	/*Als JSON zurückgeben*/
          	$settings = json_encode($settings);
          	$out = json_decode($settings);
          
          	return $out;
          }
          

          Habe das so gelöst, wenn ich MAX() verwende bekomme ich ja trotzdem 2 Ergebnisse Zurück einmal von der Gruppe und von User. Daher habe ich das komplett weg gelassen.

          1. Hallo Dustin,

            danke, dass Du deinen Code vorstellst. Ich hätte ein paar Verbesserungsvorschläge für Dich.

            Punkt 1: mysql ist deprecated, nimm mysqli oder PDO.

            Punkt 2: Die User-ID hast Du hoffentlich vor Aufruf der Funktion gesäubert, sonst injiziert Dir damit noch jemand irgendwelchen Müll. Mit mysqli kannst Du Parameter an SQL-Platzhalter binden, dann übernimmt das API die Absicherung für Dich.

            Punkt 3: Du kannst auf die Schleife verzichten. Ein SELECT Statement erwartet in der FROM Klausel nicht Tabellen, sondern Tabellenausdrücke. Ein Tabellenausdruck kann eine einfache Table sein, ein JOIN, oder ein SELECT. Dieser weitere Select braucht lediglich einen Aliasnamen, sonst meckert der Server. Und soweit ich weiß, darf der innere Select kein ORDER BY haben, sortiert wird immer nur am Ende. GROUP BY und HAVING sind im inneren Select kein Problem.

            Abstraktes Beispiel:

            SELECT MAX(X.a), MAX(X.b), MAX(X.c), MAX(X.d)
            FROM (SELECT a,b,c,d FROM tabA JOIN tabB on tabA.x=tabB.y WHEREUNION
                  SELECT a,b,c,d FROM tabC WHERE) X
            

            Die Spaltennamen und -typen werden vom ersten SELECT einer UNION Gruppe festgelegt. Wenn Du andere festlegen willst (oder musst, weil Du einen Ausdruck in der SELECT Liste hast), vergebe im ersten SELECT Aliasnamen (SELECT xyz AS q, ...).

            Rolf

            1. Wird vorher gesäubert!

              Ich probiere es mal zu ändern. Danke.

    3. Kann man hier als Alternative auch einen View benutzen?

      Grüße

      1. Tach!

        Kann man hier als Alternative auch einen View benutzen?

        Kann man. Die Frage ist nur, ob es sich für den gegebenen Anwendungsfall lohnt, da noch eine View drumherum zu bauen. Die Querys als solche müssen ja trotzdem formuliert werden.

        dedlfix.