Linuchs: mysql_fetch_: Letzte Position erkennen

Moin,

wie kann ich in einer Schleife wie

while ( $row = mysql_fetch_assoc( $res )) { // oder mysql_fetch_array ... // Zeile ausgeben }

die letzte Position erkennen? Ich möchte beim Rückwärts-Seitenwechsel einer Liste auf die letzte Position verlinken, sie soll also eine id bekommen.

Gruß, Linuchs

EDIT: Ich habe ein Beispiel gefunden, in dem man die Sätze mitzählt und mit count() vergleicht. Sieht eher nach Krücke aus, kennt mySQL die Position ihrer eigenen Sätze nicht?

  1. Lieber Linuchs,

    Ich möchte beim Rückwärts-Seitenwechsel einer Liste auf die letzte Position verlinken, sie soll also eine id bekommen.

    Du willst also eine Art Navigation haben, bei der "eine Seite zurück" mit der passenden ID versehen werden soll, damit auf der neuen Seite die korrekten Inhalte ermittelt werden können?

    Warum hast Du keine Gesamtliste aller notwendigen IDs, aus der Du die jeweils notwendigen IDs benutzt?

    Liebe Grüße,

    Felix Riesterer.

    1. Lieber Felix,

      Warum hast Du keine Gesamtliste aller notwendigen IDs, aus der Du die jeweils notwendigen IDs benutzt?

      Frage nicht verstanden. Klar, jeder Satz hat eine id. Aber wenn ich auf Seite 5 einer Liste bin, woher soll ich die letzte id der Seite 4 kennen?

      Und angenommen, ich kentete sie, was wäre, wenn nach stundenlangem Betrachten der Seite 5 genau diese id inzwischen gelöscht wäre?

      Im Moment, in dem ich Seite 4 aufbaue, möchte ich die letzte Zeile kennzeichnen.

      Gruß, Linuchs

      1. Lieber Linuchs,

        Frage nicht verstanden.

        wirklich?

        Aber wenn ich auf Seite 5 einer Liste bin, woher soll ich die letzte id der Seite 4 kennen?

        Indem Du eine Liste aller IDs hast, aus der Du die für Seite 5 benötigten IDs berechnest. Die ID, die vor diesen IDs in der Liste steht, ist die letzte für Seite 4. Oder passt das nicht für Dein Projekt?

        Und angenommen, ich kentete sie,

        Schöne Grammatik! :-)

        was wäre, wenn nach stundenlangem Betrachten der Seite 5 genau diese id inzwischen gelöscht wäre?

        Dann kann Dein Algorithmus in der Liste eben eine ID früher einsteigen. Du wirst ja den Eintrag nicht aus der DB entfernt, sondern nur mit einer Löschmarkierung versehen haben.

        Im Moment, in dem ich Seite 4 aufbaue, möchte ich die letzte Zeile kennzeichnen.

        Schon klar.

        Liebe Grüße,

        Felix Riesterer.

        1. Tach!

          Aber wenn ich auf Seite 5 einer Liste bin, woher soll ich die letzte id der Seite 4 kennen?

          Indem Du eine Liste aller IDs hast, aus der Du die für Seite 5 benötigten IDs berechnest. Die ID, die vor diesen IDs in der Liste steht, ist die letzte für Seite 4.

          IDs sind hier unbrauchbar. Sie müssen nicht fortaufend und ohne Unterbrechung sein, sie können auch in x-beliebiger Reihenfolge vorkommen, wenn die Ergebnismenge nach einem anderen Kriterium sortiert ist. Wie willst du dann fortsetzen? Du musst für die näächste Seite dieselbe Abfrage stellen und dann in der vollständigen Ergebnismenge vorwärts laufen, bis die gesuchte ID auftritt. Eine Bedingung WHERE id kleiner oder größer ist, sentfernt auch diejenigen Datensätze, deren ID größer oder kleiner ist, die aber laut Sortierkrtiterium in der Ergebnismenge weiter vorn oder weiter hinten gelegen hätten.

          Wenn die Wikipedia sortierte Mengen seitenweise präsentiert, dann merkt sie sich nicht die nutzlose Datensatz-ID, sondern den Schlüsselwert (muss unique sein), nach dem sortiert worden ist, und selektiert für die nächste Seite alle Datensätze, deren Wert größer als letzte Wert der vorhergehenden Seite ist. Und das funktioniert dann problemlos, selbst wenn zwischendurch Seiten hinzugekommen oder weggefallen sind. Natürlich sieht man nicht nachträglich weiter vorn eingefügte Seiten, aber man erhält auch keine bereits gesehenen oder übersprungenen am Anfang der Seite, wenn durch das Ändern ein Versatz in der Positionsnummer entstanden ist.

          dedlfix.

          1. Lieber dedlfix,

            IDs sind hier unbrauchbar. Sie müssen nicht fortaufend und ohne Unterbrechung sein, sie können auch in x-beliebiger Reihenfolge vorkommen, wenn die Ergebnismenge nach einem anderen Kriterium sortiert ist. Wie willst du dann fortsetzen?

            ich gehe davon aus, dass es eine Liste aller IDs gibt, in der sie alle auffindbar sind. Dabei spielt es überhaupt keine Rolle, ob die IDs eine fortlaufende Nummerierung oder lustige Namen-Strings sind. Allein ihre Position in der Liste ist das Kriterium, um eine Paginierung davon abzuleiten.

            Aber ich gebe Dir insofern natürlich Recht, dass bei einer Art Paginierung ein Zählwert viel Sinnvoller ist, als eine ID, wenn man einen Link gestalten will.

            Liebe Grüße,

            Felix Riesterer.

            1. Tach!

              ich gehe davon aus, dass es eine Liste aller IDs gibt, in der sie alle auffindbar sind. Dabei spielt es überhaupt keine Rolle, ob die IDs eine fortlaufende Nummerierung oder lustige Namen-Strings sind. Allein ihre Position in der Liste ist das Kriterium, um eine Paginierung davon abzuleiten.

              Datensätze anhand der Position in der Ergebnismenge zu beschränken, ist bereits mit LIMIT problemarm möglich. Ohne LIMIT müsste man händisch die komplette vorhergehende Ergebnismenge durchzählen, um die Fortsetzung zu ermitteln. Das ist ein unverhältnismäßiger Aufwand, weil man das mit einer Stored Procedure serverseitig oder mit einer komplett zum Client übertragenenen Datenmenge machen müsste. LIMIT ist normalerweise das Mittel der Wahl zum seitenweisen Abfragen. Natürlich mit den Nachteilen, wenn Datensätze hinzugefügt oder entfernt werden, während man blättert.

              Um übrigens die Gesamtanzahl der unLIMITierten Menge zu bekommen, kann man FOUND_ROWS() zusammen mit SQL_CALC_FOUND_ROWS verwenden. Das braucht man, um die Seitennummernanzeige für die Page-Links berechnen zu können.

              dedlfix.

    2. Du willst also eine Art Navigation haben, bei der "eine Seite zurück" mit der passenden ID versehen werden soll, damit auf der neuen Seite die korrekten Inhalte ermittelt werden können?

      Nein. "eine Seite zurück" bedeutet die Angabe einer Seitenzahl.

      Welche Sätze es dann sind, ergibt sich aus der Positions-Anzahl der Liste (die als Parameter variabel sein kann).

      Beispiel: Seite 4 auf einer Liste mit 25 Positionen bedeutet LIMIT 75,25

      Gruß, Linuchs

  2. Tach!

    wie kann ich in einer Schleife wie

    while ( $row = mysql_fetch_assoc( $res )) { // oder mysql_fetch_array ... // Zeile ausgeben }

    die letzte Position erkennen?

    Wenn du das nicht anhand der Daten erkennen kannst, sehe ich keine direkte Möglichkeit. mysql_fetch_assoc() liefert erst dann etwas unterscheidbares, wenn es keinen Datensatz mehr liefern kann, also wenn es bereits hinter dem letzten Datensatz ist.

    Lass die Ergebnisse zuerst in ein Array laufen, das kann man besser auf solche Gegebenhaiten wie Anfang und Ende untersuchen, weil vom Array bereits die Gesamtanzahl der Elemente bekannt ist.

    Außerdem sind PHP-Versionen, in denen mysql-ohne-i-Funktionen laufen, klinisch tot.

    dedlfix.

  3. Erstmal das:

    Warnung Diese Erweiterung ist seit PHP 5.5.0 als veraltet markiert und wurde in PHP 7.0.0 entfernt.

    wie kann ich in einer Schleife wie

    while ( $row = mysql_fetch_assoc( $res )) { // oder mysql_fetch_array ... // Zeile ausgeben }

    die letzte Position erkennen?

    mysqli_num_rows liefert die Anzahl der Datensätze. Das tat auch mysql_num_rows. Du könntest also mitzählen. Stellt sich die Frage wozu das gut sein soll, denn…

    Nach dem vollständigen Durchlauf der Schleife steht in $row immer der letzte Datensatz. Soll heißen, Dein Problem existiert eigentlich gar nicht.

    Folgende Nachrichten verweisen auf diesen Beitrag:

    1. Tach!

      Nach dem vollständigen Durchlauf der Schleife steht in $row immer der letzte Datensatz. Soll heißen, Dein Problem existiert eigentlich gar nicht.

      Nein, da steht ein false drin, sonst könnte while nicht bremsen.

      dedlfix.

      1. Tach!

        Nach dem vollständigen Durchlauf der Schleife steht in $row immer der letzte Datensatz. Soll heißen, Dein Problem existiert eigentlich gar nicht.

        Nein, da steht ein false drin, sonst könnte while nicht bremsen.

        Stimmt. Du hast Recht. Lösung:

        while ( $row = ) { $lastRow = $row; }

        Dann stehts in $lastRow.

        2. Lösung: Man kann auch mitzählen. mysql[i]_nun_rows liefert ja die Anzahl der "Ergebniszeilen" und dann:

        $c = 0; # $l = mysql_num_rows( $result ); $l = $result->num_rows; while ( $row = ) { $c++; if ( $l == $c ) { $lastRow = $row; } }

        bei vielen/großen Feldern (Spalten) im Resultset könnte das Mitzählen billiger sein als das die Übernahme in eine weitere Variable.

        3. Lösung:

        Die abgefragten Datensätze enthalten womöglich eine ID oder eine unique Spalte, nach der laut Abfrage auch sortiert ist. Einfach merken, was bei mysqli_fetch_assoc rauskommt.

        while ($row = $result->fetch_assoc()) { $lastId = $row['ID']; }
        1. Tach!

          Stimmt. Du hast Recht. Lösung:

          Ich hätte eine bessere im Angebot: Endlich mysql zugunsten von mysqli begraben, dann gibt es mysqli_fetch_all(), das ohne weitere Schleife gleich ein Array liefert. - Ich weiß, großes Projekt, macht viel Arbeit, das alles umzustellen. Aber ewig mit dem bereits seit langem abgekündigten Altmetall zu arbeiten, macht es auch nicht besser. Andererseits die Ergebnismengendaten in ein Array zu fetchen ist auch keine Raketenwissenschaft.

          dedlfix.

          1. Tach!

            Stimmt. Du hast Recht. Lösung:

            Ich hätte eine bessere im Angebot: Endlich mysql zugunsten von mysqli begraben

            Nun, das hatte ich dem @Linuchs auch nahe gelegt. Wenn er schon daran fummelt, dann kann und sollte er auch modernisieren, damit die Chose morgen noch läuft. Hier mal ein Mail meines Hosters:

            im April 2019 werden wir beginnen, unsere Webserver auf eine neue Linux-Distribution zu aktualisieren, um auch weiterhin den höchsten Sicherheitsstandards und Performance-Ansprüchen genügen zu können. Aufgrund von Inkompatibilitäten zwischen älteren PHP-Versionen und den von der Distribution bereitgestellten aktuellen Versionen von Standard-Softwarebibliotheken wie OpenSSL können wir auf der neuen Webserver-Plattform nur PHP-Versionen ab 5.6 anbieten.

            Damit ist das alte Mysql-Zeug tot.

            1. Ich hätte eine bessere im Angebot: Endlich mysql zugunsten von mysqli begraben

              Nun, das hatte ich dem @Linuchs auch nahe gelegt. Wenn er schon daran fummelt, dann kann und sollte er auch modernisieren, damit die Chose morgen noch läuft.

              Naja ... wahrscheinlich knallt es dann irgendwo im Gestrüpp der include. Wer kann mir eine kompakte Einführung für sqli nennen? Ich könnte wohl anfangen bei den Mini-Programmen, die auf Ajax-Anfragen reagieren.

              MySQL-Vers.=[10.1.37-MariaDB-0+deb9u1], [] PHP-Vers.=[5.6.40-0+deb8u1]

              Als ich im Jahr 2001 mit PHP und mySQL begann, musste ich mächtig zurückschrauben, hatte vorher im großen Team professionell mit ORACLE und SAP-Schnittstellen gearbeitet. mySQL war irgendwie ein kostenloses "Spielzeug" auf Kleinstrechnern, wo ich mich heute noch wundere, dass es so oft funktioniert ;-)

              In meiner erzwungenen Bescheidenheit habe ich dann wohl einige Neuerungen verpasst, etwa die VIEWs. Die ältesten (und vergessenen) noch laufenden Programme treffe ich manchmal als Ergebnisse in Suchmaschinen.

              1. Die Hilfe steht so nahe: SelfHTML→Wiki→PHP→Tutorials: Umstieg von MySQL auf MySQLi oder PDO

              2. Tach!

                Wer kann mir eine kompakte Einführung für sqli nennen?

                Das PHP-Handbuch kann. mysqli kommt in zwei Varianten, als Funktion (procedural style) oder in OOP. PDO gibt es auch noch, aber nur in OOP. Es ist was eigenständiges und obwohl konzeptionell nicht grundlegend anders, doch mit deutlichen Unterschieden zu den mysql(i)-Funktionen behaftet. Für den einfachen Umstieg nimm also mysqli und da die Funktionen. Meist beschränkt es sich darauf, ein i einzufügen und die Parameter umzudrehen. Die Verbindungskennung war bisher meist am Ende und oft optional. Sie ist nun der erste Parameter und damit Pflicht. Der Rest ist größtenteils gleich, gelegntlich aber auch erweitert worden. Das PHP-Handbuch klärt auf über die Funktionsweise der neuen Funktionen auf. Zu den alten mysql-Funktionen ist meist ein Link zum i-Äquivalent im Handbuch zu finden.

                dedlfix.

  4. Tach!

    EDIT: Ich habe ein Beispiel gefunden, in dem man die Sätze mitzählt und mit count() vergleicht. Sieht eher nach Krücke aus, kennt mySQL die Position ihrer eigenen Sätze nicht?

    Es gibt keine Positionsangabe in der Ergebnismenge. Eine Ergebnismenge hat nichts mit der Reihenfolge in der Tabelle zu tun, sondern hängt neben einschränkenden Bedingungen im WHERE und anderen SQL-Konstrukten nicht zuletzt auch vom Sortierkriterium ab.

    Du kannst aber LIMIT verwenden, solange die Querys ansonsten gleich bleiben. Gegen das zeitliche Problem, dass zwischen zwei Abfragen sich die Menge geändert haben kann, kannst du nichts weiter tun, solange du nicht mit einem eingefrorenen Snapshot arbeitest.

    dedlfix.

    1. Es gibt keine Positionsangabe in der Ergebnismenge.

      Doch! Ich kann doch mit data_seek eine bestimmte Position ansteuern und ab da weiterlesen.

      mySQL kennt also ihren Pointer im result genau. Aber verrät ihn nicht?

      1. Tach!

        Es gibt keine Positionsangabe in der Ergebnismenge.

        Doch! Ich kann doch mit data_seek eine bestimmte Position ansteuern und ab da weiterlesen.

        mySQL kennt also ihren Pointer im result genau. Aber verrät ihn nicht?

        Nicht MySQL kennt die Zahl. Du musst dazu wissen, dass PHP bereits mit der mysql_query()-Funktion die Ergebnismenge zum Client holt. Ein Fetchen greift nur noch auf die bereits abgeholte Menge zu und macht nicht jedes Mal ein Daten-Holen vom Server. Nur so ist es möglich, zum Beispiel sofort ein mysql_num_rows() ausführen zu können, weil der Client bereits die Menge der Datensätze kennt. Ohne dieses Hintergrund-Fetchen wäre die Anzahl erst nach vollständigem Fetchen bekannt.

        Wenn du vorwärts und rückwärts blättern möchtest, nimm LIMIT und FOUND_ROWS() nebst SQL_CALC_FOUND_ROWS. Das ist die übliche Vorgehensweise, wenn zwischenzeitliche Änderungen am Datenbestand keine Berücksichtigung finden sollen. Man muss dabei auch nicht mitzählen, wieviele Datensätze man schon gefetcht/angezeigt hat. Das geht auch ohne und ist relativ einfache Mathematik. Sowas ist seit langem bekannt und Tutorials dazu gibt es garantiert.

        dedlfix.

        1. Nicht MySQL kennt die Zahl.

          Na gut, dann PHP, verrät aber auch nichts zur Position in einer Fundmenge?

          Wenn du vorwärts und rückwärts blättern möchtest, nimm LIMIT und FOUND_ROWS() nebst SQL_CALC_FOUND_ROWS.

          Nutze ich seit Jahren.

          1. Tach!

            Na gut, dann PHP, verrät aber auch nichts zur Position in einer Fundmenge?

            Nicht das ich wüsste. Aber ich schätze, dass du diese Information eigentlich auch nicht brauchst, und es für das eigentliche Problem eine bessere Lösung gibt, die das Problem mit der Positionsnumer gleich gar nicht hat.

            dedlfix.

  5. ich kann doch in der Ergebnismenge mit mysqli_data_seek auf einen Satz der Fundmenge positionieren.

    Aber wie kann ich diesen Pointer abfragen, der ja mit while weitergeschaltet wird.

    1. Tach!

      ich kann doch in der Ergebnismenge mit mysqli_data_seek auf einen Satz der Fundmenge positionieren.

      Aber wie kann ich diesen Pointer abfragen, der ja mit while weitergeschaltet wird.

      Der nützt dir nichts, wenn du die nächste Seite einer bereits seitens des DBMS limitierten Ergebnismenge abfragst. Das ist lediglich ein PHP-interner Zeiger auf diese vom DBMS bereits erhaltene Ergebnismenge, der für das DBMS bedeutungslos ist. Du kannst da beispielsweise Werte von 0 bis 9 bei 10 Ergebnissen pro Seite als $row_number übergeben und bei der nächsten Seite wieder dieselben Zahlen.

      dedlfix.

  6. Moin,

    wenn Du die Ergebnismenge als Array anfordern tätest, gäbe es eine Funktion end() welche Dir das letzte Element liefern würde. Idee!