Meowsalot: Einträge auslesen

Hallo,

mit diesem Script lese ich meine Termine aus einer MySQL Datenbank aus. Im Feld sort_datum steht z.B. 2018-07-30

Jetzt möchte ich gerne alle Termine ausgelesen haben die im Monat 07 im Jahr 2018 stattfinden bzw. diesen Wert steht in meiner URL ?ym=2018-07 und die größer/gleich heute sind.

Ist dieses möglich ohne das Datum auseinander zu nehmen? Hat MySQL dafür eine Funktion?

$stmt = $mysqli->prepare( "
     
     SELECT id, code, status, titel, von, bis 
     FROM projekte 
     WHERE id NOT IN (" . $empfaengerListe . ") 
     AND status IN (" . $status . ") 
     AND sort_datum > NOW()  
     ORDER by sort_datum ASC");

Bis bald! Meowsalot (Bernd)

  1. Lieber Meowsalot,

    Jetzt möchte ich gerne alle Termine ausgelesen haben die im Monat 07 im Jahr 2018 stattfinden bzw. diesen Wert steht in meiner URL ?ym=2018-07 und die größer/gleich heute sind.

    das bedeutet, dass die Termine zwischen Monatsanfang (2018-07-01) und Monatsende (2018-07-31) liegen müssen - und mit einem Datum, welches größer gleich des heutigen ist.

    SELECT *
    FROM projekte
    WHERE sort_datum BETWEEN '2018-07-01' AND '2018-07-31'
     AND sort_datum >= NOW()
    

    Liebe Grüße,

    Felix Riesterer.

    1. (Ergänzend: Man kann jetzt nicht einfach die 31 als letzten Tag nehmen. Sonst kommt womöglich auch der 3. März, in Schaltjahren nämlich nur der zweite. Oder gar nichts.)

      Das Manual hilft.

      SELECT *
      FROM projekte
      WHERE sort_datum BETWEEN '2018-07-01' AND LAST_DAY('2018-07-01')
       AND sort_datum >= NOW()
      
    2. Lieber Felix,

      danke für deine Antwort

      das bedeutet, dass die Termine zwischen Monatsanfang (2018-07-01) und Monatsende (2018-07-31) liegen müssen - und mit einem Datum, welches größer gleich des heutigen ist.

      SELECT *
      FROM projekte
      WHERE sort_datum BETWEEN '2018-07-01' AND '2018-07-31'
       AND sort_datum >= NOW()
      

      BETWEEN und AND war mir fast klar. Allerdings möchte ich das Datum automatisch einfügen lassen je nachdem was in der URL steht. In diesem Beispiel ?ym=2018-07

      Kann ich nicht irgenwie sagen schau alle Einträge an wo im Feld sort_datu das Jahr 2018 und der Monat 07 steht?

      Bis bald!
      Meowsalot (Bernd)

      1. Kann ich nicht irgenwie sagen schau alle Einträge an wo im Feld sort_datu das Jahr 2018 und der Monat 07 steht?

        Können kannst Du das schon, aber müssen und sollen sollst und musst Du nicht.

  2. Hallo,

    Jetzt möchte ich gerne alle Termine ausgelesen haben die im Monat 07 im Jahr 2018 stattfinden bzw. diesen Wert steht in meiner URL ?ym=2018-07 und die größer/gleich heute sind.

    Klause auf Monat AND Date >= NOW();

    MfG

  3. Moin Meowsalot,

    Jetzt möchte ich gerne alle Termine ausgelesen haben die im Monat 07 im Jahr 2018 stattfinden bzw. diesen Wert steht in meiner URL ?ym=2018-07 und die größer/gleich heute sind.

    Vielleicht helfen dir die Funktionen MONTH und YEAR weiter.

    Ist dieses möglich ohne das Datum auseinander zu nehmen? Hat MySQL dafür eine Funktion?

    Nein, du müsstest dafür 2018-07 in zwei Werte, einen für das Jahr 2018 und für den Monat 07 zerlegen.

    Viele Grüße
    Robert

    1. Vielleicht helfen dir die Funktionen MONTH und YEAR weiter.

      • Ja. Weil es im Prinzip geht.
      • Nein, weil es zu einem vermeidbaren Fulltablescan führt.
      SELECT *
      FROM projekte
      WHERE MONTH(sort_datum) = 7 
       AND YEAR(sort_datum) = 2018
       AND sort_datum >= NOW()
      

      Da kann man auch gleich den Index weglassen oder eine Textdatei nehmen...

      1. Vielleicht helfen dir die Funktionen MONTH und YEAR weiter.

        • Ja. Weil es im Prinzip geht.
        • Nein, weil es zu einem vermeidbaren Fulltablescan führt.
        SELECT *
        FROM projekte
        WHERE MONTH(sort_datum) = 7 
         AND YEAR(sort_datum) = 2018
         AND sort_datum >= NOW()
        

        Da kann man auch gleich den Index weglassen oder eine Textdatei nehmen...

        Auf welchem Feld hast Du denn einen Index? Doch sicher auf dem Feld mit dem Datum.. also ich kenne das DB Design nicht.

        Ansonsten kann man die Abfrage auch so formulieren: Zeige alle Termine die für einen bestimmten Monat noch in der Zukunft liegen -- da ist die Klause schon passend. Also anders geht das gar nicht -- Mit oder ohne Index.

        MfG

        1. Hallo pl,

          Auf welchem Feld hast Du denn einen Index? Doch sicher auf dem Feld mit dem Datum.. also ich kenne das DB Design nicht.

          wenn ich ehrlich bin auf gar keinem Feld. Ist dieses denn wichtig?

          Bis bald!
          Meowsalot (Bernd)

          1. Auf welchem Feld hast Du denn einen Index? Doch sicher auf dem Feld mit dem Datum.. also ich kenne das DB Design nicht.

            wenn ich ehrlich bin auf gar keinem Feld. Ist dieses denn wichtig?

            Bei nur zwei Testeinträgen in Deiner Datenbank noch nicht. Sind es dann mal irgendwann 10.000 Einträge Genauer: Deine Tabelle wird größer als 2 Prozent des database block buffer) loggst Du Dich im Forum ein und fragst, warum denn wohl die Antwort des Servers so irre lange brauche oder kündigst beim Hoster um beim neuen zu erleben, dass es da - ohne Index - auch nicht besser geht.

            Wenn Du mehr wissen willst, dann schreib mal einer mysql-Konsole das schöne Wort "explain" vor Deine Abfragen und werte die Rückgaben aus.

          2. Hallo pl,

            Auf welchem Feld hast Du denn einen Index? Doch sicher auf dem Feld mit dem Datum.. also ich kenne das DB Design nicht.

            wenn ich ehrlich bin auf gar keinem Feld. Ist dieses denn wichtig?

            Ein Index spielt hauptsächlich in der WHERE Klause eine Rolle hinsichtlich Performance. MySQL explain einem SELECT vorangestellt erklärt Dir welche Index greifen. So kannst Du Abfragen optimieren infolge gezielter Indizierung.

            Einfach mal machen, es ist so kompliziert nun auch wieder nicht. Ein Index greift nicht, wenn eine Abfrage dazu führt, daß jeder Eintrag gelesen bzw. die ganze Tabelle durchlaufen werden muss.

            MfG

        2. Also anders geht das gar nicht -- Mit oder ohne Index.

          Im Hinblick auf die in meiner Antwort verlinkte Lösung ist das, mit allem Verlaub, eine sehr mutige Behauptung.

          1. Also anders geht das gar nicht -- Mit oder ohne Index.

            Im Hinblick auf die in meiner Antwort verlinkte Lösung ist das, mit allem Verlaub, eine sehr mutige Behauptung.

            Was heißt hier mutig? Wenn eine Klause auf Monat und Jahr liegt, muss schonmal gar nicht die ganze Tabelle durchlaufen werden: Genau da greift nämlich der Index -- Falls vorhanden.

            MfG

            1. Also anders geht das gar nicht -- Mit oder ohne Index.

              Im Hinblick auf die in meiner Antwort verlinkte Lösung ist das, mit allem Verlaub, eine sehr mutige Behauptung.

              Was heißt hier mutig?

              Naja. Das es anders geht wurde ja kurz vorher gezeigt. Da ist es durchaus "mutig" zu behaupten, dass es anders nicht gehe. Du hattest hatte ja auch deutlich auf MONTH() Bezug genommen, also auf die Variante, die ich nicht grundlos als "bad" markiert habe.

              Genau da greift nämlich der Index -- Falls vorhanden.

              DEDLFIX hat gerade erst so schön erklärt, dass bei

              MONTH(sort_datum) = 7 
               AND YEAR(sort_datum) = 2018
              

              die Indizes nicht greifen können und deshalb die einmalige Operation mit

              BETWEEN '2018-07-01' AND LAST_DAY('2018-07-01')
              

              vorzuziehen ist.

              Ansonsten kommt mir es mir vor, als versuche @Meowsalot mit einem Q8 eine Damenhandtasche in den Gassen der Innenstadt von Siena auszuliefern: Viele PS, viel umbauter Raum, viel Schnickschnack - aber er muss den Fußgängern im Schrittempo hinterherschleichen, bei jedem Abbiegen braucht er einen Einweiser und rempelt trotzdem an den Ecken an. Und: Bei Gegenverkehr geht gar nichts mehr.

              Was @Meowsalot erreichen will geht, zumindest mit den zu erwartenden, geringen Datenmengen, mit Textdateien viel einfacher. Und sehr performant: Der Typ mit der Vespa schlägt den Q8 beim Transport von Damenhandtaschen in der Innenstadt von Siena nämlich um Längen.

            2. Tach!

              Wenn eine Klause auf Monat und Jahr liegt, muss schonmal gar nicht die ganze Tabelle durchlaufen werden: Genau da greift nämlich der Index -- Falls vorhanden.

              Kann ich nicht nachvollziehen. Ich hab eine Testdatenbank genommen. Ein Index auf employees.birth_date war nicht vorhanden, den habe ich vor dem Test hinzugefügt. Das Ergebnis sagt, dass kein nutzbarer Key für die Query mit YEAR() verwendet werden konnte (MONTH() hab ich mir gespart). Beim BETWEEN hingegen konnte der Index jedoch verwendet werden.

              EXPLAIN SELECT * FROM `employees` WHERE YEAR(`birth_date`)=1960
              

              id|select_type|table|type|possible_keys|key|key_len|ref|rows|Extra 1|SIMPLE|employees|ALL|NULL|NULL|NULL|NULL|299348|Using where

              EXPLAIN SELECT * FROM `employees` WHERE `birth_date` BETWEEN '1960-01-01' AND '1960-12-31'
              

              id|select_type|table|type|possible_keys|key|key_len|ref|rows|Extra 1|SIMPLE|employees|range|birth_date|birth_date|3|NULL|47684|Using index condition

              dedlfix.

      2. Tach!

        Noch ein bisschen generelle Erläuterung dazu. Wenn man auf einen Wert in einem Feld nicht direkt zugreifen kann, sondern erst eine Funktion aufrufen muss, um den gewünschten Teilwert zu erhalten, erzeugt das meistens einen Full-Table-Scan. Das ist nicht weiter tragisch, wenn man nur wenige Datensätze hat. "Viel" fängt mit heutiger Rechenleistung aber auch meist erst bei 6- bis 7-stelligen Mengen an. Man muss es aber trotzdem nicht auf einen Full-Table-Scan ankommen lassen. Generell gilt, dass Felder, in denen (besonders häufig) gesucht wird, einen Index bekommen sollen. Damit der Index aber genutzt werden kann, muss die Bedingung eingehalten werden, dass man direkt darin nachschlagen kann, ohne zu rechnen.

        Bei Datumsgeschichten kann man auch in der Query selbst rechnen, dann aber im feststehenden Teil. Das heißt, beispielsweise mit der Nutzereingabe, aber nicht mit dem Feld. Um Daten eines Monats zu berücksichtigen also nicht Jahr und Monat aus dem Feld extrahieren, sondern Anfang und Ende des gesuchten Zeitraums errechnen. Das muss das DBMS lediglich einmal tun, denn die Nutzereingabe ändert sich ja im Verlaufe der Statement-Abarbeitung nicht. Nun kann das DBMS mit dem Feld beziehungsweise dessen Index über einfache Vergleichsoperationen auf das Einhalten dieser Grenzen prüfen.

        dedlfix.

        1. "Viel" fängt mit heutiger Rechenleistung aber auch meist erst bei 6- bis 7-stelligen Mengen an

          Nun ja, im Hinblick darauf, dass Massenhoster zwar (meistens) relativ leistungsfähige Datenbankserver haben - in denen dann aber Massen an Datenbanken bearbeitet werden, kann man nicht davon ausgehen, dass ausgerechnet die abgefragte Datenbank im Cache - die Abfrage und deren Antwort gar im Abfrage-Cache ist. Zudem sind die Server durch genug Programmierer, die da denken "Index anlegen? Das macht nur Arbeit - und man kann da sogar was falsch machen!" recht ordentlich ausgelastet.

          Und deshalb geht es mit den slow-queries auf solchen gut bestückten, aber eben auch ausgelasteten Datenbankservern durchaus "etwas" früher los als auf einer Maschine mit 64 GB Speicher und nur dieser einen Datenbank.