j4nk3y: MySQL data type

Salve!

Ich hätte da gern nochmal eine allgemeine Frage zu MySQL. In meinen ganzen Tabellen mit denen Ich arbeite stehen Daten mit den unterschiedlichsten Typen wie, Intenger, Floats, Strings... etc. Was ich heute, ich glaub nicht zum ersten mal, bemerkt habe ist nun folgendes, dass Intenger und Floats, ich glaube, ausschließlich als String in meinen Arrays landen.
Iin PHP hatte ich bisher, anscheinend, keine Probleme auch mit Strings zu rechnen, jedenfalls ist es mir nicht aufgefallen, nun habe ich heute viel mit Javascript gemacht, mit Daten mit denen ich Serverseitig (noch) nicht gerechnet habe.
Und Javascript gibt anscheinend gern NaN aus wenn man versucht mit Strings zu rechnen. Daher die Frage: wie bekomme ich schon im MySQL Statement den Korrekten Daten Typ?

Danke Euch. Gruß
Jo

akzeptierte Antworten

  1. Hallo und guten Abend,

    Du könntest die Informationen von der Datenbank z. B. mit

    show columns from <tablename>;

    abfragen.

    Liebe Grüße
    TS

    --
    es wachse der Freifunk
    http://freifunk-oberharz.de
  2. Tach!

    Und Javascript gibt anscheinend gern NaN aus wenn man versucht mit Strings zu rechnen.

    Ein weiterer Punkt ist auch noch, dass Javascript ja nicht direkt mit MySQL spricht, sondern da auch noch eine Übertragung von PHP zum Browser stattfindet. Auch da musst du berücksichtigen, wie die Daten formatiert sind. Wenn sie in JSON eingepackt sind, dann sollten sie bereits auf der Serverseite korrekt als Zahl und nicht als String eingepackt werden, damit sie korrekt als Number angelegt werden können, wenn das JSON geparst wird. Wenn es hingegen eine andere auf String basierende Übertragung ist, dann musst du selbst dafür sorgen, dass du das als Number geparst bekommst.

    PHP hat keine solchen Probleme wie Javascript, weil es durch die unterschiedlichen Operatoren einen Rechenoperationswunsch von einem Stringverkettungswunsch unterscheiden kann. Javascript hat für beide Fälle ja nur das +. Abgesehen davon ist PHP generell toleranter und versucht mehr als Javascript zu erraten, was gemeint ist.

    Daher die Frage: wie bekomme ich schon im MySQL Statement den Korrekten Daten Typ?

    Das Statement ist noch nicht die richtige Stelle zum Ansetzen. Da gibt es nichts, um den gewünschten Datentyp anzugeben, wenn du nicht gerade was generelles umgestaltet haben möchtest, wie beispielsweise einen Date-Time-Wert in einen Unix-Timestamp. Erst das Lesen der Ergebnismenge ist der Punkt, an dem man anzusetzen versuchen kann. Ich würde dazu in die Dokumentation der verwendeten Fetch-Funktionen schauen, ob da was zum Datentyp geschrieben wird und/oder ob es andere Funktionen gibt, die das genauer zurückgeben. Wenn es da nichts gibt, ein einfacher Typecast in PHP zu int oder float sollte genügen. Wenn nicht gerade NULL-Werte zurückkommen können, sorgt ja schon der Spaltentyp dafür, dass nur gültige Zahlenwerte gespeichert sein können, und somit auch nur solche in der Ergebnismenge landen (wenn sie ohne weitere Berechnungen abgefragt werden).

    dedlfix.

    1. Hey,

      Ein weiterer Punkt ist auch noch, dass Javascript ja nicht direkt mit MySQL spricht, sondern da auch noch eine Übertragung von PHP zum Browser stattfindet. Auch da musst du berücksichtigen, wie die Daten formatiert sind. Wenn sie in JSON eingepackt sind,[...]

      Das ist der Fall.

      [...] dann sollten sie bereits auf der Serverseite korrekt als Zahl und nicht als String eingepackt werden,[...]

      Darauf zielte die Frage ab, vllt etwas unglücklich und drum herum kommuniziert.

      PHP hat keine solchen Probleme wie Javascript, weil es durch die unterschiedlichen Operatoren einen Rechenoperationswunsch von einem Stringverkettungswunsch unterscheiden kann. Javascript hat für beide Fälle ja nur das +.

      Stimmt , daran hab ich garnicht gedacht.

      Das Statement ist noch nicht die richtige Stelle zum Ansetzen. Da gibt es nichts, um den gewünschten Datentyp anzugeben,[...]

      Habe ich mir fast gedacht.

      Erst das Lesen der Ergebnismenge ist der Punkt, an dem man anzusetzen versuchen kann. Ich würde dazu in die Dokumentation der verwendeten Fetch-Funktionen schauen, ob da was zum Datentyp geschrieben wird und/oder ob es andere Funktionen gibt, die das genauer zurückgeben.[...]

      Kurzes nachschauen, ergab kein Erfolg zum Datentyp.

      Wenn es da nichts gibt, ein einfacher Typecast in PHP zu int oder float sollte genügen.

      Also Ergebnissmenge in einer Schleife laufen lassen und jeden wirklichen Zahlenwert mit intval() und floatval() beackern?

      [...], sorgt ja schon der Spaltentyp dafür, dass nur gültige Zahlenwerte gespeichert sein können, und somit auch nur solche in der Ergebnismenge landen (wenn sie ohne weitere Berechnungen abgefragt werden).

      Das sollte so sein.

      Ich muss mich eh nochmal an meine Datenbankabfrage ran setzen, da das bis jetzt einzelne Statments sind, dies mit Joins/Unions jedoch wesentlich performanter sein sollte. Da kann ich mich gleich auch an die "typisierung" ran machen.

      Danke Schön!

      Gruß
      Jo

      1. Tach!

        Erst das Lesen der Ergebnismenge ist der Punkt, an dem man anzusetzen versuchen kann. Ich würde dazu in die Dokumentation der verwendeten Fetch-Funktionen schauen, ob da was zum Datentyp geschrieben wird und/oder ob es andere Funktionen gibt, die das genauer zurückgeben.[...]

        Kurzes nachschauen, ergab kein Erfolg zum Datentyp.

        Nun, abgesehen davon, dass ich bei PHP nachgeschlagen hätte, aber die Seite bei MySQL sieht auf den ersten Blick inhaltlich gleich aus. Der entscheidende Punkt ist da die Aussage "Returns an associative array of strings ...". Damit dürfte schon recht viel gesagt sein, wenn da nicht noch was anderes steht, was nicht der Fall zu sein scheint.

        Wenn es da nichts gibt, ein einfacher Typecast in PHP zu int oder float sollte genügen.

        Also Ergebnissmenge in einer Schleife laufen lassen und jeden wirklichen Zahlenwert mit intval() und floatval() beackern?

        Na, schauen wir mal beim Nachbarn rein. Es gibt da ja auch noch Prepared Statements und das Binding der Ergebnismengeninhalte an Variablen, sprich: mysqli_stmt::bind_result(). "Depending on column types bound variables can silently change to the corresponding PHP type." Das liest sich doch schon eher so, als ob das zielführend ist.

        Nun wollte ich auch noch die Handbuchseite zu Prepared Statements verlinken, und was sehen meine altersschwachen Augen da in Example #5? "Native Datatypes" als Überschrift, Typangaben im Ergebnis und im Erläuterungstext "This behavior differs from non-prepared statements. By default, non-prepared statements return all results as strings." Mit anderen Worten, ein Result-Binding ist nicht notwendig, es muss nur das Statement als prepared abgeschickt werden und man kann dann recht herkömmlich fetchen und bekommt ordentliche Datentypen.

        dedlfix.

        1. Guten morgen,

          Na, schauen wir mal beim Nachbarn rein. Es gibt da ja auch noch Prepared Statements und das Binding der Ergebnismengeninhalte an Variablen, sprich: mysqli_stmt::bind_result(). "Depending on column types bound variables can silently change to the corresponding PHP type." Das liest sich doch schon eher so, als ob das zielführend ist.

          Nun wollte ich auch noch die Handbuchseite zu Prepared Statements verlinken, und was sehen meine altersschwachen Augen da in Example #5? "Native Datatypes" als Überschrift, Typangaben im Ergebnis und im Erläuterungstext "This behavior differs from non-prepared statements. By default, non-prepared statements return all results as strings." Mit anderen Worten, ein Result-Binding ist nicht notwendig, es muss nur das Statement als prepared abgeschickt werden und man kann dann recht herkömmlich fetchen und bekommt ordentliche Datentypen.

          Vielen danke, dass hab ich damals als ich damit angefangen hab noch nicht verstanden aber jetzt macht es Sinn. Nun denn ans Werk.

          Gruß
          Jo

      2. Hallo und guten Tag,

        Wenn es da nichts gibt, ein einfacher Typecast in PHP zu int oder float sollte genügen.

        Also Ergebnissmenge in einer Schleife laufen lassen und jeden wirklichen Zahlenwert mit intval() und floatval() beackern?

        Dafür schreibst Du dir eine Funktion. Hol dir z. B. die Spaltenbeschreibung (wie bereits angedeutet) am Anfang des Vorganges und wende dann die Typen auf die Ergebniszeilen an.

        Für PHP benötigst Du das allerdings meistens nicht. Nur für die Weiterverarbeitung Richtung Frontend (z. B passenden HTML-Input-Type und -Format) oder andere Programmschnittstellen kann es relevant sein. Und für den Rückweg von PHP in die Datenbank kann man die Information des Typs selbstverständlich für das Escaping nutzen.

        Liebe Grüße
        TS

        --
        es wachse der Freifunk
        http://freifunk-oberharz.de
  3. Hey,

    So mal ein wenig gearbeitet und es tritt das erste Problem auf, welches ich zwar verstehe aber keine Möglichkeit sehe, dies zu beheben.

    Ich hab jetzt folgendes Statment:

    $get_data = $db->prepare(sprintf(
    	"Select 
    		%1$s.sid, %1$s.x, %1$s.y, %1$s.z,
    		%2$s.pid, %2$s.ppos, %2$s.pclass,
    		%3$s.h, %3$s.he, %3$s.c, %3$s.n, %3$s.o, %3$s.si, %3$s.ti, %3$s.fe,
    		%4$s.mid, %4$s.mpos, %4$s.mclass,
    		%5$s.h, %5$s.he, %5$s.c, %5$s.n, %5$s.o, %5$s.si, %5$s.ti, %5$s.fe
    	From %1$s
    	Left JOIN %2$s ON %1$s.sid = %2$s.sid
    	Left JOIN %3$s ON %1$s.sid = %3$s.sid
    	Left JOIN %4$s ON %2$s.pid = %4$s.pid
    	Left JOIN %5$s ON %2$s.pid = %5$s.pid
    	", mysqli_real_escape_string($db, $_SESSION['gid']."_s"), 
             mysqli_real_escape_string($db, $_SESSION['gid']."_pinfo"), 
             mysqli_real_escape_string($db, $_SESSION['gid']."_presource"),
             mysqli_real_escape_string($db, $_SESSION['gid']."_minfo"), 
             mysqli_real_escape_string($db, $_SESSION['gid']."_mresource")));
    	$get_data->execute();
    	$result = $get_data->get_result();
    	$data['gdata']['s'] = $result->fetch_assoc();
    

    Dazu nochmal kurz dargestellt wie die Tabellen aussehen:

    s:

    | sid | x | y | z |
    | 1 | 2 | 4 | 2 |
    | 2 | 4 | 5 | 1 |

    pinfo:

    | pid | sid |...
    | 1 | 2 |...
    | ... | ... |...

    presource:

    | pid | sid |...
    | 1 | 2 |...
    | ... | ... |...

    mresource:

    | mid | pid |...
    | 1 | 2 |...
    | ... | ... |...

    mresource:

    | mid | pid |...
    | 1 | 2 |...
    | ... | ... |...

    Logischerweise, meckert PHP bei der Verknüpfung $s.* und sagt das er die Variable nicht kennt.

    Und ich erhalte Fatal error: Call to a member function execute() on a non-object in W:\htdocs\html\... on line 2738. Und zu allem überfluss bekomme ich auch noch Warning: sprintf(): Too few arguments in W:\htdocs\html\... on line 2738.
    Also grad etwas zum Haare raufen aber was mach ich nur falsch?

    Gruß
    Jo

    1. Tach!

      Logischerweise, meckert PHP bei der Verknüpfung $s.* und sagt das er die Variable nicht kennt.

      Meine Vorgehensweise ist, dass ich Strings generell in ' einrahme, und nur dann " nehme, wenn die zusätzlichen Eigenschaften wie Variablenersetzung und Escape-Sequenzen (wie \r, \n) benötigt werden.

      dedlfix.

      1. Hey,

        Meine Vorgehensweise ist, dass ich Strings generell in ' einrahme, und nur dann " nehme, wenn die zusätzlichen Eigenschaften wie Variablenersetzung und Escape-Sequenzen (wie \r, \n) benötigt werden.

        Interessant, das löst schon mal das erste und das dritte Problem. Zweiters wird gelöst wenn man die spalten namen richtig schreibt!

        Danke dir dedflix!

        Gruß
        Jo

  4. Hello again,

    Nächstes bescheuertes Problem: in Tabelle 2 und 4 sowie 3 und 5 haben die Spalten denselben Namen, nun funktioniert das mit dem LEFT JOIN nicht so wie ich erwartet hätte. Das ein Array an Daten aus der Haupttabelle erstellt wird und dann für jede "gejointe" Tabelle, wenn denn nicht NULL zurück kommt, ein Array innerhalb des Arrays erzeugt wird in welches die Daten der "gejointen" Tabelle geschrieben werden.

    Es kommt aber ein Array aus dem Query der die Reihe der zuletzt gejointen Tabelle beinhaltet, was logischerweise beim fetch_assoc() dazu führt, dass die Werte aus Tabelle 2 respektive 3, mit den Werten aus 4 bzw. 5 überschrieben werden.

    Kann ich irgendwie schon im Query mein Array sortieren?

    Vorher hatte ich es so, dass ich für die Haupttabelle eine Abfrage gestellt habe und dann über die Ergebnismenge iteriert habe und für jede Iteration eine Anfrage an die nächste Tabelle gestellt habe um das Ergebnis eben in ein Array zu schreiben wo die Daten dann geordnet waren. Geordnet im Sinne von

    
    [s] = Array(
      [$sid]= Array(
        [p]=Array(
          [$pid] = Array([h]=xyz,[he]=xyz,...,[m]=Array([$mid]=Array([h]=xyz,[he]=xyz,...)),
          [$pid] = Array([h]=xyz,[he]=xyz,...,[m]=Array([$mid]=Array([h]=xyz,[he]=xyz,...)),
          [data]=xyz,...),
        [p]=Array(
          [$pid] = Array([h]=xyz,[he]=xyz,...,[m]=Array([$mid]=Array([h]=xyz,[he]=xyz,...)),
          [data]=xyz,...)
    ,...)
    

    Da das eben nicht besonders performant und eben zu viele Anfragen an die DB gestellt werden, muss ich das überarbeiten. Problem ist eben nur, das schon der Query ein "falsches" Ergebnis liefert.

    Gruß
    Jo

    1. Tach!

      nun funktioniert das mit dem LEFT JOIN nicht so wie ich erwartet hätte.

      Meine Mepfehlung: Leg erstmal alle Erwartungen an Joins beiseite und schau dir an, wie Joins generell funktionieren.

      Das ein Array an Daten aus der Haupttabelle erstellt wird und dann für jede "gejointe" Tabelle, wenn denn nicht NULL zurück kommt, ein Array innerhalb des Arrays erzeugt wird in welches die Daten der "gejointen" Tabelle geschrieben werden.

      Arrays spielen für das DBMS keine Rolle. Bleib erstmal im DBMS. Die Ergebnismenge einer Query sieht immer tabellenförmig, also Zeilen mit Werten, und keinesfalls wie eine Baumstruktur. (Das Wort Menge kommt übrigens nicht nur zufällig so oft vor. So ein DBMS arbeitet mengenorientiert.)

      Bei einem Join entsteht eine Datenmenge mit X mal Y Datensätzen. Jeder Datensatz der Tabelle X wird mit jedem Datensatz der Tabelle Y verknüpft. Das nennt sich kartesisches Produkt (von Descaretes, nicht von Karthago). Diese Menge wird durch die Art des Joins eingeschränkt, sowie durch Joinbedingungen und generelle Datensatzausschlussbedingungen (WHERE und HAVING).

      Wenn du diese flache Datenstruktur lieber als Baum oder verschachtelte Arrays hättest, musst du sie nach dem Abfragen selbst in eine solche Form bringen. Wenn die Datensätze nach X sortiert sind, kannst du mit der Gruppenwechseltechnik arbeiten. Wenn die X-Werte gleich bleiben, bist du immer noch im selben X-Datensatz, wenn sie sich ändern, hast du eine neue Gruppe. Wenn X unsortiert ist, kannst und musst du für jeden Datensatz der Ergebnismenge anhand der X-Werte die passende Stelle im Ziel-Array suchen.

      Es kommt aber ein Array aus dem Query der die Reihe der zuletzt gejointen Tabelle beinhaltet, was logischerweise beim fetch_assoc() dazu führt, dass die Werte aus Tabelle 2 respektive 3, mit den Werten aus 4 bzw. 5 überschrieben werden.

      Aliasnamen für uneindeutige Spaltennamen helfen.

      Kann ich irgendwie schon im Query mein Array sortieren?

      Dein Array nicht, aber die Ergebnismenge kann selbstverständlich sortiert werden: ORDER BY. Nur zusammenfassen kannst du die Datensätze nicht innerhalb des DBMS.

      Vorher hatte ich es so, dass ich für die Haupttabelle eine Abfrage gestellt habe und dann über die Ergebnismenge iteriert habe und für jede Iteration eine Anfrage an die nächste Tabelle gestellt habe um das Ergebnis eben in ein Array zu schreiben wo die Daten dann geordnet waren.

      Für kleine Datenmengen durchaus nicht unzweckmäßig. Je nach Situation kann das eine oder das andere für dich oder für das DBMS Mehraufwand bedeuten. Es ist eine Abwägungssache, was man dann letzlich nimmt.

      Problem ist eben nur, das schon der Query ein "falsches" Ergebnis liefert.

      Abgesehen von eindeutigen Ergebnismenge-Spaltennamen durch Aliase wirst du kein anderes Ergebnis aus einer Query bekommen.

      dedlfix.

      1. Hallo und guten Tag,

        Vorher hatte ich es so, dass ich für die Haupttabelle eine Abfrage gestellt habe und dann über die Ergebnismenge iteriert habe und für jede Iteration eine Anfrage an die nächste Tabelle gestellt habe um das Ergebnis eben in ein Array zu schreiben wo die Daten dann geordnet waren.

        Für kleine Datenmengen durchaus nicht unzweckmäßig. Je nach Situation kann das eine oder das andere für dich oder für das DBMS Mehraufwand bedeuten. Es ist eine Abwägungssache, was man dann letzlich nimmt.

        Das führt in bewegten Datenbeständen aber regelmäßig zu schweren Fehlern (TOCTTOU, Integrität ), wenn man nicht total intelligente Maßnahmen™ dagegen unternimmt (gravierender Einfluss auf das Datenmodell), bzw. alle betroffenen Tabellen solange sperrt. [...]

        Liebe Grüße
        TS

        --
        es wachse der Freifunk
        http://freifunk-oberharz.de
      2. Hey,

        Die Ergebnismenge einer Query sieht immer tabellenförmig, also Zeilen mit Werten, und keinesfalls wie eine Baumstruktur.

        Soweit verstanden. Vor allem in Bezug auf das Ergebnis welches ich erhalte.

        Aliasnamen für uneindeutige Spaltennamen helfen.

        Wo dann aber der Aliasnamen im Assoziativen Array landen würden?

        Für kleine Datenmengen durchaus nicht unzweckmäßig. Je nach Situation kann das eine oder das andere für dich oder für das DBMS Mehraufwand bedeuten. Es ist eine Abwägungssache, was man dann letzlich nimmt.

        Ich glaub von kleinen Datenmengen kann leider nicht mehr die rede sein. Die Menge an Reihen multipliziert sich mit etwa 5 für jede "gejointe" Tabelle. (z.B. 200 Einträge in der Haupttabelle, 1000 Einträge in dazu gejointen und 5000 in der zur zweit gejointen Tabelle. Und 200 Einträge sind noch wenig und imo Standart um das System zu entwickeln, geplant sind dann mehrere tausend / zehntausend Einträge in der Haupttabelle.)

        Das Problem was ich gerade habe ist, wie mache ich aus einer Reihe die alle Werte aus der Haupttabelle, 1te gejointe und 2t gejointe Tabelle, ein Array welches dem entspricht welches ich vorher hatte, gerne ohne jede Reihe zu prüfen wo welcher Wert aus der Reihe (da ja auch Werte in der Reihe stehen die logisch in eine andere Dimension des Arrays gehören) hin kommt.

        Was zusätzlich verwirrend ist, wenn in der 1t/2t gejointen Tabelle kein Datensatz zur ID der Haupttabelle ist, landet ein leerer Eintrag im $result->fetch_assoc() und nicht nichts. Da müsste ich dann auch für jedes Element prüfen ob ein Wert enthalten ist oder diesen Eintrag löschen.

        Naja ich probiere mich mal.

        Gruß
        Jo

        1. Tach!

          Aliasnamen für uneindeutige Spaltennamen helfen.

          Wo dann aber der Aliasnamen im Assoziativen Array landen würden?

          Der ersetzt den Spaltennamen aus der Tabelle. Oder die Formel, wenn es ein berechnetes Feld ist.

          Ich glaub von kleinen Datenmengen kann leider nicht mehr die rede sein. Die Menge an Reihen multipliziert sich mit etwa 5 für jede "gejointe" Tabelle. (z.B. 200 Einträge in der Haupttabelle, 1000 Einträge in dazu gejointen und 5000 in der zur zweit gejointen Tabelle. Und 200 Einträge sind noch wenig und imo Standart um das System zu entwickeln, geplant sind dann mehrere tausend / zehntausend Einträge in der Haupttabelle.)

          Naja, das sind noch nicht unbedingt Mengen, bei denen das DBMS ins Schwitzen kommt.

          Das Problem was ich gerade habe ist, wie mache ich aus einer Reihe die alle Werte aus der Haupttabelle, 1te gejointe und 2t gejointe Tabelle, ein Array welches dem entspricht welches ich vorher hatte, gerne ohne jede Reihe zu prüfen wo welcher Wert aus der Reihe (da ja auch Werte in der Reihe stehen die logisch in eine andere Dimension des Arrays gehören) hin kommt.

          Erwähnte ich doch, sortierte Menge: Gruppenwechsel, unsortierte Menge: Position im Zielarray suchen. Ausgehend von der Haupt-Query, deren Daten durch den Join mehrfach in der Ergebnismenge stehen.

          Was zusätzlich verwirrend ist, wenn in der 1t/2t gejointen Tabelle kein Datensatz zur ID der Haupttabelle ist, landet ein leerer Eintrag im $result->fetch_assoc() und nicht nichts. Da müsste ich dann auch für jedes Element prüfen ob ein Wert enthalten ist oder diesen Eintrag löschen.

          Dann möchtest du vielleicht keinen OUTER JOIN (enthält LEFT und RIGHT), denn ein solcher liefert immer mindestens einen Datensatz für die Haupttabelle - mit NULL-Werten für die Spalten der gejointen Tabelle.

          dedlfix.

          1. Hey,

            Dann möchtest du vielleicht keinen OUTER JOIN (enthält LEFT und RIGHT), denn ein solcher liefert immer mindestens einen Datensatz für die Haupttabelle - mit NULL-Werten für die Spalten der gejointen Tabelle.

            Doch die Daten der Haupttabelle brauch ich ja auch. Ein print_r($row) liefert nur irgendwas der Art Array([1]=>[2]=>), wenn ein Eintrag nicht vorhanden ist. Ein isset() liefert dann aber False für den Eintrag 1, das ist schonmal gut.

            Ich Danke dir übrigens ganz herzlich, dass du dich so um meine Problemchen kümmerst :-)

            Gruß
            Jo

        2. Mensch ist das wieder kompliziert...

          In jeder Reihe muss ich prüfen ob Werte in der ersten und zweiten gejointen Tabelle vorhanden sind, sprich if(isset($key)).

          Je nach Fall, sind ja erstmal nur 3, Alle Werte aus $row in mein gewünschtes Array schreiben. Für jeden Wert einzeln? Etwa:

          $sid = $row['sid'];
          $data[$sid]['x'] = $row['x'];
          $data[$sid]['y'] = $row['y'];
          .  
          $pid = $row['pid']; 
          $data[$sid][$pid]['h'] = $row['h'];  
          .  
          .
          

          Und es gibt wieder keine generelle Möglichkeit die Daten zu separieren?

          Wie macht man das Professionel? Also ein Mehrdimensionales Array aus einem MySQL Statment mit Joins. und zwar so, das man im nachhinein Spalten entfernen oder hinzufügen kann.

          Gruß
          Jo

          1. Tach!

            Wie macht man das Professionel? Also ein Mehrdimensionales Array aus einem MySQL Statment mit Joins.

            Auch nicht anders. Man kann dazu aber ORM-Tools nehmen, die einem die Arbeit abnehmen.

            dedlfix.

            1. Hey,

              Danke dir, dass müsste aber einen großen Aufand bedeuten alles auf das ORM anzupassen.

              Hab jetzt folgenden Ansatz, noch ungetestet, aber die logik müsste schon fast passen.

              while ($row = $result->fetch_assoc())
              {
              	$sid = $row['sid'];
              	if(isset($row['pid']))
              	{
              		$pid = $row['pid'];
              	}
              	if(isset($row['mid']))
              	{
              		$mid = $row['mid'];
              	}	
              	$s = TRUE;
              	$p = FALSE;
              	$m = FALSE;
              	foreach($row => $key as $value)
              	{
              		if($key === "pid")
              		{
              			$s = FALSE;
              			$p = TRUE;
              			$m = FALSE;
              		}
              		if($key === "mid")
              		{
              			$s = FALSE;
              			$p = FALSE;
              			$m = TRUE;
              		}
              		if($s === TRUE)
              		{
              			$data[$sid][$key] = $value;
              		}
              		if($p === TRUE)
              		{
              			$data[$sid][$pid][$key] = $value;
              		}
              		if($m === TRUE)
              		{
              			$data[$sid][$pid][$mid][$key] = $value;
              		}
              	}
              }
              

              Also eine Iteration bis zu einem gewissen $key und speichern der $values in der entsprechenden Dimension des Arrays.

              Oder?

              Gruß
              Jo

              P.S. Ich find es unschön :/ aber erstmal ausprobieren...

  5. Hey,

    Und HA... da hab ich doch gleich noch etwas verstanden... Und hab eine Frage dazu.

    Wenn ich sagen wir mal 3 Tabellen habe, in der Haupttabelle ist ein Eintrag und in den beiden anderen, die per Join hinzugefügt werden sind 10 Einträge.

    Dann ist ja die Ergebnismenge 100 Zeilen lang, wegen 10101.

    Kann man das durch geschicktes joinen verhindern?

    Gruß
    Jo

    1. Tach!

      Wenn ich sagen wir mal 3 Tabellen habe, in der Haupttabelle ist ein Eintrag und in den beiden anderen, die per Join hinzugefügt werden sind 10 Einträge.

      Dann ist ja die Ergebnismenge 100 Zeilen lang, wegen 10*10*1.

      Kann man das durch geschicktes joinen verhindern?

      Ja, aber was genau willst du erreichen? Beim Joinen kannst du eine Join-Bedingung angeben, so dass nicht jeder mit jedem, sondern nur bestimmte miteinander verbunden werden. Du kannst außerdem eine allgemeine Where-Bedingung angeben, die die Menge weiter einschränkt.

      Am besten du schaust dir mal unsere Join-Tutorials an.

      dedlfix.

      1. Hey,

        Ja, hab ich schon des öfteren rein geschaut. Aber ich verstehe nicht wie ich in das Kreuzprodukt noch weitere reglementierungen einbauen kann.

        Sagen wir ich hab Folgende Tabellen: a.

        |uid|pid|
        | 1 | 1 | | 2 | 3 |

        b.

        |pid|...|
        | 1 |...| | 1 |...| | 1 |...| | 1 |...| | 1 |...| | 2 |...| | 2 |...| | 2 |...| | 2 |...| | 2 |...|

        c.

        |pid|...|
        | 1 |...| | 1 |...| | 1 |...| | 1 |...| | 1 |...| | 2 |...| | 2 |...| | 2 |...| | 2 |...| | 2 |...|

        Und mein Select sieht dann etwa so aus:

        Select * FROM a LEFT JOIN b ON a.pid = b.pid LEFT JOIN c ON a.pid = c.pid WHERE uid = 1
        

        Das sind dann 25 Zeilen in der Ergebnismenge. Brauchen tue ich aber effektiv nur 10.

        Gruß
        Jo

        1. Tach!

          Das sind dann 25 Zeilen in der Ergebnismenge. Brauchen tue ich aber effektiv nur 10.

          Dann mach mal schrittweise, Erst a und b joinen. Was kommt raus? Eine Menge von 5 Datensätzen. Und wenn du dann c hinzujoinst, entsteht ein kartesisches Produkt, weil es keine Joinbedingung zwischen b und c gibt. Ergo 5 × 5 = 25.

          dedlfix.

          1. Hey,

            Dann mach mal schrittweise, Erst a und b joinen. Was kommt raus? Eine Menge von 5 Datensätzen. Und wenn du dann c hinzujoinst, entsteht ein kartesisches Produkt, weil es keine Joinbedingung zwischen b und c gibt. Ergo 5 × 5 = 25.

            Das sage ich ja ;) Aber wie verhinder ich das?

            Wie bekomme ich die von dir Angesprochene Bedingung in das Statement.

            Select * FROM a LEFT JOIN b ON a.pid = b.pid LEFT JOIN c ON a.pid = c.pid AND b.pid = c.pid WHERE uid = 1

            Gruß
            Jo

            1. Tach!

              Wie bekomme ich die von dir Angesprochene Bedingung in das Statement.

              Dazu musst du sie erstmal die Regel dazu formulieren. Welcher Datensatz aus b soll mit welchem aus c verknüpft werden?

              dedlfix.

              1. Hey,

                Dazu musst du sie erstmal die Regel dazu formulieren. Welcher Datensatz aus b soll mit welchem aus c verknüpft werden?

                Ich habe ja nur 1 Wert der in allen 3 Tabellen gleich ist, und die Verknüpfung liefert. Ich bekomme es gerade nicht hin die Logik aus einer komplexeren Anweisung zu filtern. Also bei 3 oder mehr Tabellen.

                Moment... ich Groschen gefallen:

                SELECT * FROM (a INNER JOIN (b INNER JOIN c ON b.id = c.id) ON a.id = b.id)

                Ich glaub das ists...

                Gruß
                Jo

                1. Tach!

                  Ich habe ja nur 1 Wert der in allen 3 Tabellen gleich ist, und die Verknüpfung liefert. Ich bekomme es gerade nicht hin die Logik aus einer komplexeren Anweisung zu filtern. Also bei 3 oder mehr Tabellen.

                  Versuch die Regel erstmal in normalsprachlichen Worten zu verfassen. Was soll passieren, was darf nicht passieren, gibt es Ausnahmen?

                  Moment... ich Groschen gefallen:

                  SELECT * FROM (a INNER JOIN (b INNER JOIN c ON b.id = c.id) ON a.id = b.id)

                  Na, wenns passt, ist ja alles gut.

                  dedlfix.

                  1. Hey,

                    Moment... ich Groschen gefallen:

                    SELECT * FROM (a INNER JOIN (b INNER JOIN c ON b.id = c.id) ON a.id = b.id)

                    Na, wenns passt, ist ja alles gut.

                    Ne :-D MySQL Syntax Fehler in Zeile 1...

                    Versuch die Regel erstmal in normalsprachlichen Worten zu verfassen. Was soll passieren, was darf nicht passieren, gibt es Ausnahmen?

                    Szenario 1 ( noch von Heute morgen ):

                    Drei Tabellen, alle Daten der Haupttabelle sollen in der Ausgabe auftreten, zu jedem Datensatz der Haupttabelle, gibt es 0-12 Einträge der 2ten Tabelle und zu jedem Eintrag der 2ten gibt es 0-xy Einträge in Tabelle 3. Haupttabelle und 2te sind über $sid verknüpft, 2te und 3te über $pid.

                    Szenario 2:

                    5 Tabellen, Hauptabelle hat 0-xy Einträge pro Nutzer, Tabellen 2 und 3 haben pro Haupttabellen Eintrag einen Eintrag, Tabellen 4 und 5 haben pro Hauptabellen Eintrag 21 Einträge. (Was 441 Iterationen ergibt, weshalb ich erst darauf gekommen bin). Alle Tabellen über $pid verknüpft.

                    Im Szenario 1 werden es dann noch mehr Iterationen sein. (derzeitig 200 * 1000 * 5000 später gut und gern 10.000 * 50.000 * 250.000)

                    Gruß
                    Jo

                    1. Edit:

                      Im Szenario 1 werden es dann noch mehr Iterationen sein. (derzeitig 200 * 1000 * 5000 später gut und gern 10.000 * 50.000 * 250.000)

                      Blödsinn... ist mir gerade auf dem Heimweg aufgefallen. Die Anzahl der Iterationen ist die Summe über die Produkte der Einträge aus t1, t2 und t3. Weil diese über unterschiedliche ID's verknüpft sind.

                      Gruß
                      Jo

                    2. Tach!

                      Versuch die Regel erstmal in normalsprachlichen Worten zu verfassen. Was soll passieren, was darf nicht passieren, gibt es Ausnahmen?

                      Szenario 1 ( noch von Heute morgen ):

                      Drei Tabellen, alle Daten der Haupttabelle sollen in der Ausgabe auftreten, zu jedem Datensatz der Haupttabelle, gibt es 0-12 Einträge der 2ten Tabelle und zu jedem Eintrag der 2ten gibt es 0-xy Einträge in Tabelle 3. Haupttabelle und 2te sind über $sid verknüpft, 2te und 3te über $pid.

                      Ich wollte dein Augenmerk mehr auf die Verknüpfungsbedingungen lenken, nicht so sehr auf die allgemeine Beschreibung der Aufgabenstellung. Aber gut, die liest sich eher einfach, so nach dem Motto eins-drei-viele, wie bei einem Baum seinen Ästen und deren Blätter. Da entsteht eigentlich nicht mehr als notwendig, wenn man so einen Baum flachklopft, also die Blätter und dazu stets der Stamm und der eine Ast zwischen den beiden.

                      Szenario 2:

                      5 Tabellen, Hauptabelle hat 0-xy Einträge pro Nutzer, Tabellen 2 und 3 haben pro Haupttabellen Eintrag einen Eintrag, Tabellen 4 und 5 haben pro Hauptabellen Eintrag 21 Einträge. (Was 441 Iterationen ergibt, weshalb ich erst darauf gekommen bin). Alle Tabellen über $pid verknüpft.

                      Es scheint, es gibt keine Beziehung zwischen Tabelle 4 und 5. Dann ist es vermutlich auch nicht sinnvoll die Datenmenge zu vereinigen und sich mit einem kartesischen Produkt rumzuschlagen, das man gar nicht haben möchte.

                      Man muss ja nicht unbedingt für jeden Datensatz der Haupttabelle eine eigene Abfrage starten. Es gibt da ja auch Operatoren wie IN(), in dem man die IDs der Haupttabelle auflistet, die man in deren Ergebnismenge findet. Oder man gibt die Bedingung der Hauptquery auch bei den Folgequerys an und hat dann auch genau die zur Hauptquery passenden Datensätze. Die Verknüpfung muss man dann nach oder während des Fetchens der Ergebnismenge selbst herstellen. Das ist aber nicht unbedingt mehr Aufwand, als man durch einen Gruppenwechsel-Mechanismus im anderen Fall hätte. Das ist womöglich sogar performanter als wenn das DBMS sich mit einem Join abmühen muss und dabei jede Menge redundante Daten der mehr oder weniger kartesich vervielfachten Hauptquery-Datensätze entstehen.

                      Es gibt übrigens auch noch Alternativen zu Joins, jedenfalls in einigen Fällen. Wenn man von der einen Tabelle nur einen einzelnen Feldinhalt pro Datensatz der anderen Tabelle haben möchte, dann kann man da mit Correlated Subquerys arbeiten. Das erspart einem die Kopfschmerzen, die so ein Join bereitet, und man kann beide Teilquerys sehr schön separat testen. Wenn allerdings mehr als ein Feld benötigt wird, müsste man eine weitere korrelierte Unterabfrage für dieses erstellen, und dann fängt es an, sich nicht mehr gegenüber einem Join zu lohnen.

                      dedlfix.

                      1. Hey,

                        Da entsteht eigentlich nicht mehr als notwendig, wenn man so einen Baum flachklopft, also die Blätter und dazu stets der Stamm und der eine Ast zwischen den beiden.

                        Genau das ist mir aufgefallen, Ergebnismenge = Summe der Produkte der Einträge.

                        Es scheint, es gibt keine Beziehung zwischen Tabelle 4 und 5. Dann ist es vermutlich auch nicht sinnvoll die Datenmenge zu vereinigen und sich mit einem kartesischen Produkt rumzuschlagen, das man gar nicht haben möchte.

                        Naja 1-5 haben alle eine Spalte in der die pid steht. Wahrscheinlich ist das gerade nicht sinnvoll und mein Denkfehler. Weil es eben, um bei deinem Beispiel zu bleiben, ein Baum mit 5 Stämmen ist.

                        Man muss ja nicht unbedingt für jeden Datensatz der Haupttabelle eine eigene Abfrage starten. Es gibt da ja auch Operatoren wie IN(), [...]

                        Das werde ich mir morgen mal Ansehen!

                        Vielen Dank Dedflix! Für deine Anregungen und Lösungen!

                        Gruß
                        Jo

  6. Hey,

    Was soll denn das bedeuten?

    der Join tatsächlich nötig ist und nicht aus reiner Bequemlichkeit einer zweiten Abfrage vorgezogen wird

    Aus der Einführung der Joins unter Abschließende Bemerkungen.

    Soll das heißen ein Join ist schlechter als:

    Select * FROM a WHERE id = 1
    // Eine Ergebnismenge von 10 Zeilen oder 10.000 Zeilen
    while($row...){
       Select * FROM b WHERE id = $row['**']
    }
    

    Gruß
    Jo

    1. Hallo j4nk3y,

      Soll das heißen ein Join ist schlechter als:

      Select * FROM a WHERE id = 1
      // Eine Ergebnismenge von 10 Zeilen oder 10.000 Zeilen
      while($row...){
         Select * FROM b WHERE id = $row['**']
      }
      

      Nein. Ein solches Konstrukt ist zu vermeiden.

      LG,
      CK

      1. Hallo Christian,

        Nein. Ein solches Konstrukt ist zu vermeiden.

        Das denk ich mir, darum schreib ich es um. Danke!

        Gruß
        Jo

    2. Tach!

      Was soll denn das bedeuten?

      der Join tatsächlich nötig ist und nicht aus reiner Bequemlichkeit einer zweiten Abfrage vorgezogen wird

      Soll das heißen ein Join ist schlechter als:

      Select * FROM a WHERE id = 1
      // Eine Ergebnismenge von 10 Zeilen oder 10.000 Zeilen
      while($row...){
         Select * FROM b WHERE id = $row['**']
      }
      

      Das ist damit nicht gemeint. Da steht einer zweiten und nicht mehrere abhängige. Bequemlichkeit ist es, wenn die Abfragen eigentlich nichts miteinander zu tun haben, aber trotzdem in nur einer Query abgefrühstückt werden sollen. Ich mach solche schmutzigen Tricks nicht und kann dir deshalb keine Beispiele liefern.

      dedlfix.