Jnnbo: Zwei Tabellen verbinden

Moin,

ich habe irgendwie das Gefühl, dass ich mich etwas vertan habe und stehe nun in einer Sackgasse. Hoffentlich komme ich hier ohne große Mühen wieder raus.

Folgende Situation habe ich derzeit:

Mein MySQL Abfrage

$select = "SELECT s_id, s_hID, s_titel, s_titelUrl, s_status, h_titel, s_titelUrl 
						FROM web_serien 
						LEFT JOIN web_hersteller ON web_hersteller.h_id = web_serien.s_hID ";
		
		if ($id) {
			$stmt = $mysqli->prepare($select . "WHERE s_hID = ?" );
			$stmt->bind_param("s", $id);
  		} else {
			$stmt = $mysqli->prepare($select);
		}

Meine zwei MySQL Tabellen

CREATE TABLE IF NOT EXISTS `web_hersteller` (
`h_id` int(11) NOT NULL,
  `h_titel` varchar(100) NOT NULL,
  `h_titelURL` varchar(100) NOT NULL,
  `h_status` varchar(2) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `web_serien` (
`s_id` int(11) NOT NULL,
  `s_hID` varchar(100) NOT NULL,
  `s_titel` varchar(200) NOT NULL,
  `s_titelUrl` varchar(200) NOT NULL,
  `s_status` varchar(1) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=930 DEFAULT CHARSET=utf8;

Mein Plan war, beide Tabellen so zu verbinden:

LEFT JOIN web_hersteller ON web_hersteller.h_id = web_serien.s_hID ";

allerdings übergebe ich keine ID in meiner URL sondern "brother.html" dieser Wert steht in "h_titelURL" Entweder sehe ich gerade den Wald vor lauter Bäume nicht mehr oder ich kann wirklich nicht so weiter arbeiten wie ich mit der URL angefangen habe.

Eine weitere Idee wäre, dass ich innerhalb der Funktion noch eine weitere Abfrage gezielt auf "web_hersteller" mache mit dem Wert, den ich in der URL habe um an die ID zu kommen, diesen Wert dann in einer Variable speichern und in der eigentlichen Abfrage verwenden.

Ihr habt davon mehr Ahnung, wie sollte ich vorgehen oder habt ihr vielleicht noch eine ganz andere Idee?

  1. Moin!

      if ($id) {
      	$stmt = $mysqli->prepare($select . "WHERE s_hID = ?" );
      	$stmt->bind_param("s", $id);
    

    allerdings übergebe ich keine ID in meiner URL sondern "brother.html" dieser Wert steht in "h_titelURL"

    Ist der Aha-Effekt eingetreten?

    Jörg Reinholz

    1. Hallo Jörg,

      Ist der Aha-Effekt eingetreten?

      leider nein :/ Ich habe diesen Wert natürlich schon auf "h_titelURL" umgestellt gehabt, allerdings steht ja in meiner zweiten Tabelle wieder eine ID

      1. Moin!

        Ist der Aha-Effekt eingetreten?

        leider nein

        Dann wird es leider etwas schwierig zu erraten, was Du willst.

        Wir wollen bzw. brauchen:

        • den tatsächlichen Code und
        • die tatsächlichen Fehlermeldungen bzw.
          • erwartete Resultate
          • bewirkte Resultate

        Jörg Reinholz

  2. Tach!

    Mein Plan war, beide Tabellen so zu verbinden:

    LEFT JOIN web_hersteller ON web_hersteller.h_id = web_serien.s_hID ";
    

    allerdings übergebe ich keine ID in meiner URL sondern "brother.html" dieser Wert steht in "h_titelURL" Entweder sehe ich gerade den Wald vor lauter Bäume nicht mehr oder ich kann wirklich nicht so weiter arbeiten wie ich mit der URL angefangen habe.

    Die URL kann ganz unabhängig von der Verknüpfung mit WHERE eingeschränkt werden.

    dedlfix.

  3. Moin!

    Zweiter Versuch:

    Ich vermute, Du kommst mit der URL des Herstellers vorbei und suchst die Serien. Dann sollte das, was an MySQL geschickt wird, wohl etwa so aussehen:

    SELECT 
      `web_serien`.`s_id`,
      `web_serien`.`s_hID`,
      `web_serien`.`s_titel`,
      `web_serien`.`s_titelUrl`,
      `web_serien`.`s_status`,
      `web_serien`.`s_titelUrl`, 
      `web_hersteller`.`h_titel`
    FROM
      `web_serien`,
      `web_hersteller`
    WHERE
      `web_hersteller`.`h_titelURL` = $VARIABLE
       AND `web_serien`.`s_hID` = `web_hersteller.h_id`
    

    Jörg Reinholz

    1. Hallo Jörg,

      Ich vermute, Du kommst mit der URL des Herstellers vorbei und suchst die Serien. Dann sollte das, was an MySQL geschickt wird, wohl etwa so aussehen:

      SELECT 
        `web_serien`.`s_id`,
        `web_serien`.`s_hID`,
        `web_serien`.`s_titel`,
        `web_serien`.`s_titelUrl`,
        `web_serien`.`s_status`,
        `web_serien`.`s_titelUrl`, 
        `web_hersteller`.`h_titel`
      FROM
        `web_serien`,
        `web_hersteller`
      WHERE
        `web_hersteller`.`h_titelURL` = $VARIABLE
         AND `web_serien`.`s_hID` = `web_hersteller.h_id`
      

      vielen Dank für deinen Code, aber benötige ich kein LEFT JOIN um zwei Tabellen zu verbinden? Das vermisse ich bei dir

      1. Tach!

        vielen Dank für deinen Code, aber benötige ich kein LEFT JOIN um zwei Tabellen zu verbinden? Das vermisse ich bei dir

        Ob Left oder nicht, hängt von der Aufgabenstellung ab. Jörg hat deinen Left Join zu einem impliziten Inner Join umgeschrieben (was vermutlich nicht gewollt ist). Die Verknüpfungsbedingung in der WHERE-Klausel erzeugt auch einen Join, aber einen Inner Join. Für Outer Joins muss man die explizite Join-Syntax nehmen.

        dedlfix.

        1. Moin!

          (was vermutlich nicht gewollt ist)

          Meine Vermutung lief darauf hinaus, dass Jnnbo das wollte.

          Es ist, glaube ich, an der Zeit dafür, zu fragen: Jnnbo: WAS (zum Henker) willst Du eigentlich erreichen?

          Jörg Reinholz

          1. Hallo Jörg,

            Es ist, glaube ich, an der Zeit dafür, zu fragen: Jnnbo: WAS (zum Henker) willst Du eigentlich erreichen?

            was ICH erreichen möchte habe ich doch in meinem ersten Posting geschrieben oder? Ich möchte BEIDE Tabellen verbinden um mit dieser URL "brother.html" an die Serien zu kommen. Mein URL Wert steht in der Tabelle "web_hersteller" im Feld "h_titelURL" daneben gibt es dann ein Feld "h_id" dieses benötige ich um die dazugehörigen Serien die in der Tabelle "web_serien" im Feld "s_hID" stehen.

            1. Moin!

              was ICH erreichen möchte habe ich doch in meinem ersten Posting geschrieben oder?

              Nicht wirklich. Falls doch war für meinen geringen Verstand zu stark verklausuliert.

              Jörg Reinholz

              1. Hallo Jörg,

                Nicht wirklich. Falls doch war für meinen geringen Verstand zu stark verklausuliert.

                damit muss ich dann einfach leben. Ich versuche gerade einfach eine zweite MySQL Abfrage in die Funktion einzubauen, dann habe ich den TitelURL Wert und kann mit der dazugehörigen ID weiterarbeiten.

                1. Moin!

                  damit muss ich dann einfach leben … zweite MySQL Abfrage

                  Musst Du nicht. Es wäre für Dich einfacher, Du würdest diese Antwort lesen.

                  Jörg Reinholz

                  1. Hallo Jörg,

                    Musst Du nicht. Es wäre für Dich einfacher, Du würdest diese Antwort lesen.

                    habe ich!

        2. Hallo dedlfix,

          Ob Left oder nicht, hängt von der Aufgabenstellung ab. Jörg hat deinen Left Join zu einem impliziten Inner Join umgeschrieben (was vermutlich nicht gewollt ist). Die Verknüpfungsbedingung in der WHERE-Klausel erzeugt auch einen Join, aber einen Inner Join. Für Outer Joins muss man die explizite Join-Syntax nehmen.

          ich hab das jetzt so umgesetzt und wie erwartet bekomme ich eine Fehlermeldung

          	function serienTEMP($mysqli, $id) {
          		
          		$select = "SELECT 
          					  `web_serien`.`s_id`,
          					  `web_serien`.`s_hID`,
          					  `web_serien`.`s_titel`,
          					  `web_serien`.`s_titelUrl`,
          					  `web_serien`.`s_status`,
          					  `web_serien`.`s_titelUrl`, 
          					  `web_hersteller`.`h_titelURL`,
          					  `web_hersteller`.`h_id`
          					FROM
          					  `web_serien`,
          					  `web_hersteller`
          					WHERE
          					  `web_hersteller`.`h_titelURL` = ?
          					   AND `web_serien`.`s_hID` = `web_hersteller.h_id`";
          							
          		$stmt->bind_param("s", $id);
          		$stmt->execute();
          		$stmt->bind_result($s_id, $s_hID, $s_titel, $s_titelUrl, $s_status, $s_titelUrl, $h_titelURL, $h_id);
          		$stmt->store_result();
          	 	
          		if($stmt->num_rows() >  0) {     
          			while ($stmt->fetch()){
          				$serien[] = array( 
          					's_id' 			=> $s_id, 
          					's_hID' 		=> $s_hID, 
          					's_titel' 		=> $s_titel, 
          					's_titelUrl'	=> $s_titelUrl,
          					's_status'		=> $s_status,
          					'h_titel'		=> $h_titel,
          					'h_titelURL'	=> $h_titelURL,
          					'h_id'			=> $h_id
          				);
          			}
          			return $serien;
          			}
          	}
          
          Notice: Undefined variable: stmt in uebersicht.php on line 250 
          Fatal error: Call to a member function bind_param() on a non-object in uebersicht.php on line 250
          

          Ich mach es am besten mit zwei Abfragen wie ich es im ersten Posting schon geschrieben habe.

          1. Moin!

            Du hast einen recht einfachen Fehler in Zeile 250. Vermutlich ist das diese hier:

            $stmt->bind_param("s", $id);
            

            es fehlt davor eine Zeile:

            $stmt = $mysqli->prepare($select);
            

            Ich mach es am besten mit zwei Abfragen wie ich es im ersten Posting schon geschrieben habe.

            Klar doch. Dann hättest Du den selben Fehler voraussichtlich zwei mal.

            Jörg Reinholz

            1. Hallo Jörg,

              es fehlt davor eine Zeile:

              $stmt = $mysqli->prepare($select);
              

              habe ich nun eingefügt und erhalte noch diese Meldung

              	function serienTEMP($mysqli, $id) {
              		
              		$select = "SELECT 
              					  `web_serien`.`s_id`,
              					  `web_serien`.`s_hID`,
              					  `web_serien`.`s_titel`,
              					  `web_serien`.`s_titelUrl`,
              					  `web_serien`.`s_status`,
              					  `web_serien`.`s_titelUrl`, 
              					  `web_hersteller`.`h_titelURL`,
              					  `web_hersteller`.`h_id`
              					FROM
              					  `web_serien`,
              					  `web_hersteller`
              					WHERE
              					  `web_hersteller`.`h_titelURL` = ?
              					   AND `web_serien`.`s_hID` = `web_hersteller.h_id`";
              							
              		$stmt = $mysqli->prepare($select);
              		$stmt->bind_param("s", $id);
              		$stmt->execute();
              		$stmt->bind_result($s_id, $s_hID, $s_titel, $s_titelUrl, $s_status, $s_titelUrl, $h_titelURL, $h_id);
              		$stmt->store_result();
              	 	
              		if($stmt->num_rows() >  0) {     
              			while ($stmt->fetch()){
              				$serien[] = array( 
              					's_id' 			=> $s_id, 
              					's_hID' 		=> $s_hID, 
              					's_titel' 		=> $s_titel, 
              					's_titelUrl'	=> $s_titelUrl,
              					's_status'		=> $s_status,
              					's_titelUrl'	=> $s_titelUrl,
              					'h_titelURL'	=> $h_titelURL,
              					'h_id'			=> $h_id
              				);
              			}
              			return $serien;
              			}
              	}
              
              Fatal error: Call to a member function bind_param() on a non-object 
              

              Ich hatte diese schon öfters, dann ein Wert nicht gestimmt, allerdings sehe ich hier kein Fehler. Was ich vermute ist, dass etwas mit dem =? nicht stimmt.

              1. Tach!

                  $stmt = $mysqli->prepare($select);
                  $stmt->bind_param("s", $id);
                

                Fatal error: Call to a member function bind_param() on a non-object

                Ich hatte diese schon öfters, dann ein Wert nicht gestimmt, allerdings sehe ich hier kein Fehler. Was ich vermute ist, dass etwas mit dem =? nicht stimmt.

                Nicht vermuten, Fehlermeldung anzeigen lassen! Wenn das Prepare misslingt, dann gibt die Methode kein Statement-Objekt sondern ein false zurück. In dem Fall kennt MySQL/PHP auch eine konkrete Fehlermeldung. Schau ins PHP-Handbuch, wie man die abfragen kann.

                dedlfix.

                1. Hallo dedlfix,

                  Nicht vermuten, Fehlermeldung anzeigen lassen! Wenn das Prepare misslingt, dann gibt die Methode kein Statement-Objekt sondern ein false zurück. In dem Fall kennt MySQL/PHP auch eine konkrete Fehlermeldung. Schau ins PHP-Handbuch, wie man die abfragen kann.

                  jetzt hast du mich auf eine Idee gebracht, ich frag was in der URL steht so ab:

                  $seite = explode("/", $_SERVER['REQUEST_URI']);
                  $er=  $seite[2];
                  

                  Als Ergebnis erhalte ich "brother.html" FALSCH! Ich benötige nur "brother", denn dieser Wert steht in der Datenbank, deshalb steht auch nichts in Prepare drin. Jetzt muss ich mal schauen wie ich das .html weg bekomme.

                  1. Moin!

                    jetzt hast du mich auf eine Idee gebracht, ich frag was in der URL steht so ab:

                    Als Ergebnis erhalte ich "brother.html" FALSCH! Ich benötige nur "brother",

                    Das dann auch, aber das würde nur zu einem leeren Ergebnis führen und also nicht zu dem gezeigten Fehler. Der hat eine eigene Ursache.

                    Jörg Reinholz

                    1. Hallo Jörg,

                      Das dann auch, aber das würde nur zu einem leeren Ergebnis führen und also nicht zu dem gezeigten Fehler. Der hat eine eigene Ursache.

                      ok, das .html habe ich so entfernt:

                      $seite = explode("/", $_SERVER['REQUEST_URI']);
                      $er = str_replace(".html", "", $seite[2]);
                      echo $er;
                      
              2. Moin!

                	$stmt = $mysqli->prepare($select);
                

                Fatal error: Call to a member function bind_param() on a non-object

                Ich hatte diese schon öfters, dann ein Wert nicht gestimmt, allerdings sehe ich hier kein Fehler. Was ich vermute ist, dass etwas mit dem =? nicht stimmt.

                Ja. Und dafür gibt es eine Fehlerbehandlung:

                  define('DEBUG', true); # Auf Produktivsystem auf false setzen
                  …			
                  $stmt = $mysqli->prepare($select);
                  if( DEBUG && !$stmt ) { echo '<pre>', $mysqli->error, '</pre>'; }
                

                Jörg Reinholz

                1. Hallo Jörg,

                  Ja. Und dafür gibt es eine Fehlerbehandlung:

                    define('DEBUG', true); # Auf Produktivsystem auf false setzen
                    …			
                    $stmt = $mysqli->prepare($select);
                    if( DEBUG && !$stmt ) { echo '<pre>', $mysqli->error, '</pre>'; }
                  

                  jetzt kommen wir der Sache etwas näher

                  Unknown column 'web_hersteller.h_id' in 'where clause'
                  

                  Das Feld h_id in der Tabelle web_hersteller existiert aber.

                  1. Moin!

                    jetzt kommen wir der Sache etwas näher

                    Unknown column 'web_hersteller.h_id' in 'where clause'
                    

                    Das Feld h_id in der Tabelle web_hersteller existiert aber.

                    Ja. Da steht aber:

                    AND `web_serien`.`s_hID` = `web_hersteller.h_id`";
                    

                    muss heissen:

                    AND `web_serien`.`s_hID` = `web_hersteller`.`h_id`";
                    

                    Jörg Reinholz

                    1. Hallo Jörg,

                      Ja. Da steht aber:

                      AND `web_serien`.`s_hID` = `web_hersteller.h_id`";
                      

                      muss heissen:

                      AND `web_serien`.`s_hID` = `web_hersteller`.`h_id`";
                      

                      vielen lieben Dank für deine / eure Hilfe. Es klappt nun, meine fertige Funktion sieht nun so aus:

                      	function serienTEMP($mysqli, $id) {
                      		
                      		define('DEBUG', true); 
                      		
                      		$select = "SELECT 
                      					  `web_serien`.`s_id`,
                      					  `web_serien`.`s_hID`,
                      					  `web_serien`.`s_titel`,
                      					  `web_serien`.`s_titelUrl`,
                      					  `web_serien`.`s_status`,
                      					  `web_serien`.`s_titelUrl`, 
                      					  `web_hersteller`.`h_titel`,
                      					  `web_hersteller`.`h_titelURL`,
                      					  `web_hersteller`.`h_id`
                      					FROM
                      					  `web_serien`,
                      					  `web_hersteller`
                      					WHERE
                      					  `web_hersteller`.`h_titelURL` = ?
                      					   AND `web_serien`.`s_hID` = `web_hersteller`.`h_id`";
                      							
                      		$stmt = $mysqli->prepare($select);
                      		if( DEBUG && !$stmt ) { echo '<pre>', $mysqli->error, '</pre>'; }
                      		$stmt->bind_param("s", $id);
                      		$stmt->execute();
                      		$stmt->bind_result($s_id, $s_hID, $s_titel, $s_titelUrl, $s_status, $s_titelUrl, $h_titel, $h_titelURL, $h_id);
                      		$stmt->store_result();
                      	 	
                      		if($stmt->num_rows() >  0) {     
                      			while ($stmt->fetch()){
                      				$serien[] = array( 
                      					's_id' 			=> $s_id, 
                      					's_hID' 		=> $s_hID, 
                      					's_titel' 		=> $s_titel, 
                      					's_titelUrl'	=> $s_titelUrl,
                      					's_status'		=> $s_status,
                      					's_titelUrl'	=> $s_titelUrl,
                      					'h_titel'		=> $h_titel,
                      					'h_titelURL'	=> $h_titelURL,
                      					'h_id'			=> $h_id
                      				);
                      			}
                      			return $serien;
                      			}
                      	}
                      

                      Diese Zeile " if( DEBUG && !$stmt ) { echo '<pre>', $mysqli->error, '</pre>'; }" werde ich jetzt erstmal überall einfügen, dann sehe ich was Sache ist und was nicht. Danke!

                      1. Tach!

                        vielen lieben Dank für deine / eure Hilfe. Es klappt nun, meine fertige Funktion sieht nun so aus:

                        Du bist dir sicher, dass die Änderung von Left Join zu Inner Join richtig ist?

                        Diese Zeile " if( DEBUG && !$stmt ) { echo '<pre>', $mysqli->error, '</pre>'; }" werde ich jetzt erstmal überall einfügen, dann sehe ich was Sache ist und was nicht. Danke!

                        Und wenn im Produktivbetrieb ein Fehler auftritt? Dann rennt die Anwendung weiter und es kommt zu Folgefehlern. Beim Datenbankzugriff muss man immer damit rechnen, dass was schiefläuft. Selbst wenn die Verbindung problemlos aufzubauen war und das Statement fehlerfrei ist, kann trotzdem die Ausführung wegen anderer Gründe scheitern. Und die liegen dann außerhalb des Einflussbereichs deiner Anwendung. Als Programmierer solltest du dir immer Gedanken machen (beziehungsweise im Handbuch nachlesen), wie eine Funktion einen Fehler meldet und was in dem Fall eine für den Anwender sinnvolle Alternative ist.

                        dedlfix.

                        1. Hallo dedlfix,

                          Du bist dir sicher, dass die Änderung von Left Join zu Inner Join richtig ist?

                          ich merke kein Unterschied zu zwischen Left und Inner Join.

                          1. Tach!

                            Du bist dir sicher, dass die Änderung von Left Join zu Inner Join richtig ist?

                            ich merke kein Unterschied zu zwischen Left und Inner Join.

                            Du musst anhand deiner Daten und der Aufgabenstellung ermitteln, welcher Join der passende ist. Wenn es zu jedem x ein oder mehrere y gibt, dann ist in der Tat kein Unterschied zwischen Inner und Outer Join. Wenn es aber auch kein y geben kann, dann fehlt bei einem Inner Join das x in der Ergebnismenge. Beim Left (Outer) Join ist wenigstens das x da und statt der von y stammenden Felder sind NULL-Werte in der Ergebnismenge.

                            dedlfix.

                            1. Hallo,

                              Du musst anhand deiner Daten und der Aufgabenstellung ermitteln, welcher Join der passende ist …

                              … und egal welcher Join dann tatsächlich verwendet wird: den sollte man dann auch explizit formulieren - ein impliziter Join macht den Query unübersichtlicher/schlechter lesbar.

                              Gruß,
                              Tobias

          2. Tach!

            ich hab das jetzt so umgesetzt und wie erwartet bekomme ich eine Fehlermeldung Notice: Undefined variable: stmt in uebersicht.php on line 250 Fatal error: Call to a member function bind_param() on a non-object in uebersicht.php on line 250

            Diese Meldung ist ganz und gar nicht zu erwarten gewesen, denn die bezieht sich nicht auf das geänderte Statement sondern darauf, dass $stmt nicht existiert. Du hast da eine Zeile Code zu kopieren vergessen oder $stmt muss als Parameter der Funktion übergeben werden und das mysqli_stmt-Objekt außerhalb erstellt worden sein.

              			FROM
              			  `web_serien`,
              			  `web_hersteller`
              			WHERE
              			  `web_hersteller`.`h_titelURL` = ?
              			   AND `web_serien`.`s_hID` = `web_hersteller.h_id`";
            

            Nun bist du von einem Left Join auf einen Inner Join umgestiegen. Wenn dir die Unterschiede oder allgemein die Arbeitsweisen der verschiedenen Joins nicht geläufig sind, wir haben dazu Grundlagenliteratur.

            dedlfix.