Bruzzler: Fehler bei Datenbankabfrage (Date Problem?)

Hallo, ich habe in meinem PHP Script folgende Abfrage:

$sql = "SELECT user_id,f_name,l_name,email,date,MAX(date) as datemax,MIN(date) as datemin FROM wp_fsq_data
	  WHERE datemax BETWEEN '" . date('Y-m-d', strtotime('-28 days')) . "'
      AND '" . date('Y-m-d', strtotime('-13 days')) . "' GROUP BY user_id ORDER BY datemax";

Wenn ich diese Abfrage in meiner Datenbank beispielhaft ausführe mit


SELECT user_id,f_name,l_name,email,date,MAX(date) as datemax,MIN(date) as datemin
FROM wp_fsq_data WHERE datemax BETWEEN '2015-02-23 15:02:15' AND '2015-02-21 15:02:15'
GROUP BY user_id ORDER BY datemax

bekomme ich den Fehler: #1054 - Unknown column 'datemax' in 'where clause'

Wenn ich den "Where"-Teil weglasse, funktioniert die Abfrage. Das date-Feld in der DB ist vom Typ datetime und wird so gespeichert: 0000-00-00 00:00:00

Was mache ich denn falsch? Danke und Grüße

  1. Tach!

    SELECT user_id,f_name,l_name,email,date,MAX(date) as datemax,MIN(date) as datemin
    
    > FROM wp_fsq_data WHERE datemax BETWEEN '2015-02-23 15:02:15' AND '2015-02-21 15:02:15'
    > GROUP BY user_id ORDER BY datemax
    
    

    bekomme ich den Fehler: #1054 - Unknown column 'datemax' in 'where clause'

    Die Abarbeitungsreihenfolge der Klauseln ist: FROM (mit Joins), WHERE, GROUP BY, jetzt erst kommt das SELECT, ORDER BY, LIMIT. Das WHERE hat keine Ahnung von den Aliasnamen im SELECT. Sie können dort nicht verwendet werden. Du kannst dich da nur auf den Feldnamen beziehen. (Aliasnamen von Tabellen können angegeben werden, weil FROM ja schon behandelt wurde.)

    Ich denke, eine Subquery, die zuerst gruppiert und die Max-/Min-Werte ermittelt, und das WHERE in der äußeren Query ist zielführend.

    Das date-Feld in der DB ist vom Typ datetime und wird so gespeichert: 0000-00-00 00:00:00

    Wohl eher nicht. Wie es gespeichert wird, ist nicht relevant. Das was du da zeigst ist das Aus- und Eingabeformat. Für den Programmierer ist nur wichtig, ob das Feld ein Datums- (und Zeit-)Typ ist oder ein String-Typ. Auf erstere kann man eine Vielzahl Datums- und Zeit-Funktionen anwenden, auf Strings nicht.

    Was mache ich denn falsch?

    Außer dem genannten Punkten verwendest du noch jede Menge Felder im Select, die nicht im Group-By aufgeführt sind. MySQL lässt zwar sowas zu, nimmt aber dann irgendwelche Feldinhalte aus der Gruppe der Datensätze. Das kann zu unerwünschten Ergebnissen führen. Lediglich Aggregatfunktionen (MIN, MAX, SUM, ...) können gefahrlos andere Felder verwenden.

    dedlfix.

    1. Hallo,

      Die Abarbeitungsreihenfolge der Klauseln ist: FROM (mit Joins), WHERE, GROUP BY, jetzt erst kommt das SELECT, ORDER BY, LIMIT. Das WHERE hat keine Ahnung von den Aliasnamen im SELECT. Sie können dort nicht verwendet werden. Du kannst dich da nur auf den Feldnamen beziehen. (Aliasnamen von Tabellen können angegeben werden, weil FROM ja schon behandelt wurde.)

      Ich möchte hier ergänzen, dass man sich mal mit HAVING beschäftigen kann:

      SELECT   city.location_name,    city.lat,     city.lon,    ROUND(   (acos(sin(radians(city.lat)) * sin(radians(56.0)) +    cos(radians(city.lat)) * cos(radians(56.0)) *  cos(radians(18.0) -                  (radians(city.lon)))) * 6380), 1) AS linear_distance   FROM            city HAVING linear_distance <=  10000 ORDER BY linear_distance

      Viele Grüße Siri

      1. Tach!

        Die Abarbeitungsreihenfolge der Klauseln ist: FROM (mit Joins), WHERE, GROUP BY, jetzt erst kommt das SELECT, ORDER BY, LIMIT. Das WHERE hat keine Ahnung von den Aliasnamen im SELECT. Sie können dort nicht verwendet werden. Du kannst dich da nur auf den Feldnamen beziehen. (Aliasnamen von Tabellen können angegeben werden, weil FROM ja schon behandelt wurde.)

        Ich möchte hier ergänzen, dass man sich mal mit HAVING beschäftigen kann:

        Ja, das ist ein guter Hinweis. Das HAVING kommt zwischen SELECT und ORDER BY, somit kann es auf Aliasnamen und auf Ergebnisse von im Select notierten Ausdrücken zugreifen.

        dedlfix.

      2. Liebe Mitdenker, liebe Wissende, liebe Neugierige,

        ja!

        Ich möchte hier ergänzen, dass man sich mal mit HAVING beschäftigen kann:

        SELECT   city.location_name,    city.lat,     city.lon,    ROUND(   (acos(sin(radians(city.lat)) * sin(radians(56.0)) +    cos(radians(city.lat)) * cos(radians(56.0)) *  cos(radians(18.0) -                  (radians(city.lon)))) * 6380),

        1. AS linear_distance   FROM            city HAVING linear_distance <=  10000 ORDER BY linear_distance

        Und ich möchte nochmals erwähnen, dass man hier zunächst erst einmal als Subselect eine "Quadratabfrage" auf die große Menge durchführen sollte, für die nur einfache Vergleiche notwendig sind.

        Und im zweiten Schritt sollte man die gelieferte (kleine) Menge dann erst mit Sin() und Cos() & Co filtern.

        Das kann dank Subselect selbstverständlich auch in einer SQL-Abfrage stattfinden.

        Das rechnet sich spätestens, wenn die Anzahl der Datensätze in der Tabelle die 10.000 (oder 50.000, ...) überschreitet.

        Spirituelle Grüße Euer Robert

        --
        Möge der Forumsgeist wiederbelebt werden!
    2. Hi dedlfix,

      danke für deine Antwort. Und wenn ich das Datum in Unix Timestamps ausgebe? Warum kann die Where Abfrage hier nicht "subtrahieren" bzw. größer / kleiner erkennen?

      $sql = "SELECT user_id,f_name,l_name,email,date,UNIX_TIMESTAMP( NOW( ) ) - UNIX_TIMESTAMP( MAX( date ) ) AS diff
      FROM wp_fsq_data WHERE 'diff' < 1209600
      GROUP BY user_id
      

      Hier werden mir wieder alle ausgegeben

      Danke und Grüße

      1. Tach!

        Und wenn ich das Datum in Unix Timestamps ausgebe? Warum kann die Where Abfrage hier nicht "subtrahieren" bzw. größer / kleiner erkennen?

        WHERE kann das. Aber nicht mit Aliasnamen oder Ergebnissen von Berechnungen aus dem SELECT, weil SELECT erst nach dem WHERE ausgeführt wird und diese Ergebnisse und Aliasnamen noch gar nicht vorliegen.

        $sql = "SELECT user_id,f_name,l_name,email,date,UNIX_TIMESTAMP( NOW( ) ) - UNIX_TIMESTAMP( MAX( date ) ) AS diff
        
        > FROM wp_fsq_data WHERE 'diff' < 1209600
        > GROUP BY user_id
        
        

        Hier werden mir wieder alle ausgegeben

        'diff' ist ein String. Der wird im numerischen Kontext zu 0 und 0 ist kleiner als 1209600. Die Bedingung ist stets erfüllt.

        Backticks statt einfache Anführungszeichen lösen das Problem nicht, weil es grundsätzlich nicht auf diesem Wege lösbar ist. Siehe oben.

        dedlfix.

        1. Tach!

          Und wenn ich das Datum in Unix Timestamps ausgebe? Warum kann die Where Abfrage hier nicht "subtrahieren" bzw. größer / kleiner erkennen?

          WHERE kann das. Aber nicht mit Aliasnamen oder Ergebnissen von Berechnungen aus dem SELECT, weil SELECT erst nach dem WHERE ausgeführt wird und diese Ergebnisse und Aliasnamen noch gar nicht vorliegen.

          $sql = "SELECT user_id,f_name,l_name,email,date,UNIX_TIMESTAMP( NOW( ) ) - UNIX_TIMESTAMP( MAX( date ) ) AS diff
          
          > > FROM wp_fsq_data WHERE 'diff' < 1209600
          > > GROUP BY user_id
          
          

          Hier werden mir wieder alle ausgegeben

          'diff' ist ein String. Der wird im numerischen Kontext zu 0 und 0 ist kleiner als 1209600. Die Bedingung ist stets erfüllt.

          Backticks statt einfache Anführungszeichen lösen das Problem nicht, weil es grundsätzlich nicht auf diesem Wege lösbar ist. Siehe oben.

          dedlfix.

          Ich komm hier einfach nicht weiter. Acuh wenn ich

          
          
          SELECT user_id,f_name,l_name,email,date FROM wp_fsq_data
          WHERE  date = (SELECT MAX(date) BETWEEN '2015-02-21 15:02:15' AND '2015-02-23 15:02:15' FROM wp_fsq_data)
          GROUP BY user_id
          
          

          ausführe kriege ich kein Resultat. Hat jemand für mich ein konkretes Beispiel, wie die Abfrage funktionieren könnte? Danke vielmals !

          1. Ich komm hier einfach nicht weiter. Acuh wenn ich

            
            
            > 
            > SELECT user_id,f_name,l_name,email,date FROM wp_fsq_data
            > WHERE  date = (SELECT MAX(date) BETWEEN '2015-02-21 15:02:15' AND '2015-02-23 15:02:15' FROM wp_fsq_data)
            > GROUP BY user_id
            > 
            
            

            ausführe kriege ich kein Resultat.

            Hallo,

            wie mein Beispiel gezeigt hat, kann HAVING im Gegensatz zu WHERE mit einem Alias auf eine Tabellenspalte umgehen. Warum setzt du nicht dort an? Außerdem würde ich Roberts Hinweis aufnehmen um eventuelle Fehler durch 'date' auszuschließen.

            Viele Grüße Siri

            1. Ich komm hier einfach nicht weiter. Acuh wenn ich

              
              
              > > 
              > > SELECT user_id,f_name,l_name,email,date FROM wp_fsq_data
              > > WHERE  date = (SELECT MAX(date) BETWEEN '2015-02-21 15:02:15' AND '2015-02-23 15:02:15' FROM wp_fsq_data)
              > > GROUP BY user_id
              > > 
              
              

              ausführe kriege ich kein Resultat.

              Hallo,

              wie mein Beispiel gezeigt hat, kann HAVING im Gegensatz zu WHERE mit einem Alias auf eine Tabellenspalte umgehen. Warum setzt du nicht dort an? Außerdem würde ich Roberts Hinweis aufnehmen um eventuelle Fehler durch 'date' auszuschließen.

              Viele Grüße Siri

              Habe ich:

              SELECT `user_id`,`f_name`,`l_name`,`email`,`date`,MAX(`date`) as datemax,MIN(`date`) as datemin
              FROM `wp_fsq_data` GROUP BY `user_id` HAVING `datemax` BETWEEN '2015-02-23 15:02:15' AND '2015-02-21 15:02:15' ORDER BY `datemax`
              

              --> Kein Resultat

              1. Tach!

                Habe ich:

                SELECT `user_id`,`f_name`,`l_name`,`email`,`date`,MAX(`date`) as datemax,MIN(`date`) as datemin
                
                > FROM `wp_fsq_data` GROUP BY `user_id` HAVING `datemax` BETWEEN '2015-02-23 15:02:15' AND '2015-02-21 15:02:15' ORDER BY `datemax`
                
                

                --> Kein Resultat

                Arbeite dich schrittweise an die Ursache ran. Zuerst mal das HAVING raus. Gibt das die gewünschte (noch uneingeschränkte) Ergebnismenge?

                dedlfix.

                1. Tach!

                  Habe ich:

                  SELECT `user_id`,`f_name`,`l_name`,`email`,`date`,MAX(`date`) as datemax,MIN(`date`) as datemin
                  
                  > > FROM `wp_fsq_data` GROUP BY `user_id` HAVING `datemax` BETWEEN '2015-02-23 15:02:15' AND '2015-02-21 15:02:15' ORDER BY `datemax`
                  
                  

                  --> Kein Resultat

                  Arbeite dich schrittweise an die Ursache ran. Zuerst mal das HAVING raus. Gibt das die gewünschte (noch uneingeschränkte) Ergebnismenge?

                  dedlfix.

                  Ja, durch

                  SELECT `user_id`,`f_name`,`l_name`,`email`,`date`,MAX(`date`) as datemax,MIN(`date`) as datemin
                  FROM `wp_fsq_data` GROUP BY `user_id` ORDER BY `datemax`
                  

                  erhalte ich die uneingeschränkte Menge, gruppiert nach user_id

                  1. Tach!

                    Arbeite dich schrittweise an die Ursache ran. Zuerst mal das HAVING raus. Gibt das die gewünschte (noch uneingeschränkte) Ergebnismenge? Ja, durch [...] erhalte ich die uneingeschränkte Menge, gruppiert nach user_id

                    Und da sind auch Datensätze dabei, die auf das Kriterium passen? Du kannst ja mal die Datümer im BETWEEN in die richtige Reihenfolge bringen, erst das kleine, dann das große.

                    dedlfix.

                    1. Tach!

                      Arbeite dich schrittweise an die Ursache ran. Zuerst mal das HAVING raus. Gibt das die gewünschte (noch uneingeschränkte) Ergebnismenge? Ja, durch [...] erhalte ich die uneingeschränkte Menge, gruppiert nach user_id

                      Und da sind auch Datensätze dabei, die auf das Kriterium passen? Du kannst ja mal die Datümer im BETWEEN in die richtige Reihenfolge bringen, erst das kleine, dann das große.

                      dedlfix.

                      DANKE!!!!!!!!!!! Die Reihenfolge wars!!! Vielen lieben Dank

  2. Hallo,

    Wenn ich diese Abfrage in meiner Datenbank beispielhaft ausführe mit

    
    
    > SELECT user_id,f_name,l_name,email,date,MAX(date) as datemax,MIN(date) as datemin
    > FROM wp_fsq_data WHERE datemax BETWEEN '2015-02-23 15:02:15' AND '2015-02-21 15:02:15'
    > GROUP BY user_id ORDER BY datemax
    > 
    
    

    bekomme ich den Fehler: #1054 - Unknown column 'datemax' in 'where clause'

    Max(date) liefert das höchste Datum über alle Datensätze und damit genau einen Datensatz. Willst du das überhaupt?

    Viele Grüße Siri

    1. Tach!

      Max(date) liefert das höchste Datum über alle Datensätze und damit genau einen Datensatz. Willst du das überhaupt?

      Das Ergebnis ist ein Datensatz je Gruppe, nicht nur einer für die gesamte Tabelle. So wie die Query jetzt aufgebaut ist, sollen wohl nur die Gruppen berücksichtigt werden, deren Max-Datum im angegebenen Zeitraum liegt.

      dedlfix.

    2. Hallo,

      Wenn ich diese Abfrage in meiner Datenbank beispielhaft ausführe mit

      
      
      > > SELECT user_id,f_name,l_name,email,date,MAX(date) as datemax,MIN(date) as datemin
      > > FROM wp_fsq_data WHERE datemax BETWEEN '2015-02-23 15:02:15' AND '2015-02-21 15:02:15'
      > > GROUP BY user_id ORDER BY datemax
      > > 
      
      

      bekomme ich den Fehler: #1054 - Unknown column 'datemax' in 'where clause'

      Max(date) liefert das höchste Datum über alle Datensätze und damit genau einen Datensatz. Willst du das überhaupt?

      Viele Grüße Siri

      Ja, genau das will ich. Ich möchte diejenigen User haben, deren höchstes Datum älter als 14 Tage ist, und jeden User natürlich nur einmal.

  3. Liebe Mitdenker, liebe Wissende, liebe Neugierige,

    ja!

    $sql = "SELECT user_id,f_name,l_name,email,date,MAX(date) as datemax,MIN(date) as datemin FROM wp_fsq_data
    
    > 	  WHERE datemax BETWEEN '" . date('Y-m-d', strtotime('-28 days')) . "'
    >       AND '" . date('Y-m-d', strtotime('-13 days')) . "' GROUP BY user_id ORDER BY datemax";
    
    

    bekomme ich den Fehler: #1054 - Unknown column 'datemax' in 'where clause'

    Klar, denn unbechtet der anderen Fehler ist "date" ein Schküsselwort in MySQL http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html

    folglich weiß MySQL spätetens an der Stelle ",date, MAX(date)" nichts mehr damit anzufangen. Um derartige Verwechselungen von Spaltennamen mit Schlüselwörtern zu vermeiden, kann man Spaltenamen in MySQL daher mit Backticks maskieren

    Spirituelle Grüße Euer Robert

    --
    Möge der Forumsgeist wiederbelebt werden!
    1. Hallo,

      Klar, denn unbechtet der anderen Fehler ist "date" ein Schküsselwort in MySQL http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html

      sicher? Ich lese (MySQL permits some keywords to be used as unquoted identifiers because many people previously used them.) da was anderes.

      Gruß Kalk

    2. Hallo,

      Klar, denn unbechtet der anderen Fehler ist "date" ein Schküsselwort in MySQL http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html

      folglich weiß MySQL spätetens an der Stelle ",date, MAX(date)" nichts mehr damit anzufangen. Um derartige Verwechselungen von Spaltennamen mit Schlüselwörtern zu vermeiden, kann man Spaltenamen in MySQL daher mit Backticks maskieren

      IMHO machen  den Backticks Code unübersichtlicher. In jedem Fall sind passende Spaltennamen wie z.B. "last_activity_date" die bessere Lösung.

      Viele Grüße Siri

      1. Liebe Mitdenker, liebe Wissende, liebe Neugierige,

        ja!

        IMHO machen  den Backticks Code unübersichtlicher. In jedem Fall sind passende Spaltennamen wie z.B. "last_activity_date" die bessere Lösung.

        Man sollte immer die höchstmögliche Sicherheit für die Datenintegrität wählen. Die Backticks sind zwar nicht schön und auch MySQL-eigen (andere DMBS machen das anders), aber sie verhindern Störungen des Querystrings durch versehentliche Nutzung von reservierten Bezeichnern.

        Darüberhinaus sollte man Spaltenbezeichner natürlich so wählen, dass sie eben diese reservierten Bezeichner nicht treffen. Wer garantiert aber, dass in einer späteren MySQL-Version kein reserviertes Wort hinzukommt, dass dann plötzlich mit den Spaltenbezeichnern kollidiert?

        Hier waren es auch nicht die reservierten Bezeichner, wie schon jemand anderes schrieb, sondern es wären Funktionsnamen gewesen. Allerdings hätte es so sein können.

        Für einen Funktionsnamen fehlte ein Funktionsargument. Allerdings bin ich leider nicht ganz sicher bin, ob Funktionsnamen immer sauber an den Klammern erkannt werden können...

        Spirituelle Grüße Euer Robert

        --
        Möge der Forumsgeist wiederbelebt werden!
        1. Tach!

          Für einen Funktionsnamen fehlte ein Funktionsargument. Allerdings bin ich leider nicht ganz sicher bin, ob Funktionsnamen immer sauber an den Klammern erkannt werden können...

          Es gibt keine Referenzen auf Funktionen in MySQL. Funktionen werden immer nur aufgerufen (abgesehen von der Erstellung benutzerdefinierter Funktionen) und dabei sind die Klammern Pflicht. Es gibt aber einige Konstanten im Date/Time-Bereich, die denselben Namen haben wie Funktionen (und dasselbe Ergebnis).

          dedlfix.