Meowsalot: AND an Funktion übergeben

Hallo alle,

meine Idee war folgende:

$ToDoUebersicht = ToDoUebersicht($mysqli, $Art, $User->kuerzel, $User->kuerzel, $testEintrag);

In der Funktion wollte ich die Daten dann so anhängen

WHERE status NOT IN ('d9788f30bcf311ed98ef6bd5113784b2', '302fa36fca330e8faf9a5fe9f6ca5637') 
  AND vertraulich = '0' ?

$stmt->bind_param("sss", $von, $an, $testEintrag);

Jetzt bekomme ich ein

Fatal error: Call to a member function bind_param() on boolean

Ich glaube, ich habe es mir zu einfach gemacht, das AND einfach zu erweitern? So schaut der übergebene Wert aus

AND Empfaenger = '2b442c0dc74c1dff7fdaab8a364361d2' 
AND Empfaenger = '151237075579946c033aadc899804380' 
AND Empfaenger = '0b5247f8493271ec41297c4385386837' 
AND Empfaenger = '57f300b4fa8518ab557acf154af5e621'

Bis bald! Meowsalot (Bernd)

akzeptierte Antworten

  1. @@Meowsalot

    meine Idee war folgende:

    Geht es immer noch darum, einen bestimmten Wert auszublenden?

    LLAP 🖖

    --
    „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
    1. Hallo Gunnar,

      nein. Das habe ich ja hinbekommen.

      Bis bald!
      Meowsalot (Bernd)

  2. Tach!

    In der Funktion wollte ich die Daten dann so anhängen

    WHERE status NOT IN ('d9788f30bcf311ed98ef6bd5113784b2', '302fa36fca330e8faf9a5fe9f6ca5637') 
      AND vertraulich = '0' ?
    
    $stmt->bind_param("sss", $von, $an, $testEintrag);
    

    Jetzt bekomme ich ein

    Fatal error: Call to a member function bind_param() on boolean

    Das ist ein Folgefehler. Der eigentliche ist ein Syntaxfehler in SQL. Dass der aufgetreten ist, wurde dir über den Rückgabewert von prepare() mitgeteilt, den du aber anscheinend ignoriert hast.

    Ich glaube, ich habe es mir zu einfach gemacht, das AND einfach zu erweitern?

    Ja. Mit Prepared Statements können nur die Werte variabel sein, nicht aber andere Bestandteile der Query. Das würde auch das Konzept ad absurdum führen, weil dann das Statement nicht mehr vorbereitet werden kann, wenn es sich dann doch noch verändern soll.

    dedlfix.

    1. Hallo dedlfix,

      Ja. Mit Prepared Statements können nur die Werte variabel sein, nicht aber andere Bestandteile der Query. Das würde auch das Konzept ad absurdum führen, weil dann das Statement nicht mehr vorbereitet werden kann, wenn es sich dann doch noch verändern soll.

      misst, habe ich mir fast gedacht. Dann weiß ich nicht, wie ich das AND dynamisch erweitern kann. Mal sind es 2, mal 4, mal vielleicht 5 oder mehr / weniger AND die angehängt werden müssen. Hast du du eine Idee?

      Bis bald!
      Meowsalot (Bernd)

      1. Tach!

        Dann weiß ich nicht, wie ich das AND dynamisch erweitern kann. Mal sind es 2, mal 4, mal vielleicht 5 oder mehr / weniger AND die angehängt werden müssen. Hast du du eine Idee?

        So wie du das vorhast, geht es sowieso nicht. Der Wert im Feld X kann niemals a AND b AND c ... sein. Er kann aber a OR b OR c sein, oder IN(a,b,c). Wie auch immer, auch das sind mehrere Werte, die du nicht in einem Stück übergeben kannst. Da wird dir wohl nichts anderes übrig bleiben, als das Statement selbst nach Bedarf anzupassen, also entsprechend viele ? für das IN() einbauen.

        dedlfix.

        1. Hallo dedlfix,

          Ok, ich dachte so komme ich weiter

          
          $values = array('2b442c0dc74c1dff7fdaab8a364361d2',
                          '151237075579946c033aadc899804380', 
                          '0b5247f8493271ec41297c4385386837', 
                          '57f300b4fa8518ab557acf154af5e621');
          
          $s      = substr( str_repeat( ' , ?' , count( $values ) ) , 2 );
          
          $stmt = $mysqli->prepare($select . " 
          
          	WHERE status NOT IN ('d9788f30bcf311ed98ef6bd5113784b2', 
                                 '302fa36fca330e8faf9a5fe9f6ca5637') 
            
            AND vertraulich = '0' AND bereichEmpfaenger IN (" . $s . ")
                                                           
              UNION SELECT id, code, kurzbeschreibung, art, erstellungsdatum, job, 
                           bereichSender, apSender, bereichEmpfaenger, apEmpfaenger, prio, 
                           status, fertigstellung_sender, fertigstellung_uhrzeit_sender, 
                           fertigstellung_empfaenger, fertigstellung_uhrzeit_empfaenger, 
                           beschreibung, vertraulich, ta_titel, tp_titel, tp_farbe, ts_id, 
                           ts_titel, s.tb_titelkurz as Sender, e.tb_titelkurz as Empfaenger
                                                           
                      FROM todo_grunddaten g                                 
                                                           
                      LEFT JOIN todo_art ON todo_art.ta_code = g.art
                      LEFT JOIN todo_prio ON todo_prio.tp_code = g.prio
                      LEFT JOIN todo_status ON todo_status.ts_code = g.status
                      LEFT JOIN todo_bereich s ON g.bereichSender = s.tb_code
                      LEFT JOIN todo_bereich e ON g.bereichEmpfaenger = e.tb_code 
          
                      WHERE status NOT IN ('d9788f30bcf311ed98ef6bd5113784b2',
                                           '302fa36fca330e8faf9a5fe9f6ca5637')  
                      AND vertraulich = '1' AND (apSender =? OR apEmpfaenger =?)  
                      AND bereichEmpfaenger IN (" . $s . ")
          
                      ORDER by erstellungsdatum DESC" );
                 
                 	$typeDefinitions = str_repeat( 's' , count( $values ) );
                  $params = array( $typeDefinitions );
          
                  foreach ( $values as $k => $v ) {
                      ${ 'varvar' . $k } = $v;
                  	    $params[] = &${ 'varvar' . $k };# provide references
                      }
                      call_user_func_array( array( $stmt , 'bind_param' ) , $params );
                      $stmt->bind_param("ss", $von, $an);
                  }
          
                  {
                  $stmt->execute();
          

          Jetzt bekomme ich zwei Warnungen

          Warning: mysqli_stmt::bind_param(): Number of variables doesn't match number of parameters in prepared statement in
          Warning: Invalid argument supplied for foreach()^

          Ich denke es liegt an diesen Zeilen?

          call_user_func_array( array( $stmt , 'bind_param' ) , $params );
          $stmt->bind_param("ss", $von, $an);
          

          Diese beiden müssten irgendwie verknüft werden? Denn ich kann ja bind_param nicht zweimal aufrufen?

          Bis bald,
          Meowsalot (Bernd)

          1. Tach!

            $values = array('2b442c0dc74c1dff7fdaab8a364361d2', '151237075579946c033aadc899804380', '0b5247f8493271ec41297c4385386837', '57f300b4fa8518ab557acf154af5e621');

            $s = substr( str_repeat( ' , ?' , count( $values ) ) , 2 );

            str_repeat() ist ok, aber dann nimm lieber implode(). Dann musst du nicht überflüssige Zeichen abschneiden.

            $s = implode(',', str_repeat('?', count($values)));

            Warning: mysqli_stmt::bind_param(): Number of variables doesn't match number of parameters in prepared statement in

            Damit hat die Meldung ja auch recht. Du hast die Werte von $values zweimal verwendet, musst sie also auch zweimal binden, vor und nach den beiden anderen Einzelkandidaten.

            Warning: Invalid argument supplied for foreach()^

            Das kommt wohl aus einer anderen Ecke deines Programms.

            Diese beiden müssten irgendwie verknüft werden? Denn ich kann ja bind_param nicht zweimal aufrufen?

            Das auch noch. Du musst also erstmal ein komplettes Array mit beiden $values-Inhalt, den beiden Einzelwerten und nochmals $values bilden und das dann in einem Rutsch binden.

            Ich rate dir nochmal, auf PDO umzusteigen, denn dann entfällt dieses Gehampel mit den Referenzen und dem Binden. Einmal Prepare und beim Execute ein Array mit den Werten übergeben. Fertig.

            dedlfix.

            1. Hallo dedlfix,

              Ich rate dir nochmal, auf PDO umzusteigen, denn dann entfällt dieses Gehampel mit den Referenzen und dem Binden. Einmal Prepare und beim Execute ein Array mit den Werten übergeben. Fertig.

              ich kann leider nicht alles auf einmal. Die Funktion hat mittlerweile fast 300 Zeilen Code. Dieses alles auf PDO umzustellen bedeutet wahrscheinlich sehr viel Arbeit und auch noch Anpassungen an anderen Stellen?

              Das auch noch. Du musst also erstmal ein komplettes Array mit beiden $values-Inhalt, den beiden Einzelwerten und nochmals $values bilden und das dann in einem Rutsch binden.

              Und dieses verstehe ich leider nicht.

              Bis bald!
              Meowsalot (Bernd)

              1. Tach!

                Das auch noch. Du musst also erstmal ein komplettes Array mit beiden $values-Inhalt, den beiden Einzelwerten und nochmals $values bilden und das dann in einem Rutsch binden.

                Und dieses verstehe ich leider nicht.

                Erstell dir ein neues Array aus den Werten in $values plus die beiden einzelnen plus nochmal die Werte aus $values. Am Ende müssen die Werte in der Reihenfolge drinstehen, wie im Statement die ? auftauchen. Und dann bindest du dieses neue Array nach dem schon bekannten Verfahren.

                dedlfix.

                1. Hallo dedlfix,

                  habe ich damit nicht schon ein Array?

                  $params[]
                  

                  Und könnte man da außerdem von foreach nicht die beiden Werte mit dran hängen und dann nochmals durch eine Schleife laufen lassen um alle Daten nochmals zu bekommen?

                  Bis bald!
                  Meowsalot (Bernd)

                  1. Tach!

                    habe ich damit nicht schon ein Array?

                    $params[]
                    

                    Ja, stimmt. Aber das musst du erst befüllen, dann das Binden durchführen. Das Binden darf jedenfalls nicht im Körper von foreach auftauchen.

                    dedlfix.

                    1. Hallo dedlfix,

                      stimmt das so denn?

                             	$typeDefinitions = str_repeat( 's' , count( $values ) );
                              $params = array( $typeDefinitions );
                      
                              foreach ( $values as $k => $v ) {
                                  ${ 'varvar' . $k } = $v;
                              	    $params[] = &${ 'varvar' . $k };# provide references
                                  }
                                
                                  	$params[]. = &${ 's' . $von };
                                  	$params[]. = &${ 's' . $an };
                      
                              foreach ( $values as $k => $v ) {
                                  ${ 'varvar' . $k } = $v;
                              	    $params[]. = &${ 'varvar' . $k };# provide references
                                  }   	
                      
                      
                        		call_user_func_array( array( $stmt , 'bind_param' ) , $params );
                                  $stmt->bind_param("ss", $von, $an);
                              }
                      

                      Bis bald! Meowsalot (Bernd)

                      1. Tach!

                        stimmt das so denn?

                        Das Konstrukt $params[]. = ... ergibt keinen Sinn. Die [] bedeuten, dass ein neuer Eintrag hinzugefügt werden soll, der Punkt-Operator ist eine Stringverkettung. In ein neues Feld möchte man etwas reinschreiben, aber nicht etwas an nichts anhängen. Der Punkt kann da also weg.

                           	$typeDefinitions = str_repeat( 's' , count( $values ) );
                        

                        Hier müssen so viele s rein, wie Werte im Array, also zweimal count($values) plus 2.

                        call_user_func_array( array( $stmt , 'bind_param' ) , $params );
                        $stmt->bind_param("ss", $von, $an);
                        

                        Die zweite Zeile muss weg. Diese Werte hast du ja zwischen den beiden foreaches eingefügt.

                        Ansonsten fällt mir erstmal nichts auf, was nicht viel heißt. Trockenschwimmen ist Mist und wenn was kaputt ist, bemerkt das PHP das viel besser als ich.

                        dedlfix.

                        1. Hallo dedlfix,

                          danke für deine Erklärung. Ich habe es nochmals angepasst

                                  $typeDefinitions = str_repeat( 's' , count( $values )*2 +2 );
                                  $params = array( $typeDefinitions );
                          
                                  foreach ( $values as $k => $v ) {
                                      ${ 'varvar' . $k } = $v;
                                  	    $params[] = &${ 'varvar' . $k };# provide references
                                      }
                                    
                                      	$params[] = &${ 's' . $von };
                                      	$params[] = &${ 's' . $an };
                          
                                  foreach ( $values as $k => $v ) {
                                      ${ 'varvar' . $k } = $v;
                                  	    $params[] = &${ 'varvar' . $k };# provide references
                                      }   	
                          
                            		call_user_func_array( array( $stmt , 'bind_param' ) , $params );
                                  }
                          
                                  {
                                  $stmt->execute();
                          

                          Passt das mit dem

                          str_repeat( 's' , count( $values *2 +2 ));
                          

                          EDIT: OK, es passt wohl. Es kommen zumindest keine Fehler mehr.

                          Bis bald!
                          Meowsalot (Bernd)

                          1. Hallo Meowsalot,

                            ich krieg die Krise wenn ich versuche, diesen Codeblob zu verstehen. Und ich habe in meinen 30 Jahren im Beruf schon einiges an Quälcode erlebt.

                            1. „Die Funktion hat mittlerweile fast 300 Zeilen Code.“

                            Die Funktion ist zu groß. Sie macht garantiert mehr als eine Sache. Zerlege sie in Funktionsblöcke. Ein paar Zeilen kannst Du auch eindampfen, wenn Du weiterliest...

                            2. Dynamisches Binden

                            Ich würde wetten, dass Du das Statement nach Bedarf zusammenhämmerst und dann genau einmal ausführst. Richtig?

                            Dann hast Du von einem Prepare überhaupt keinen Nutzen. Sind deine $values-Einträge eigentlich immer diese Hex-Strings und vertrauenswürdig (d.h. irgendwann mal durch eine Korrektheitsprüfung gelaufen)? Dann ist es doch das einfachste, sie mit

                            $empfaengerListe = "'".implode("','", $values)."'";
                            

                            zu einem String zusammenzusetzen. Und an Stelle einer umständlich erzeugten Fragezeichenliste setzt Du einfach die $valueList in die Klammer vom INs SQL Statement. Schwups, ist die dynamische Bindung verschwunden.

                            Wenn die $value-Werte nicht vertrauenswürdig sind oder Hochkommas enthalten können, musst Du sie natürlich erstmal korrekt für den Kontextwechsel ins SQL escapen. Das weißt Du besser als wir.

                            Den prepare brauchst Du dann nur noch für $von und $an, mit zwei s-Parametern.

                            3. varvar Akrobatik

                            Hatte ich das nicht schonmal angesprochen? Diese Mühe ist nicht nötig. Man kann auch Referenzen auf Array-Elemente bilden und in einem Array abspeichern. Dazu ist es nur nötig, die Variable der foreach-Schleife als Referenz zu definieren und dann nochmals als Referenz ins $params Array zu legen. Aber wenn Du den Inhalt des IN nicht zu binden brauchst, ist diese Übung ohnehin nicht nötig.

                            foreach ( $values as &$v ) {    // Hier ein & vor $v
                               $params[] = &$v;             // und hier auch noch mal
                            }
                            

                            Alternativ so, ohne Zwischenreferenzen (aber mit Zählvariable). Ich laufe abwärts um nicht pro Durchlauf count($values) neu bilden zu müssen

                            for ($i = count($values)-1; $i >= 0; $i--) {
                               $params[$i] =& $values[$i];
                            }
                            

                            4. Die $select-Variable

                            Steht in $select eigentlich das gleiche wie zwischen UNION und WHERE? Ich würde es stark vermuten. In dem Fall kannst Du doch $select zweimal verwenden, oder?

                            5. Ist der UNION nötig?

                            Wenn man annimmt, dass Nr. 4 zutrifft, müsste man die beiden WHERE-Bedingungen auch zusammenlegen können, statt einen UNION zu bilden. Wenn nicht, ok, dann geht's nicht. Aber Du könntest dann Bausteine bilden. Die Abfragen auf status und bereichEmpfaenger sind in beiden Teilen gleich. Die kannst Du in eine Variable $filter legen und diese Variable in den SQL String einsetzen.

                            Mit UNION:

                               $empfaengerListe = "'" . implode("','", $values) . "'";
                               $statusListe = "'d9788f30bcf311ed98ef6bd5113784b2', '302fa36fca330e8faf9a5fe9f6ca5637'";
                               $filter = "status NOT IN ($statusListe) AND bereichEmpfaenger IN ($empfaengerListe)";
                            
                               $sql = "$select
                                       WHERE $filter AND vertraulich = '0'
                                       UNION
                                       SELECT ... 
                                       FROM ... JOINJOINJOIN
                                       WHERE $filter AND vetraulich = '1' AND (apSender = ? OR apEmpfaenger = ?)
                                       ORDER BY erstellungsdatum DESC";
                            
                               $stmt = $mysqli->prepare($sql);
                            

                            Falls $select und der zweite SELECT identisch sind, kannst Du den UNION zu einem OR machen:

                               $empfaengerListe = "'" . implode("','", $values) . "'";
                               $statusListe = "'d9788f30bcf311ed98ef6bd5113784b2', '302fa36fca330e8faf9a5fe9f6ca5637'";
                            
                               $sql = "$select
                                       WHERE status NOT IN ($statusListe)
                                       AND bereichEmpfaenger IN ($empfaengerListe)
                                       AND (   vertraulich = '0'
                                            OR vertraulich = '1' AND (apSender = ? OR apEmpfaenger = ?) )
                                       ORDER BY erstellungsdatum DESC";
                            
                               $stmt = $mysqli->prepare($sql);
                            

                            Die Bausteine machen das ganze lesbarer und leichter debug-bar. Finde ich. Die Trennung in Konstruktion des SQL und Übergabe an Prepare hat noch den Vorteil, dass Du im Zweifelsfall mit var_dump das erzeugte SQL betrachten kannst.

                            Rolf

                            --
                            sumpsi - posui - clusi
                            1. Hallo Rolf,

                              Dann hast Du von einem Prepare überhaupt keinen Nutzen. Sind deine $values-Einträge eigentlich immer diese Hex-Strings und vertrauenswürdig (d.h. irgendwann mal durch eine Korrektheitsprüfung gelaufen)? Dann ist es doch das einfachste, sie mit

                              $empfaengerListe = "'".implode("','", $values)."'";
                              

                              ja, es sind immer ex-Strings und ja die sind immer vertrauenswürdig. Die Werte kommen von mir selbst.

                              Das heißt ich kann in deinem Beispiel $empfaengerListe direkt wie folgt nutzen?

                              AND vertraulich = '0' AND bereichEmpfaenger IN (" . empfaengerListe . ")
                              

                              Ohne Frage usw.? Das heißt es muss dann nicht gebunden werden? Das wäre ja das was ich eigentlich wollte

                              Bis bald!
                              Meowsalot (Bernd)

                              1. Hallo Meowsalot,

                                klar. Du hast immer die Wahl zwischen Parameterbindung und direktem Einsetzen der Werte ins SQL. Beides hat Vor- und Nachteile, bei beidem muss man darauf achten, es richtig zu machen.

                                Auf Stringverkettung kannst Du übrigens bei Strings in doppelten Anführungszeichen verzichten. PHP erkennt Variablen in diesen Strings und setzt den Wert ein. Das geht mit einfachen Variablen und Array-Elementen problemlos:

                                $foo = "Welt";
                                $a = ARRAY(1, 2, 3, 5);
                                $b = ARRAY("ding3" => "bums");
                                
                                $bar  = "Hallo ".$foo;        // ergibt "Hallo Welt"
                                $bar  = "Hallo $foo";         // das auch
                                $parf = "Chanel No. $a[3]";  // Chanel No. 5
                                $bla  = "So ein $b[ding3]";   // So ein bums
                                $huch = "So ein $b['ding3']";  // FEHLER, keine Hochkomma erlaubt!
                                $aha  = "So ein ${b['ding'.3]}";  // {} hilft, jetzt geht sogar ein . Operator
                                

                                PHP-Handbuch: String Parsing

                                Rolf

                                --
                                sumpsi - posui - clusi
                                1. Hallo Rolf,

                                  klar. Du hast immer die Wahl zwischen Parameterbindung und direktem Einsetzen der Werte ins SQL. Beides hat Vor- und Nachteile, bei beidem muss man darauf achten, es richtig zu machen.

                                  wann entscheidet man sich für das eine und wann für das andere? Gibt es da Anwendungsfälle wie man reagiert? Ich denke wenn ich selber weiß was ankommt dann kann ich dieses direkt einfügen, wenn ich nicht weiß was der User mit unterjubeln will sollte ich auf das andere setzten?

                                  Liege ich da richtig?

                                  Bis bald!
                                  Meowsalot (Bernd)

                                  1. Tach!

                                    wann entscheidet man sich für das eine und wann für das andere? Gibt es da Anwendungsfälle wie man reagiert? Ich denke wenn ich selber weiß was ankommt dann kann ich dieses direkt einfügen, wenn ich nicht weiß was der User mit unterjubeln will sollte ich auf das andere setzten?

                                    Die Unterscheidung darf nicht User vs. Anderes sein, sondern es muss die Korrektheit des SQL-Statements garantieren werden. Die Herkunft der Daten, die du da einfügen möchtest, spielt keine Rolle. Wichtig ist nur die Frage ob Sonderzeichen enthalten sein können, also all das, was man maskieren muss. Zu beachten sind auch Fälle, wo beispielsweise numerische Werte eingefügt werden sollen, die im Statement nicht in Anführungszeichen geschrieben werden. Auch das muss syntaktisch korrekt erfolgen, zum Beispiel indem mit intval() eine Zahl erzwungen wird.

                                    Und dann ist es im Prinzip egal, ob du das Statement selbst zusammenbaust oder die Daten getrennt per Prepared Statement übermittelst.

                                    Prepared Statements sind eigentlich dafür gedacht, ein Prepare und mehrere Executes durchführen zu können. Wenn man nur ein Execute hat, dann nutzt man lediglich die angenehme Nebenwirkung, sich um Quotierung und Maskierung nicht kümmern zu müssen.

                                    dedlfix.

                                    1. Hallo,

                                      und wenn

                                      die angenehme Nebenwirkung

                                      durch den Hassel und Brassel des Bindens überlagert wird, dann lässt man es. Wenn die Binde-Birne zu sauer wird, dann beißt man lieber in den Escaping-Apfel. Irgendwas beißen muss man aber. Wenn nicht bei den SQL Zugriffen, dann in die Tischkante weil man gehackt wurde 😂

                                      Die große Performance-Ersparnis bringt ein Prepare auf einem schwach belasteten Server ohnehin nicht. Der Server cached den Execution-Plan, den er für ein Statement erzeugt hat, und erkennt die Wiederverwendung. Auf einem stark belasteten Server mag dieser Cache überlaufen, so dass unnötig oft ein neuer Statement-Compile erfolgen muss.

                                      Der Prepare sorgt dafür, dass der Plan erhalten bleibt, solange das Statement nicht mit close() geschlossen wird. Die "Rüstzeiten" für die eigentliche Ausführung werden damit reduziert.

                                      Gelegentlich kann ein Prepare auch nachteilig sein. Wenn Du die Parameter im Statement direkt stehen hast, kann der Optimizer ggf. je nach Werten einen anderen Plan erzeugen, der performancetechnisch besser ist. Ob sowas passiert, kann man aber nicht abstrakt beantworten; das ist viel Erfahrung, genaue Kenntnis der Daten in der Datenbank und messen messen messen. Eventuell auch mal die Query mit unterschiedlichen Parametern vom MySQL explainen lassen. Messen kann man entweder mit DB-Tools, oder mit Stoppuhren in der Anwendung.

                                      Wenn man den Eindruck gewinnt, dass ein bestimmtes Statement zu langsam ist, muss man mit Explains 'ran und gucken, ob es durch Indexe besser werden kann oder ob das technische Datenmodell untauglich ist. Es kann bei stark belasteten Datenbanken z.B. nötig werden, bestimmte Spalten, die im konzeptionellen Modell normalisiert sind, im technischen Modell zu denormalisieren, d.h. bewusst Redundanzen zuzulassen. Man muss dann mit den Konsequenzen leben, die Redundanzen bei Updates nun mal haben, hat aber ggf. eine deutliche Beschleunigung der Lesezugriffe.

                                      Rolf

                                      --
                                      sumpsi - posui - clusi
                                      1. Tach!

                                        und wenn

                                        die angenehme Nebenwirkung

                                        durch den Hassel und Brassel des Bindens überlagert wird,

                                        dann wechselt man zu PDO und schlägt sich nicht mit der mysqli-Bindehautentzündung rum.

                                        dedlfix.

                                    2. Hallo dedlfix,

                                      kann ich ein IN nicht zweimal verwenden mit der gleichen Variable?

                                      WHERE status NOT IN ('d9788f30bcf311ed98ef6bd5113784b2', '302fa36fca330e8faf9a5fe9f6ca5637') 
                                                                                       AND bereichSender IN ($empfaengerListe) 
                                                                                       AND bereichEmpfaenger IN ($empfaengerListe)
                                                                                       AND vertraulich = '0' 
                                      
                                                                                       UNION SELECT id, code, kurzbeschreibung, art, erstellungsdatum, job, bereichSender, apSender, bereichEmpfaenger, 
                                                                                                    apEmpfaenger, prio, status, fertigstellung_sender, fertigstellung_uhrzeit_sender,
                                                                                                    fertigstellung_empfaenger, fertigstellung_uhrzeit_empfaenger, beschreibung, vertraulich, ta_titel,
                                                                                                    tp_titel, tp_farbe, ts_id, ts_titel, s.tb_titelkurz as Sender, e.tb_titelkurz as Empfaenger
                                                                                       
                                                                                       FROM todo_grunddaten g                                 
                                                                                       
                                                                                       LEFT JOIN todo_art ON todo_art.ta_code = g.art
                                                                                       LEFT JOIN todo_prio ON todo_prio.tp_code = g.prio
                                                                                       LEFT JOIN todo_status ON todo_status.ts_code = g.status
                                                                                       LEFT JOIN todo_bereich s ON g.bereichSender = s.tb_code
                                                                                       LEFT JOIN todo_bereich e ON g.bereichEmpfaenger = e.tb_code 
                                      
                                                                                       WHERE status NOT IN ('d9788f30bcf311ed98ef6bd5113784b2', '302fa36fca330e8faf9a5fe9f6ca5637')  
                                                                                       AND bereichSender IN ($empfaengerListe) 
                                                                                       AND bereichEmpfaenger IN ($empfaengerListe)
                                                                                       AND vertraulich = '1' 
                                                                                       AND (apSender =? OR apEmpfaenger =?) 
                                                                                       ORDER by erstellungsdatum DESC" );
                                      

                                      Oder lasse ich mich da wieder mit dem AND und OR täuschen.

                                      Bis bald!
                                      Meowsalot (Bernd)

                                      1. Tach!

                                        kann ich ein IN nicht zweimal verwenden mit der gleichen Variable?

                                        PHP-Variablen sind für MySQL nicht weiter relevant. Du erzeugst einen String und erst dieser fertige Wert ist das Statement. Beim Erzeugen von Strings gibt es keine Beschränkungen, welche Variablen und wie oft die verwendet werden können. Wichtig ist nur, dass am Ende ein gültiges SQL-Statement entsteht. Du kannst dieses Statement auch ausgeben lassen, einerseits zwecks Kontrolle, andererseits um es zu kopieren und in Tools wie phpMyAdmin testen zu können, um es ganz unabhängig von deinem PHP-Script zu testen. Lediglich deine Platzhalter-Fragezeichen musst du dann dort mit konkreten Werten füttern.

                                        Oder lasse ich mich da wieder mit dem AND und OR täuschen.

                                        Das musst du mit Logik ergründen, indem du die Antwort auf die Frage findest: Gibt es einen Datensatz, für den alle aufgeführten Bedingungen zutreffen?

                                        dedlfix.

                                        1. Hallo dedlfix,

                                          ich habe es so weit wie möglich gekürzt

                                          WHERE status NOT IN ('d9788f30bcf311ed98ef6bd5113784b2', '302fa36fca330e8faf9a5fe9f6ca5637') 
                                          
                                          AND bereichSender IN ($empfaengerListe) OR bereichEmpfaenger IN ($empfaengerListe)
                                                                                          
                                          ORDER by erstellungsdatum DESC
                                          
                                          

                                          Die Ausgabe läuft zwar Fehlerfrei, aber es werden mir auch Einträge ausgegeben die ich oben im status ausschließe. Kommt die Datenbank mit dem NOT IN und IN nicht zurecht?

                                          Bis bald!
                                          Meowsalot (Bernd)

                                          1. Hallo Meowsalot,

                                            ich habe es so getestet und es hat wieder funktioniert

                                            WHERE status NOT IN ('d9788f30bcf311ed98ef6bd5113784b2', '302fa36fca330e8faf9a5fe9f6ca5637') 
                                                                                            
                                            AND (bereichSender IN ($empfaengerListe) OR bereichEmpfaenger IN ($empfaengerListe))
                                                                                            
                                            ORDER by erstellungsdatum DESC
                                            
                                            

                                            Was bewirkt die () um das AND und OR?

                                            Bis bald!
                                            Meowsalot (Bernd)

                                            1. Tach!

                                              Was bewirkt die () um das AND und OR?

                                              Das übliche: Priorisierung der Teilausdrücke, wie bei Mathe: a * (b + c), damit Punktrechnung nicht vor Strichrechnung ausgeführt wird. Alle Operatoren, auch AND und OR haben einen Platz in der Prioritätenliste. Und wenn man es andere haben möchte, muss man klammern.

                                              dedlfix.

                                              1. Hallo dedlfix,

                                                Danke für die Erklärung.

                                                Bis bald!
                                                Meowsalot (Bernd)

                                          2. Tach!

                                            Die Ausgabe läuft zwar Fehlerfrei, aber es werden mir auch Einträge ausgegeben wie ich oben im status ausschließe. Kommt die Datenbank mit dem NOT IN und IN nicht zurecht?

                                            Doch, aber deine Bedingungen sind dann nicht so, wie du dir das vorstellst. Wenn was nicht auszuführen ginge, gäbe es einen Syntaxfehler.

                                            Dein Statement ist ziemlich komplex geworden. Ich würde es erstmal im phpMyAdmin oder ähnlichen Tools testen. Dazu alles überflüssige wie Joins rauswerfen, die nur für die Ausgabe von Werten zu Fremdschlüsseln vorhanden sind, und die Bedingungen einzeln testen. Dann langsam die anderen Bedingungen wieder hinzufügen und schauen, wie sich das in der jeweiligen Kombination entwickelt.

                                            dedlfix.