Sophie: Nach Datum filtern

Guten Morgen,

warum wird das bis ignoriert?

$stmt = $mysqli->prepare($select . " WHERE datum >= ? AND datum <= ? " );
$stmt->bind_param("ss", $datum_von, $datum_bis);

Mein Feld in der Datenbank ist vom Typ "Date". Sehr ihr den Fehler?

  1. Hello,

    warum wird das bis ignoriert?

    $stmt = $mysqli->prepare($select . " WHERE datum >= ? AND datum <= ? " );
    $stmt->bind_param("ss", $datum_von, $datum_bis);
    

    Mein Feld in der Datenbank ist vom Typ "Date". Sehr ihr den Fehler?

    Und wie sind die Daten formatiert? Bitte mit var_dump() ausgeben lassen.

    if (DEBUG) { var_dump($datum_von); var_dump($datum_bis); }

    Das DEBUG kannst Du z.B. in deiner Virtual-Hosts-Umgebung setzen ...

    Für die Range-Abfrage kennt mysql between.

    Liebe Grüße
    Tom S.

    --
    Es gibt nichts Gutes, außer man tut es
    Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
    1. Hall TS,

      danke für den Link. Schade dass es dort keine vernünftige Beispiele gibt.

      EDIT: Hab hier etwas gefunden: https://www.tutorialspoint.com/mysql/mysql-between-clause.htm Das between kommt nach dem WHERE

      1. Hello,

        danke für den Link. Schade dass es dort keine vernünftige Beispiele gibt.

        entscheidend ist wohl der Zusatz, der auch für deinen Vergleich wichtig ist!:

        For best results when using BETWEEN with date or time values, use CAST() to explicitly convert the values to the desired data type. Examples: If you compare a DATETIME to two DATE values, convert the DATE values to DATETIME values. If you use a string constant such as '2001-1-1' in a comparison to a DATE, cast the string to a DATE. 
        

        EDIT: Hab hier etwas gefunden: https://www.tutorialspoint.com/mysql/mysql-between-clause.htm Das between kommt nach dem WHERE

        Liebe Grüße
        Tom S.

        --
        Es gibt nichts Gutes, außer man tut es
        Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
        1. Hallo TS,

          ich habe es jetzt so umgesetzt wie ich es verstanden habe

          $stmt = $mysqli->prepare($select . " WHERE datum BETWEEN ? AND ? " );
          

          Das bis wird weiterhin nicht beachtet. Sage ich vom 01.08.2017 - 10.08.2017 dann kommt ein Eintrag vom 01.08.2017. Obwohl für den 10.08.2017 zwei Einträge in der Datenbank sind.

          1. Hello,

            ich habe es jetzt so umgesetzt wie ich es verstanden habe

            $stmt = $mysqli->prepare($select . " BETWEEN datum ? AND datum ? " );
            

            Das bis wird weiterhin nicht beachtet. Sage ich vom 01.08.2017 - 10.08.2017 dann kommt ein Eintrag vom 01.08.2017. Obwohl für den 10.08.2017 zwei Einträge in der Datenbank sind.

            Hatte ich Dich eigentlich schon gebeten, deine beiden Vergleichswerte mal mit var_dump() auszugeben? Dazu gehört selbstverständlich auch, uns die Ausgaben mitzuteilen.

            Die Datenbank verlangt für einen sinnvollen Vergleich auch ein bestimmtes (sinnvolles) Format für die Übergabewerte. Das muss man entweder vorher herstellen, oder aber versuchen, es von der Datenbank herstellen zu lassen.

            Da die Prepared Statements mit Rohdaten arbeiten (es ist keine interpretierende rtextschnittstelle mehr dazwischen), empfiehlt es sich, das Format selber vorher richtigzustellen.

            Liebe Grüße
            Tom S.

            --
            Es gibt nichts Gutes, außer man tut es
            Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
            1. Hallo TS,

              Hatte ich Dich eigentlich schon gebeten, deine beiden Vergleichswerte mal mit var_dump()

              wenn ich mir

              echo $datum_von;
              echo $datum_bis;
              

              ausgeben lasse, dann erhalte ich genau dieses Format, welches ich auch benötige:

              2017-08-01
              2017-08-10
              
              1. Hello,

                wenn ich mir

                echo $datum_von;
                echo $datum_bis;
                

                ausgeben lasse, dann erhalte ich genau dieses Format, welches ich auch benötige:

                2017-08-01
                2017-08-10
                

                Und was kommt mit var_dump()?

                Ich hatte nicht sinnlos nach var_dump() gefragt.
                Echo würde Zahlenwerte klaglos in ausgabefähige Strings umwandeln, ohne dass Du das merkst.

                Liebe Grüße
                Tom S.

                --
                Es gibt nichts Gutes, außer man tut es
                Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
                1. Hallo TS,

                  bitteschön:

                  string(10) "2017-08-01" string(10) "2017-08-10"
                  
                  1. Hello,

                    bitteschön:

                    string(10) "2017-08-01" string(10) "2017-08-10"
                    

                    Danke. Nun wird es wirklich rätselhaft und ein Fall für die Glaskugel.

                    Was könntest Du sonst noch versuchen, um den Fehler zu finden?
                    Du könntest im Select mal nach "= '2017-08-10'" fragen. Wenn dann die zwei Zeilen in der Ergebnismenge drin sind, wird es mystisch.

                    Liebe Grüße
                    Tom S.

                    --
                    Es gibt nichts Gutes, außer man tut es
                    Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
                    1. Hallo TS,

                      wenn ich folgendes ausführen lasse

                      $stmt = $mysqli->prepare($select . " WHERE datum BETWEEN '2017-08-01' AND '2017-08-10' " );
                      

                      wird mit dennoch der 11.08.2017 und 13.08.2017 mit ausgegeben. Dürfte doch eigentlich nicht sein?

                      1. Hallo,

                        wenn ich die Abfrage im phpMyAdmin ausführe, dann erhalte ich die richtige Datensätze. Also kann es nur an meiner Abfrage liegen?

                        SELECT * FROM `zeiterfassung` WHERE `datum` BETWEEN '2017-08-01' AND '2017-08-10'
                        

                        Zeige Datensätze 0 - 1 (2 insgesamt, Die Abfrage dauerte 0.0002 Sekunden.)

                        1. Hello,

                          wenn ich die Abfrage im phpMyAdmin ausführe, dann erhalte ich die richtige Datensätze. Also kann es nur an meiner Abfrage liegen?

                          SELECT * FROM `zeiterfassung` WHERE `datum` BETWEEN '2017-08-01' AND '2017-08-10'
                          

                          Zeige Datensätze 0 - 1 (2 insgesamt, Die Abfrage dauerte 0.0002 Sekunden.)

                          Auf dieselbe Tabelle?

                          Sonst könnte es auch sein, dass der Index kaputt ist.
                          Entweder "REINDEX" oder einfach Index löschen und neu anlegen.

                          Hast Du in deinem PHP-Programm die Kodierung richtig vereinbart? UND benutzen die Datenbank und das PHP-Skript dieselbe Kodierung?

                          Liebe Grüße
                          Tom S.

                          --
                          Es gibt nichts Gutes, außer man tut es
                          Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
                          1. Tach!

                            Sonst könnte es auch sein, dass der Index kaputt ist.

                            Pferde vor der Apotheke, aber das wird es nicht sein. Wenn dieselbe Query in verschiedenen Umgebungen unterschiedliche Ergebnisse liefert, könnte es auch daran liegen, dass diese auch auf verschiedene Datenquellen schauen.

                            Hast Du in deinem PHP-Programm die Kodierung richtig vereinbart? UND benutzen die Datenbank und das PHP-Skript dieselbe Kodierung?

                            Extrem unwahrscheinlich als Ursache. Da müsste schon eine nicht auf ASCII basierende Kodierung im Spiel sein.

                            dedlfix.

                          2. Hallo TS,

                            folgendes habe ich jetzt getestet

                            $stmt = $mysqli->prepare($select . " WHERE datum =?" );
                            

                            Wenn ich jetzt nach einem Datum suche z.B. den 10.08.2017 wird dieses auch gefunden.

                            $stmt = $mysqli->prepare($select . " WHERE datum <=?" );
                            

                            Auch dieses funktioniert.

                            Mache ich jetzt eine Kombination

                            $stmt = $mysqli->prepare($select . " WHERE datum BETWEEN ? AND ? " );
                            

                            Dann wird das End-Datum nicht berücksichtigt.

                            1. Guten Morgen,

                              hat keiner eine Idee, warum bei mir das Beteen nicht funktioniert? Habe ich vielleicht noch eine andere Möglichkeit?

                              1. Guten Morgen,

                                ich habe den Fehler gefunden. Ich habe eine Funktion ist wie folgt aufgebaut ist:

                                function zeiterfassung($mysqli, $name=false, $projektnummer=false, 
                                                                $datum_von=false, $datum_bis=false) {
                                        
                                       $select = "SELECT id, projektnummer, name, datum, anzStunden, 
                                                  FROM zeiterfassung";
                                        
                                        if ($projektnummer != false && $name != false) {
                                
                                                $param = '%'.$projektnummer.'%';
                                                
                                                $stmt = $mysqli->prepare($select . " WHERE projektnummer Like ? AND name=?" );
                                                $stmt->bind_param("ss", $param, $name);
                                                
                                        } elseif ($projektnummer != false) {
                                
                                                $param = '%'.$projektnummer.'%';
                                                
                                                $stmt = $mysqli->prepare($select . " WHERE projektnummer Like ?" );
                                                $stmt->bind_param("s", $param);
                                                
                                        } elseif ($name != false) {
                                                
                                                $stmt = $mysqli->prepare($select . " WHERE name =?" );
                                                $stmt->bind_param("s", $name);
                                
                                        } elseif ($datum_von != false) {
                                                
                                                $stmt = $mysqli->prepare($select . " WHERE datum =?" );
                                                $stmt->bind_param("s", $datum_von);
                                                
                                        } elseif ($datum_bis != false) {
                                                
                                                $stmt = $mysqli->prepare($select . " WHERE datum <=?" );
                                                $stmt->bind_param("s", $datum_bis);
                                                
                                        } elseif ($datum_von != false && $datum_bis != false) {
                                                
                                                $stmt = $mysqli->prepare($select . " WHERE datum BETWEEN ? AND ? " );
                                                $stmt->bind_param("ss", $datum_von, $datum_bis);
                                
                                        } else {
                                            $stmt = $mysqli->prepare($select);
                                        }
                                

                                Wenn ich diese so nutze, geht mein Between in der letzten Zeile nicht. Jetzt habe ich zum Teste die Funktion etwas gekürzt

                                function zeiterfassung($mysqli, $name=false, $projektnummer=false, 
                                                                $datum_von=false, $datum_bis=false) {
                                        
                                       $select = "SELECT id, projektnummer, name, datum, anzStunden, 
                                                  FROM zeiterfassung";
                                        
                                        if ($datum_von != false && $datum_bis != false) {
                                                
                                                $stmt = $mysqli->prepare($select . " WHERE datum BETWEEN ? AND ? " );
                                                $stmt->bind_param("ss", $datum_von, $datum_bis);
                                
                                        } else {
                                            $stmt = $mysqli->prepare($select);
                                        }
                                

                                Und siehe da, mein BETWEEN funktioniert. Aber warum? Was stimmt denn mit dem IF Bereich nicht?

                                1. Hallo,

                                  Was stimmt denn mit dem IF Bereich nicht?

                                  Die Reihenfolge.

                                  Gruß
                                  Kalk

                                  1. Hallo,

                                    danke für den Tipp. Ich habe es jetzt so geändert es funktioniert zwar, bin mir aber nicht sicher ob es richtig ist:

                                    function zeiterfassung($mysqli, $name=false, $projektnummer=false, 
                                                                    $datum_von=false, $datum_bis=false) {
                                            
                                           $select = "SELECT id, projektnummer, name, datum, anzStunden, 
                                                      FROM zeiterfassung";
                                            
                                            if ($projektnummer != false && $name != false) {
                                    
                                                    $param = '%'.$projektnummer.'%';
                                                    
                                                    $stmt = $mysqli->prepare($select . " WHERE projektnummer Like ? AND name=?" );
                                                    $stmt->bind_param("ss", $param, $name);
                                                    
                                            } elseif ($projektnummer != false) {
                                    
                                                    $param = '%'.$projektnummer.'%';
                                                    
                                                    $stmt = $mysqli->prepare($select . " WHERE projektnummer Like ?" );
                                                    $stmt->bind_param("s", $param);
                                                    
                                            } elseif ($name != false) {
                                                    
                                                    $stmt = $mysqli->prepare($select . " WHERE name =?" );
                                                    $stmt->bind_param("s", $name);
                                    
                                            } elseif ($datum_von != false) {
                                                    
                                                    $stmt = $mysqli->prepare($select . " WHERE datum =?" );
                                                    $stmt->bind_param("s", $datum_von);
                                                    
                                            } elseif ($datum_bis != false) {
                                                    
                                                    $stmt = $mysqli->prepare($select . " WHERE datum <=?" );
                                                    $stmt->bind_param("s", $datum_bis);
                                                    
                                            } else {
                                                $stmt = $mysqli->prepare($select);
                                            }
                                    
                                            if ($datum_von != false && $datum_bis != false) {
                                                    
                                                    $stmt = $mysqli->prepare($select . " WHERE datum BETWEEN ? AND ? " );
                                                    $stmt->bind_param("ss", $datum_von, $datum_bis);
                                    
                                            }
                                    
                                    1. Hallo,

                                      danke für den Tipp. Ich habe es jetzt so geändert es funktioniert zwar, bin mir aber nicht sicher ob es richtig ist:

                                      ich bin mir da auch nicht sicher, dadurch dass du die Between-Abfrage jetzt in ein einzelnes If gesteckt hast, überschreibst du das Selectstatement, das evtl. vorher schon gesetzt war. Du solltest weg vom Computer, Zettel&Stift nehmen und dir genau überlegen, welche Fälle vorkommen können sollen und dir einen Plan machen!

                                      Gruß
                                      Kalk

                                    2. Hallo Sophie,

                                      Der else mit dem einsamen prepare ist bestimmt nicht richtig.

                                      Schau dir an, wie du den Bereich projektnummer/name gelöst hast, da bist du richtig vorgegangen. Mach es mit den Datümern genauso, dann klappt das auch.

                                      Dass eine Angabe von Name oder Projektnummer den Datumfilter verhindert, ist dir klar?

                                      Rolf

                                      --
                                      Dosen sind silbern
                      2. Hello,

                        wenn ich folgendes ausführen lasse

                        $stmt = $mysqli->prepare($select . " WHERE datum BETWEEN '2017-08-01' AND '2017-08-10' " );
                        

                        wird mit dennoch der 11.08.2017 und 13.08.2017 mit ausgegeben. Dürfte doch eigentlich nicht sein?

                        Doch, bei BETWEEN gehören die Grenzen immer dazu. Da müsstest Du ggf. entweder die Werte verändern, z. B. mit date_add() oder adddate() oder doch wieder dein > und < benutzen.

                        Oder du manipulierst das Datum mittels PHP. Kommt immer darauf an, wie streng gekapselt die Abfrage werden muss.

                        Liebe Grüße
                        Tom S.

                        --
                        Es gibt nichts Gutes, außer man tut es
                        Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
                        1. Hallo,

                          Doch, bei BETWEEN gehören die Grenzen immer dazu. Da müsstest Du ggf. entweder die Werte verändern, z. B. mit date_add() oder adddate() oder doch wieder dein > und < benutzen.

                          wenn ich

                          $stmt = $mysqli->prepare($select . " WHERE datum BETWEEN '2017-08-01' AND '2017-08-10' " );
                          

                          dann ist doch die Grenze der 10.08.2017 und nicht der 13.08.2017?