Thomas Schmieder: MySQL: Workaround für NEXT und PREVIOUS gesucht

Hallo Gemeinde,

ich bin hier am abko...

...chen von Teewasser. Denn man sagt ja, anwarten und Tee trinken.

Ich suche die beste Lösung für  Next und Previous

Szenario:
MySQL-Tabelle mit Adressen. Adresse wird gelesen und angezeigt. Nun will ich die nächste in Reihe. Solange die Sortierung auf der ID steht, ist das kein Problem,

Select * from adresse where ID > '$ID' Limit 1

Oder man versucht eben mit ID='$ID' zuzugreifen. Wenn der Satz gelöscht ist, muss man das eben sooft wiederholen, bis ein Ergebnis dabei herauskommt.

Nun das Problem:
Ich möchte die Adressen z.B. nach dem Nachnamen sortiert anzeigen. Nachnamen können aber Duplicates haben. Da würde ich mit der Abfrage

Select * from adresse where NACHNAME >= ($NACHNAME) Limit 1,1

nicht vom Fleck kommen, wenn da fünf Meyers in der Tabelle sind. Außerdem könnte mir in der Zwischenzeit jemand den ersten Meyer geklaut haben, dann stimmt das Ergebnis auch nicht mehr.

Was tun???

Wieso gibt es in SQL keine Abfrage auf NEXT und PREVIOUS? Habe ich da was übersehen? Jede vernünfte DBE hat sowas. Da kann ich mit dem Schlüssel des vorhandenen Satzes und der Angabe der gewünschten Sortierung einsteigen und den Nachfolger oder Vorgänger suchen lassen.

Gruß

Tom

  1. Moin!

    Szenario:
    MySQL-Tabelle mit Adressen. Adresse wird gelesen und angezeigt. Nun will ich die nächste in Reihe. Solange die Sortierung auf der ID steht, ist das kein Problem,

    Select * from adresse where ID > '$ID' Limit 1

    Ich will dich ja nicht verunsichern, aber in diesem SQL-Statement wird nichts sortiert, sondern die Daten kommen so, wie sie gerade bunt von der Datenbank gefunden und ausgegeben werden, heraus. Durch den geschickten Einsatz von WHERE und LIMIT entsteht vielleicht der Eindruck, es würde sortiert - wird es aber nicht.

    Und wenn nicht sortiert wird, dann kann es auch keinen vorhergehenden und nächsten Datensatz im Sinne der Sortierung geben.

    Also Schritt 1: Sortieren. In SQL auch 'ORDER BY spaltenname' genannt. Wenn du nach ID sortieren willst, tu das bitte. ORDER BY ID. Wenn du nach Nachnamen sortieren willst: ORDER BY nachname. Nur damit hast du eine sortierte Ausgabe.

    Und dann kommt Schritt 2: Du willst nicht alle Einträge der Datenbank haben, sondern nur einn paar bis hin zu nur einem einzigen. Und du willst blättern. Das Einschränken der Datensätze hast du schon fast ganz herausgefunden: LIMIT. Bedenke, daß LIMIT auch zwei Parameter annehmen kann! Entweder hast du LIMIT x, dann steht x für die Anzahl der Datensätze, die du haben willst. Oder du hast LIMIT x,y, dann steht x für den x.ten Datensatz in der unlimitierten Liste (Offset), der als erstes ausgegeben wird, und y für die Anzahl der Datensätze, die du haben willst.

    Entsprechend mußt du nicht die WHERE-Bedingung ändern, sondern nur am LIMIT rumschrauben und stückweise die gesamte Datenbankausgabe abfragen, indem du das LIMIT veränderst.

    Und dadurch verschwinden alle deine Probleme:

    Nun das Problem:
    Ich möchte die Adressen z.B. nach dem Nachnamen sortiert anzeigen. Nachnamen können aber Duplicates haben.

    Außerdem könnte mir in der Zwischenzeit jemand den ersten Meyer geklaut haben, dann stimmt das Ergebnis auch nicht mehr.

    Dagegen kann keiner was tun, du erhälst dann unter Umständen verfälschte  Ergebnisse, weil zwischendurch Daten gelöscht wurden.

    - Sven Rautenberg

    1. MySQL-Tabelle mit Adressen. Adresse wird gelesen und angezeigt. Nun will ich die nächste in Reihe. Solange die Sortierung auf der ID steht, ist das kein Problem,

      Select * from adresse where ID > '$ID' Limit 1

      Ich will dich ja nicht verunsichern, aber in diesem SQL-Statement wird nichts sortiert, sondern die Daten kommen so, wie sie gerade bunt von der Datenbank gefunden und ausgegeben werden, heraus. Durch den geschickten Einsatz von WHERE und LIMIT entsteht vielleicht der Eindruck, es würde sortiert - wird es aber nicht.

      Hallo Sven,

      ich hätte natürlich dazuschreiben sollen, dass ID der Primary Key der Tabelle ist. Auf Primary Keys liegt auch bei MySQL immer ein Unique Index, der automatisch verwendet wird, wenn das Feld angesprochen wird. Einzige Ausnahme: order by rand()
      Dann bekommt man tatsächlich zufällig herausgepickte Datensätze.

      Bei einem "normalen" Textfeld sieht das eben anders aus, weil man hier Duplicate-Management berücksichtigen muss. Ich denke, ich werde diese Aufwendige Prozedur vor mir haben. Es werden also ALLE Datensätze ins Resultset geholt werden müssen, die dem Gleichheitskriterium genügen. Die werden sortiert nach der ID. Müssten sie automatisch sein, wenn man nichts anderes angibt, habe ich aber mit so vielen Daten noch nicht probiert. Dann kann man sich in dem Resultset mit "Limit 1,x" bewegen. Für den Fall, das die untere oder die obere Grenze sich seit dem letzten Aufruf verschoben haben, muss man eben neu synchronisieren. Der Schritt zum nächst größeren oder kleineren Wert ist dagegen einfach. Da hilft wieder "Limit 1".

      Ganz schöner Aufwand, nur weil die bei MySQL so puristisch sind, und keine Befehle für Next oder Previous eingebaut haben. Werde ich doch mal vorschlagen. Aber heute Abend nicht mehr. Jetzt bin ich zu müde..

      Vielen Dank, dass Ihr Euch für mich Zeit genommen habt. Vielleicht fällt ja noch jemand was ein.

      Gute Nacht wünscht

      Tom

      1. Moin!

        ich hätte natürlich dazuschreiben sollen, dass ID der Primary Key der Tabelle ist. Auf Primary Keys liegt auch bei MySQL immer ein Unique Index, der automatisch verwendet wird, wenn das Feld angesprochen wird. Einzige Ausnahme: order by rand()

        Egal wie deine ID gestaltet ist: Wenn du ein simples "SELECT * FROM tabelle" machst, kriegst du eine zufällige Ordnung. Das wird durch den Zusatz "WHERE ID > $ID" nicht besser. Im letzten Schritt begrenzt du die Ausgabe dann auf einen Eintrag. Bei dem ist aber auch nur sichergestellt, daß dessen ID größer ist als die derzeit dem Skript bekannte ID. Du hast _keine_ Garantie, daß es die nächsthöhere ID ist.

        Bei einem "normalen" Textfeld sieht das eben anders aus, weil man hier Duplicate-Management berücksichtigen muss.

        Wenn die Datenbank sortiert, wird sie immer zum gleichen Ergebnis kommen. Entsprechend kannst du mit "LIMIT x,y" einen Ausschnitt dieser definierten Liste ansprechen (auch einen einzigen Eintrag).

        Ganz schöner Aufwand, nur weil die bei MySQL so puristisch sind, und keine Befehle für Next oder Previous eingebaut haben. Werde ich doch mal vorschlagen. Aber heute Abend nicht mehr. Jetzt bin ich zu müde..

        Hm, ich habe von angeblichen SQL-Kommandos wie "NEXT" und "PREVIOUS" noch nichts gehört. Auch eine kurze Suche bei Google hat nichts ergeben. Kann es sein, daß du dir da was ausdenkst, was es garnicht geben kann. Würde ich mal vermuten, wenn ich deine Idee mit meinen Kenntnissen über SQL-Datenbanken im allgemeinen und mySQL im speziellen vergleiche.

        - Sven Rautenberg

        1. Hallo Sven, hallo Forum,

          nachdem die Diskussion ja doch etwas angeregter wurde will ich hier wenigstens auch noch das Ergebnis verkünden.

          Die Lösung lautet, im Beispiel mit meiner Kundendatenbank ausprobiert:

          für PREVIOUS:

          Select Kunde, ID from kontakte where ID < 19 order by kunde,id Desc limit 1

          für NEXT:

          Select Kunde, ID from kontakte where ID > 19 order by kunde,id  limit 1

          wobei die 19 für den aktuellen Datensatz steht. Das minimiert die zu haltenden Daten auf die ID und die Order, hier sortiert nach Kunde und Subset ID

          Diese zwei Werte wird man dann wohl im Form halten können, sodass sessionübergreifend gestept werden kann. Da hat ja CK so drauf rumgeritten, obwohl ich gar nicht verlangt hatte, dass irgendwo Zeiger oder ähnliches gehalten werden.

          Bei ca. 1.500.000 Datensätzen kann man nur nicht jedesmal ein vollständiges Resultset anfordern, oder?

          Noch zur Sortierung:
          MySQL sortiert das Subset solange nach der ID, wie die Tabelle "noch neu" ist, das heißt, keine Datensätze gelöscht wurden. Die leeren Plätze werden dann nämlich beim nächsten Insert wieder aufgefüllt. Die Anzeige findet also tatsächlich nach Order und B+Tree-Struktur statt. Gut dass Sven nochmal darauf aufmerksam gemacht hat.

          Die Befehle NEXT(ID,Order) und PREV(ID,Order) gibt es in vielen Client-Server-Datenbanken. Durch puristische SQL-DML-Schnittstellen gehen die dann verloren. Die DBEs können das, aber man kommt dann nicht mehr ran. Bei Informix kann man die DML-Schnittstelle austauschen und sein eigenes "SQL" ranbaumeln. dann wäre das machbar.

          Ich muss dann noch einen Performance-Test machen, ob das bei mehr als 10.000 Datensätzen (mehr hatte ich ben nicht zur Verfügung) auch noch funxt oder aber in die Knie geht.

          Nun ist aber Schluß für gestern.

          Grüße

          Tom

          1. Yo, Tom!

            für PREVIOUS:

            Select Kunde, ID from kontakte where ID < 19 order by kunde,id Desc limit 1

            für NEXT:

            Select Kunde, ID from kontakte where ID > 19 order by kunde,id  limit 1

            wobei die 19 für den aktuellen Datensatz steht. Das minimiert die zu haltenden Daten auf die ID und die Order, hier sortiert nach Kunde und Subset ID

            Tja, die Frage ist nur, ob dir das wirklich weiterhilft. Ich denke, du kriegst auf diese Weise es zwar in den Griff, nacheinander die IDs durchzukaspern, aber nicht, so nacheinander die Namen durchzukaspern.

            Zuerst ganz kritisch angucken würde ich die Reihenfolge der Sortierung. Denn es wird zuerst nach Namen sortiert, dann nach IDs. Du kannst also dadurch folgenden Fall erhalten (je nachdem, in welcher Reihenfolge die Namen eingetragen wurden!):

            ID   Name
            3    Meier
            4    Meier
            1    Müller
            5    Müller
            2    Walther

            Sortiert nach Namen und dann nach IDs.

            Angenommen, du bist jetzt bei der ID 4 - Dann wäre der nächste Datensatz die ID 1. Du selektierst aber nur die IDs, die größer als die 4 sind, also ID 5. Damit fällt der Müller/ID 1 aus deiner Liste heraus.

            Ich verstehe nicht, wieso du nicht in der Lage bist, einfach einen Datensatzzeiger zu erfinden, der vollkommen unabhängig von irgendwelchen IDs ist, und einfach nur auf das derzeit angezeigte Ergebnis der sortierten Tabelle aus der Datenbank zeigt.

            Dieser Datensatzzeiger ist genauso aufwendig, wie deine ID, nur kann man durch simple Addition oder Subtraktion von 1 den vorhergehenden oder nächsten Datensatz erhalten, ohne mit IDs, der Datenbanksortierung etc. ins Gehege zu kommen.

            Du fragst also immer schön die Datenbank ab mit deinem Query, und die Einschränkung durch LIMIT kommt von außen herein, ohne auf Datenbankdaten zu beruhen.

            Damit bist du dann verantwortlich, diesen Datensatzzeiger in der Session zu behalten, und nicht die Datenbank.

            Im Prinzip ist an deinen Funktionen garnichts zu ändern - außer daß sie intern umgestrickt werden müßten, um nicht mehr auf ID-Basis zu arbeiten, sondern diesen Datensatzzeiger zu benutzen.

            Diese zwei Werte wird man dann wohl im Form halten können, sodass sessionübergreifend gestept werden kann. Da hat ja CK so drauf rumgeritten, obwohl ich gar nicht verlangt hatte, dass irgendwo Zeiger oder ähnliches gehalten werden.

            Bei ca. 1.500.000 Datensätzen kann man nur nicht jedesmal ein vollständiges Resultset anfordern, oder?

            Wenn du "WHERE ID > 19" abfragst und 1,5 Mio Datensätze hast, dann werden 1,499981 Mio Datensätze in eine Tabelle gelegt, dann sortiert nach Name und ID, und dann gekürzt auf einen Eintrag. Anders ist ein korrektes Ergebnis doch garnicht hinzukriegen. Das wird nur performant, wenn du Indices in der Tabelle benutzt. Es vermeidet aber garnichts. Das könntest du nur, wenn dir exakt die nachfolgende ID bekannt wäre, die du mit "WHERE ID = 21" abfragen könntest. Dann würde das Sortieren und Limitieren mutmaßlich wegfallen können. Dazu müßtest du aber einmalig die gesamte sortierte Tabelle abfragen und die IDs zwischenspeichern, damit dir die ID-Reihenfolge bekannt ist. Ich würde meinen, daß das auch nicht besonders hilft.

            - Sven Rautenberg

            1. Hi Sven,

              die rote Fehlerlampe rotiert schon wieder. Au weia.

              für PREVIOUS:

              Select Kunde, ID from kontakte where ID < 19 order by kunde,id Desc limit 1

              ich müßte also nach "where kunde+ID < letzterKunde+ID ..." abfragen
              (Pseudecode)
              Geht das überhaupt? kann man in der whereklausel zwei Felder als Strings addieren?

              Tja, die Frage ist nur, ob dir das wirklich weiterhilft. Ich denke, du kriegst auf diese Weise es zwar in den Griff, nacheinander die IDs durchzukaspern, aber nicht, so nacheinander die Namen durchzukaspern.

              Zuerst ganz kritisch angucken würde ich die Reihenfolge der Sortierung. Denn es wird zuerst nach Namen sortiert, dann nach IDs. Du kannst also dadurch folgenden Fall erhalten (je nachdem, in welcher Reihenfolge die Namen eingetragen wurden!):

              ID   Name
              3    Meier
              4    Meier
              1    Müller
              5    Müller
              2    Walther

              Sortiert nach Namen und dann nach IDs.

              Angenommen, du bist jetzt bei der ID 4 - Dann wäre der nächste Datensatz die ID 1. Du selektierst aber nur die IDs, die größer als die 4 sind, also ID 5. Damit fällt der Müller/ID 1 aus deiner Liste heraus.

              Ja, meine vermeintliche Lösungsmethode funktioniert nur für die Duplicates. War aber nicht so gedacht.

              Ich bastel noch ein bisschen. Ich will vor allem, das das Resultset nicht wächst bis zum Abwinken.

              Wie groß darf das denn werden? Wird das auch auf die Platte ausgelagert, wenn es zu groß wird? Da stehen ja wohl nur Zeiger auf die eigentlichen Daten drin, oder? Dann wären es aber immer noch mindestens 8 Byte pro Feld, das man selected hat.

              Wird wohl doch 'ne längere Geschichte. Ich sag schon mal den Termin morgen ab...

              Wenn ichs noch hinbekomme, gebe ich einen aus. Du hast jetzt schon zwei dicke Fehler gefunden!

              Grüße

              Tom

              1. Hi Tom,

                Geht das überhaupt? kann man in der whereklausel zwei Felder als
                Strings addieren?

                das mag von der konkreten SQL-Variante abhängen (concat?).

                Zudem macht es nur Sinn, wenn alle Felder bis auf das letzte eine
                konstante Länge der Inhalte haben.

                Du würdest damit aber sicherlich die Indexzugriffe abschalten
                und so die Performance ruinieren.

                Viele Grüße
                      Michael

                1. Hallo Michael, hallo Sven,

                  Ich gebe ja nicht auf und so langsam kommt ein Tipp zum nächsten.

                  Für das Rückwärts-Blättern ergibt sich:

                  Select id, firma, nachname from KD_PRIV  where concat(nachname,id) <= 'Fritz11' order by Nachname desc, id desc Limit 0, 3;

                  Fritz11 besteht aus $LastNachname.$LastID

                  Man muss das "desc" hinter jeden teil der Sortierung schreiben, das wußte ich nicht.

                  Für Vorwärts hat das schon funktioniert:

                  Select id, firma, nachname from KD_PRIV  where concat(nachname,id) >= 'Fritz11' order by Nachname, ID Limit 0, 3;

                  limit 0,3 besorgt dann eben 3 Sätze vom Aufsetzpunkt aus. Das kann man dann ja beliebig verändern. Wenn man mit Frames arbeitet, könnte man sich immer 25 Sätze in eine Liste holen und dann im zweiten Frame die Einzelanzeige und Bearbeitung durchführen. Da hat man die ID ja dann hinter einem Button als Postvariable stehen. Wenn der Satz inzwischen von jemand anders bearbeitet wurde, bekommt man eben eine Fehlermeldung (weil Timestamp inzwischen Größer oder Satz nicht mehr da).

                  Könnte sein, dass ich jetzt langsam land sehe.

                  Wäre nett, wenn Ihr nochmal gegenlest.

                  Tom

                  1. Moin nochmal!

                    Für das Rückwärts-Blättern ergibt sich:

                    Select id, firma, nachname from KD_PRIV  where concat(nachname,id) <= 'Fritz11' order by Nachname desc, id desc Limit 0, 3;

                    Ähm, hattest du nicht irgendwann mal Performancebedenken angemeldet, weil 1,5 Mio Datensätze zu erwarten wären? Mit _dieser_ SQL-Abfrage killst du die Datenbank ganz sicher, weil die Datenbank komplett gelesen werden muß, um concat auszuführen, und keinerlei Indices genutzt werden können. Ich würde mal sagen: Ganz üble Sache.

                    Und im übrigen muß ich dir ganz offen sagen: Wir kaspern hier jetzt schon einen ganzen Tag rum, aber du zeigst dich erstaunlich beratungsresistent gegenüber meinem Vorschlag, _nicht_ auf ID-Basis zu blättern, sondern auf Basis einer außen mitgeführten Variablen. Dabei hast du meinen Vorschlag, trotzdem ich ihn wiederholt angebracht habe, ohne Begründung immer wieder ignoriert und nach anderen Lösungen gesucht. Da hab' ich irgendwann keinen Spaß mehr an der Sache. Mach deine Datenbank doch am besten allein weiter, und wunder dich bitte hinterher nicht, wenn es nicht ganz so läuft, wie du oder die Anwender sich das vorstellen.

                    - Sven Rautenberg

                    1. Hallo Sven,

                      Ähm, hattest du nicht irgendwann mal Performancebedenken angemeldet, weil 1,5 Mio Datensätze zu erwarten wären? Mit _dieser_ SQL-Abfrage killst du die Datenbank ganz sicher, weil die Datenbank komplett gelesen werden muß, um concat auszuführen, und keinerlei Indices genutzt werden können. Ich würde mal sagen: Ganz üble Sache.

                      Da bin ich mir noch nicht sicher. Es liegt ein Index auf dem Feld Name und einer auf ID. Außerdem einer auf Name+ID. Kommt also darauf an, wie intelligent MySQL ist.

                      Und im übrigen muß ich dir ganz offen sagen: Wir kaspern hier jetzt schon einen ganzen Tag rum,

                      ich habe das nicht als gekasper empfunden, sondern einige wichtige Dinge dabei herausgefunden

                      »»aber du zeigst dich erstaunlich beratungsresistent gegenüber meinem Vorschlag, _nicht_ auf ID-Basis zu blättern, sondern auf Basis einer außen mitgeführten Variablen.

                      Was soll ich denn mit der von außen mitgeführten Variablen anfangen? Die gibt mir doch keinerlei Zugriff auf den Datensatz. Nach erfolgter (Einzel)anzeige des Satzwechsels ist diese Variable  hinfällig, weil das Resultset mit dem Ende des Scriptes stirbt. Es lohnt deshalb auch nicht, beliebig große Resultsets zu erzeugen, es sei denn, ich generiere daraus eine Liste, die auf dem Client angezeigt wird. Dann müsste ich aber auf dem Client JavaScript anwenden, um die betroffenen Felder des geänderten Datensatzes auch in der Liste zu aktualisieren. Dort werden natürlich nur die wichtigsten Felder.

                      Entweder habe ich da was ganz furchtbar falsch verstanden oder Du mich nicht. Ich habe Dir schon zugelesen und auch immer wieder über Deinen Vorschlag nachgedacht. Es ist mir nämlich ziemlich egal, von WEM die beste Lösung stammt, Hauptsache es wird die beste!

                      »»Dabei hast du meinen Vorschlag, trotzdem ich ihn wiederholt angebracht habe, ohne Begründung immer wieder ignoriert und nach anderen Lösungen gesucht.

                      Michael hatte darauf ja schon erwidert. Was soll ich das wiederholen?

                      »»Da hab' ich irgendwann keinen Spaß mehr an der Sache. Mach deine Datenbank doch am besten allein weiter, und wunder dich bitte hinterher nicht, wenn es nicht ganz so läuft, wie du oder die Anwender sich das vorstellen.

                      Nun isser beleidigt *umpf*. Kann ich aber auch nicht ändern. Tut mir nur leid um die Stimmung.

                      Die Trennung von Datenhaltung und Datenanzeige hat so ihre Tücken. Bei HTML kann man eben nicht mal so eben per Serverpush und Interrupt den Bildschirm aktualisieren. Ich muss mich also auf eine Ping-Pong-Strategie einlassen, die leitungs- und serverseitig so wenig wie möglich Performace killt.

                      Trotzdem liebe Grüße aus Braunschweig

                      Tom

                      1. Hallo Sven,

                        Ähm, hattest du nicht irgendwann mal Performancebedenken angemeldet, weil 1,5 Mio Datensätze zu erwarten wären? Mit _dieser_ SQL-Abfrage killst du die Datenbank ganz sicher, weil die Datenbank komplett gelesen werden muß, um concat auszuführen, und keinerlei Indices genutzt werden können. Ich würde mal sagen: Ganz üble Sache.

                        Da bin ich mir noch nicht sicher. Es liegt ein Index auf dem Feld Name und einer auf ID. Außerdem einer auf Name+ID. Kommt also darauf an, wie intelligent MySQL ist.

                        Hast du ein eigenes Feld "Name+ID" in der Datenbank angelegt, um darauf einen Index zu setzen? Warum dann noch concat() nehmen, sortiert doch dann einfach nach diesem Feld. Ist allerdings eine unnötige Redundanz.

                        »»aber du zeigst dich erstaunlich beratungsresistent gegenüber meinem Vorschlag, _nicht_ auf ID-Basis zu blättern, sondern auf Basis einer außen mitgeführten Variablen.

                        Was soll ich denn mit der von außen mitgeführten Variablen anfangen? Die gibt mir doch keinerlei Zugriff auf den Datensatz. Nach erfolgter (Einzel)anzeige des Satzwechsels ist diese Variable  hinfällig, weil das Resultset mit dem Ende des Scriptes stirbt. Es lohnt deshalb auch nicht, beliebig große Resultsets zu erzeugen, es sei denn, ich generiere daraus eine Liste, die auf dem Client angezeigt wird. Dann müsste ich aber auf dem Client JavaScript anwenden, um die betroffenen Felder des geänderten Datensatzes auch in der Liste zu aktualisieren. Dort werden natürlich nur die wichtigsten Felder.

                        Entweder habe ich da was ganz furchtbar falsch verstanden oder Du mich nicht. Ich habe Dir schon zugelesen und auch immer wieder über Deinen Vorschlag nachgedacht. Es ist mir nämlich ziemlich egal, von WEM die beste Lösung stammt, Hauptsache es wird die beste!

                        Ok, dann mal konkret in PHP, wie ich eine Suchmaschine in der Datenbank realisiert habe (gekürzt - und bitte keine Sicherheitsdiskussion über ungeprüfte Variablen :) ):

                        $sqlquery="SELECT * FROM tabelle WHERE textcontainer1 LIKE '%$suche%' ORDER BY artikelkey DESC LIMIT $show,".($resultperpage+1)."";

                        $suche enthält den Suchbegriff

                        $show enthält den Datensatzzeiger der ansagt, welcher Ausschnitt

                        der Tabelle geholt werden soll

                        $resultsperpage enthält die Anzahl der Ergebnisse pro Seite.

                        Den $sqlquery an die Datenbank senden.

                        $anz =  mysql_num_rows(...);

                        Anzahl der Ergebnisse feststellen.

                        for ($erg=0;$erg<$resultperpage;$erg++)
                        {

                        Datensätze ausgeben - man merke, daß in der SQL-Abfrage ein Datensatz

                        mehr angefordert wurde, als hier ausgegeben wird.

                        }

                        Links zum Blättern:

                        <?
                        if ($show > 0)

                        Wenn die Seite nicht am Anfang ist, kann man zurückblättern

                        {
                          ?><a href="<?= $PHP_SELF ?>?suche=<? echo rawurlencode($suche); ?>&show=<? echo $show-$resultperpage ?>" zurück</a><?
                        }
                        else
                        {
                          echo " ";
                        }
                        if ($anz > $resultperpage)

                        Wenn mehr Datensätze gefunden wurden, als auf diese Seite passen, kann man weiterblättern.

                        {
                          ?><a href="<?= $PHP_SELF ?>?suche=<? echo rawurlencode($suche); ?>&show=<? echo $show+$resultperpage ?>">Weiter</a><?
                        }
                        else
                        {
                          echo " ";
                        } ?>

                        Dadurch wird $show im Link jeweils um die Anzahl der Datensätze, die auf der Seite angezeigt werden, erhöht oder erniedrigt. Damit das nicht fehlschlägt, sollte als Grenzprüfung ganz zu Beginn noch rein:

                        if (($show < 0) OR ($show=="")) {$show=0;}

                        Weiter zurück als bis zum Anfang kann man nicht, auch wenn der Link das vielleicht irgendwie hinkriegen kann.

                        Diese Vorgehensweise erlaubt, daß man Indices in der Tabelle nutzen kann (Performance), man kann beliebig (auch User-definiert) sortieren mit ORDER BY - egal wie man sortiert haben möchte, funktioniert das Blättern vollkommen unabhängig davon.

                        »»Da hab' ich irgendwann keinen Spaß mehr an der Sache. Mach deine Datenbank doch am besten allein weiter, und wunder dich bitte hinterher nicht, wenn es nicht ganz so läuft, wie du oder die Anwender sich das vorstellen.

                        Nun isser beleidigt *umpf*. Kann ich aber auch nicht ändern. Tut mir nur leid um die Stimmung.

                        Es hat etwas von Sandsackboxen gehabt bisher.

                        Die Trennung von Datenhaltung und Datenanzeige hat so ihre Tücken. Bei HTML kann man eben nicht mal so eben per Serverpush und Interrupt den Bildschirm aktualisieren. Ich muss mich also auf eine Ping-Pong-Strategie einlassen, die leitungs- und serverseitig so wenig wie möglich Performace killt.

                        Über diesen Punkt hast du dich noch garnicht so recht ausgelassen, also schien er bis jetzt nicht sonderlich wichtig. Aber ich denke, serverseitig ist meine Lösung garnicht so problematisch (wenn die DB indexseitig sortieren kann, ist das superschnell, einziges Problem bei mir wäre das WHERE x LIKE '%string%', was lahm ist). Die DB muß jeweils nur einen kleinen Ausschnitt der Datensätze wirklich liefern (LIMIT), und was die Leitung zum Browser angeht: Naja, irgendwie müssen die Datensätze ja über die Leitung. Es hilft nicht viel, die Daten in 20er-Blöcken zu übertragen, wenn dennoch pro Zeitpunkt nur ein Datensatz angezeigt wird. Das spart keine Leitungskapazität, sondern verlagert die Datenübertragung nur.

                        Wie gut du in den Datensätzen blättern willst/kannst, hängt von dir ab. Es wäre ohne Probleme möglich, 20er-Blöcke in einen Frame zu laden und anhand der ID des Datensatzes dann den einzelnen Datensatz in einen anderen Frame. Oder die betroffenen, kompletten Datensätze schon gleich mitzuübertragen. Ich denke, mit meinem System bist du da ziemlich flexibel, was die Datensatzzahlen angeht. :)

                        - Sven Rautenberg

                        1. Hallo Sven,

                          danke, dass Du dir die Sache nun NOCHMAL angeschaut hast. Ich hatte Dich da aber doch schon richtig verstanden. Ich will auch mal versuchen zu erklären, MEN die Schwachstellen der Lösung liegen.

                          Ähm, hattest du nicht irgendwann mal Performancebedenken

                          Die habe ich auch immer noch. Da greife ich aber Deinen folgenden Vorschlag nochmal auf...

                          Da bin ich mir noch nicht sicher. Es liegt ein Index auf dem Feld Name und einer auf ID. Außerdem einer auf Name+ID. Kommt also darauf an, wie intelligent MySQL ist.

                          Hast du ein eigenes Feld "Name+ID" in der Datenbank angelegt, um darauf einen Index zu setzen? Warum dann noch concat() nehmen, sortiert doch dann einfach nach diesem Feld. Ist allerdings eine unnötige Redundanz.

                          Der Index ist ein Kombinationsindex NAME(20),ID Das Namensfeld kann bis zu 70 Zeichen enthalten. Das will ich noch untersuchen, wann MySQL den Index überhaupt einsetzt.

                          Ok, dann mal konkret in PHP, wie ich eine Suchmaschine in der Datenbank realisiert habe (gekürzt - und bitte keine Sicherheitsdiskussion über ungeprüfte Variablen :) ):

                          $sqlquery="SELECT * FROM tabelle WHERE textcontainer1 LIKE '%$suche%' ORDER BY artikelkey DESC LIMIT $show,".($resultperpage+1)."";

                          $suche enthält den Suchbegriff

                          $show enthält den Datensatzzeiger der ansagt, welcher Ausschnitt

                          Show enthält eben keinen Datensatzzeiger auf die Tabelle, sondern einen Offset für das neue Resultset, dass aus der Abfrage erstellt werden soll. Also auf die gerade in Vorbereitung befindliche Ergebnismenge. Durch die Verarbeitsroutine der DBE rauschen alle Sätze durch und werden auf Erfüllung des Kriteriums untersucht. Wenn Ein Index benutzt werden kann, und da bin ich mir in meiner Sache ziemlich sicher, dass die DBE das erkennen sollte, kann

                          a. der Aufsetzpunkt in der Tabelle geschickt wählen
                          b. brauchen der Auswahlprozedur keine Sätze zugeführt zu werden, die überhaupt nicht passen
                          c. wird erkannt, wann der zu untersuchende Bereich der Tabelle garantiert beendet ist, nämlich wenn des nächste Index-Item größer ist, als das Suchkriterium (Das geht bei Dir batürlich nicht, da Du %bla% suchst, also es kein "Größer" gibt.)

                          Ich mache aber eine Feldanfangsuche. Das sollte MySQL können. Wenn nicht, nehme ich eben Informix. Liegt schon über drei Jahre hier nutzlos im Haus rum. Update bekomme ich (hoffentlich) noch kostenlos.

                          der Tabelle geholt werden soll

                          $resultsperpage enthält die Anzahl der Ergebnisse pro Seite.

                          Den $sqlquery an die Datenbank senden.

                          $anz =  mysql_num_rows(...);

                          Anzahl der Ergebnisse feststellen.

                          for ($erg=0;$erg<$resultperpage;$erg++)
                          {

                          Datensätze ausgeben - man merke, daß in der SQL-Abfrage ein Datensatz

                          mehr angefordert wurde, als hier ausgegeben wird.

                          }

                          Der Trick ist ganz gut.
                          Das habe ich soweit verstanden.

                          Du benutzt immer den selben String $suche und da liegt der Haken. Deine Lösung berücksichtigt keine dynamisches Datenverhalten. Es können von Bearbeitungsschritt zu Bearbeitungsschritt Sätze hinzukommen oder welche wegfallen, weil wir ja in einem ziemlich großen Netzwerk arbeiten und viele Leute unterschiedlichste Zugriffsrechte auf die Tabellen haben.

                          Wenn Sätze in den eben von Dir bereits betrachteten Berich eingefügt werden, passiert folgendes:

                          $ShowPerPage=7   // damit das hier nicht so lang wird
                          $show = 7        // von 0 bis 6 haben wir gerade bearbeitet.

                          @1 bei A      @1+x bei B     @2 bei A        2>1+x = Zeit
                          0-7           seine 0-7      seine 8-15
                          ------------- -------------- --------------
                          Adam          Adam           Hilde
                          Emil          Emil           Holger
                          Franz         Fritz          ...
                          Fritz         Fritz
                          Fritz         Günter
                          Fritz         Günther
                          Günter        Hans
                          Günther       Heinrich

                          Hans          Hilde
                          Heinrich      Holger
                          Hilde         ...
                          Holger
                          ...

                          Hans und Heirich fallen also unter den Tisch und werden nicht bearbeitet. Das fällt auch nicht weiter auf. Sie wären aber nun an der Reihe gewesen... Der Fehler fällt nur dann auf, wenn man allen zur Bearbeitung anstehenden Datensätzen einen Timestemp verpasst, auch wenn gar nix geändert wurde. Dann kann man später diese Fehler finden. Genauso findet man ja auch dann die Datensätze, die während der Bearbeitung eingefügt worden sind. Die wären aber von der Bearbeitung her sowieso noch nicht dran gewesen (Beispiel Mahnfrist abgelaufen, Wiedervorlage beim Verkauf, usw).

                          Ich habe mir das Leben deshalb so schwer gemacht, weil ich eine Lösung für das Holen eines aktuell gültigen Resultsets gesucht habe. Das geht nur, wenn man die DATEN des aktuell angezeigten/bearbeiteten Datensatzes in die nächste Suche aufnimmt.

                          Ich denke aber, ich werde doch einen zweigeteilten Anzeigebildschirm aufbauen. Obereres Frame = Liste. Die kann ja sogar gescrollt werden. Unterer Teil Detaildatensatz zur Bearbeitung, Hinzufügen, Löschen etc. Die Liste bleibt solange stehen, bis der Benutzer eine neue anfordert, wird auch nicht Updatetd. Muss der Benutzer sich eben merken, wenn er einen Satz aus der Liste gelöscht hat. Wenn er den nochmal aufruft, bekommt er eben eine Warnung.

                          Insofern hat mich Deine Ausführung also wieder ein Stück weitergebracht. Ich war da sehr am Schwanken. Ist jetzt die Frage, ob ich das Einzelblättern überhaupt einbaue oder nur listenweise blättere.

                          Wahrscheinlich werde ich für verschiedene Anwendungsfälle beide Möglichkeiten brauchen.

                          Es hat etwas von Sandsackboxen gehabt bisher.

                          Ja, ich geb ja zu, dass ich etwas zu dick geworden bin :-)

                          Wie gut du in den Datensätzen blättern willst/kannst, hängt von dir ab. Es wäre ohne Probleme möglich, 20er-Blöcke in einen Frame zu laden und anhand der ID des Datensatzes dann den einzelnen Datensatz in einen anderen Frame. Oder die betroffenen, kompletten Datensätze schon gleich mitzuübertragen. Ich denke, mit meinem System bist du da ziemlich flexibel, was die Datensatzzahlen angeht. :)

                          Für meine Kundendaten-Bearbeitung werde ich diese Möglichkeit nehmen. Ist auch ergonomsich und relativ leicht zu verstehen für den Benutzer.

                          Bis denne.

                          Tom

                          1. Korrektur:

                            Wenn Sätze in dem eben von Dir bereits betrachteten Bereich gelöscht werden, passiert folgendes:

                            $ShowPerPage=7   // damit das hier nicht so lang wird

                          2. Moin, Tom! :)

                            Hast du ein eigenes Feld "Name+ID" in der Datenbank angelegt, um darauf einen Index zu setzen? Warum dann noch concat() nehmen, sortiert doch dann einfach nach diesem Feld. Ist allerdings eine unnötige Redundanz.

                            Der Index ist ein Kombinationsindex NAME(20),ID Das Namensfeld kann bis zu 70 Zeichen enthalten. Das will ich noch untersuchen, wann MySQL den Index überhaupt einsetzt.

                            So langsam verstehe ich, wo dein Problem liegt. Und in der Tat: Ja, das Geblättere von Blöcken hat ein Problem, wenn neue Daten dazukommen oder verschwinden. Solch ein Problem hast du aber immer, wenn du Seitenweise (und nicht einzeln) blätterst, auch bei deiner Methode. Es braucht ja nur ein Eintrag hinzuzukommen, der laut Sortierung eigentlich auf der derzeitigen Seite angezeigt werden müßte. Das kann man wirklich nur durch Einzelblätterung vermeiden.

                            Hm, muß ich noch mehr kommentieren? ... mal gucken.

                            $show enthält den Datensatzzeiger der ansagt, welcher Ausschnitt

                            Show enthält eben keinen Datensatzzeiger auf die Tabelle, sondern einen Offset für das neue Resultset, dass aus der Abfrage erstellt werden soll.

                            Ein Zeiger ist etwas, was zeigt. In diesem Fall auf den ersten Datensatz der auszugebenden Liste, basierend auf den Daten zum Zeitpunkt der Abfrage. :) Etwas, was auf Datensätze zeigt, ist ein Datensatzzeiger. :) Das Problem ist nicht der Zeiger, sondern was man in der Zukunft damit macht.

                            Durch die Verarbeitsroutine der DBE rauschen alle Sätze durch und werden auf Erfüllung des Kriteriums untersucht.

                            Wobei anzumerken ist: Wenn du nach meiner Methode in der gesamten Datenmenge blättern willst, brauchst du gar kein Kriterium anzugeben.

                            Wenn Ein Index benutzt werden kann, und da bin ich mir in meiner Sache ziemlich sicher, dass die DBE das erkennen sollte, kann

                            a. der Aufsetzpunkt in der Tabelle geschickt wählen

                            Ich vermute, der Unterschied zwischen meinem Ansatz, alle Datensätze zu sortieren und nur einen Ausschnitt zu holen, und deinem Ansatz, nur die nachfolgenden/vorhergehenden Datensätze abzufragen, zu sortieren und einen Ausschnitt zu holen, dürften annähernd identisch performen. Dein Ansatz hat den Vorteil, daß die zu sortierende Menge kleiner sein kann (durchschnittlich nur 50% meiner Datenmenge), aber den Nachteil, daß ein Kriteriums verglichen werden muß.

                            b. brauchen der Auswahlprozedur keine Sätze zugeführt zu werden, die überhaupt nicht passen

                            Wenn man alle Datensätze haben will, kommt man nicht drum herum, alle Datensätze anzugucken. :)

                            c. wird erkannt, wann der zu untersuchende Bereich der Tabelle garantiert beendet ist, nämlich wenn des nächste Index-Item größer ist, als das Suchkriterium (Das geht bei Dir batürlich nicht, da Du %bla% suchst, also es kein "Größer" gibt.)

                            Ähm???

                            Ich denke, es gibt für unsere beiden Ansätze ein ganz grundlegendes Problem: Die gedachte komplette Liste der Datensätze kann sich mittendrin ändern. Das bedeutet, daß ein "Blättern" natürlich nicht mehr so möglich ist, daß man alle Datensätze erhält. Dies ließe sich nur dadurch vermeiden, daß die eindeutige, bei jedem Datensatz incrementierte ID als einziges Sortierkriterium herangezogen wird - nur dann sind vorhergehender und folgender Datensatz eindeutig definiert: Es ist der nächste existierende Datensatz, dessen ID kleiner oder größer als die derzeitige ID ist. Neue Datensätze werden am Ende der Liste angefügt. Man könnte also solange den nächsten Datensatz anfordern, bis keiner mehr kommt. Und nach einer Wartezeit wäre vielleicht wieder einer da.

                            Basierend auf dieser Überlegung dürfte klar sein: Ein Blättern in einer Namensliste ist so unmöglich hinzukriegen, da es immer doppelte Namen geben wird. Und auch wenn du basierend auf dem Namen und der ID ein eindeutiges Sortierkriterium generierst, hast du immer noch das unlösbare Problem, daß neue Datensätze, wenn sie in der gewünschten Sortierung eingeordnet werden sollen, urplötzlich mitten in der Liste auftauchen.

                            Ich mache aber eine Feldanfangsuche. Das sollte MySQL können. Wenn nicht, nehme ich eben Informix. Liegt schon über drei Jahre hier nutzlos im Haus rum. Update bekomme ich (hoffentlich) noch kostenlos.

                            Die verwendete Datenbank löst allerhöchstens Performanceprobleme, nicht dieses logische Problem. :)

                            Du benutzt immer den selben String $suche und da liegt der Haken. Deine Lösung berücksichtigt keine dynamisches Datenverhalten. Es können von Bearbeitungsschritt zu Bearbeitungsschritt Sätze hinzukommen oder welche wegfallen, weil wir ja in einem ziemlich großen Netzwerk arbeiten und viele Leute unterschiedlichste Zugriffsrechte auf die Tabellen haben.

                            Ja, die Gleichzeitigkeit ist ein Problem. Die Frage ist doch: Was soll per Blättern geschehen? Einen Datensatz bearbeiten? Das ist total unabhängig von anderen Datensätzen. Einem "Datensatz" eine Rechnung schicken? Auch kein Problem, wenn diese Aktion anderweitig ausgelöst wird, beispielsweise durch Vorliegen von Papier (Außendienstservicemeldung). Allen Datensätzen die Mitgliedsbeiträge abbuchen? Das wäre dann eher keine Aktion, die man per "Durchblättern" erledigen könnte.

                            Die einzige mir einleuchtende Lösung für solche Bearbeitungsschritte, die für alle Datensätze erledigt werden müssen, aber aus irgendwelchen Gründen nicht gleichzeitig erledigt werden können, wäre, daß man eine weitere Tabelle (oder Spalte - aber das könnte problematisch werden, weil zu starr) mit Statusmeldungen anlegt, in der genau verzeichnet wird, was mit welchen Datensätzen geschehen ist. Auf diese Weise findet man schnell heraus, welche Datensätze noch zu bearbeiten sind.

                            Wenn Sätze in den eben von Dir bereits betrachteten Berich eingefügt werden, passiert folgendes:

                            Weiß ich. War bei meiner Anwendung kein Problem.

                            Ich habe mir das Leben deshalb so schwer gemacht, weil ich eine Lösung für das Holen eines aktuell gültigen Resultsets gesucht habe. Das geht nur, wenn man die DATEN des aktuell angezeigten/bearbeiteten Datensatzes in die nächste Suche aufnimmt.

                            Tja, dein Leben ist schwer, und eine richtige Lösung ist garnicht machbar - die Welt ist ungerecht.

                            Ich denke aber, ich werde doch einen zweigeteilten Anzeigebildschirm aufbauen. Obereres Frame = Liste. Die kann ja sogar gescrollt werden. Unterer Teil Detaildatensatz zur Bearbeitung, Hinzufügen, Löschen etc. Die Liste bleibt solange stehen, bis der Benutzer eine neue anfordert, wird auch nicht Updatetd. Muss der Benutzer sich eben merken, wenn er einen Satz aus der Liste gelöscht hat. Wenn er den nochmal aufruft, bekommt er eben eine Warnung.

                            Bleibt das oben erwähnte Problem: Was ist, wenn ein Datensatz, der auf diese Seite gehören würde, hinzukommt? ;)

                            Insofern hat mich Deine Ausführung also wieder ein Stück weitergebracht. Ich war da sehr am Schwanken. Ist jetzt die Frage, ob ich das Einzelblättern überhaupt einbaue oder nur listenweise blättere.

                            Wahrscheinlich werde ich für verschiedene Anwendungsfälle beide Möglichkeiten brauchen.

                            Flexibilität ist was feines.

                            - Sven Rautenberg

                            1. Moin moin,

                              So langsam verstehe ich, wo dein Problem liegt. .... Es braucht ja nur ein Eintrag hinzuzukommen, der laut Sortierung eigentlich auf der derzeitigen Seite angezeigt werden müßte. Das kann man wirklich nur durch Einzelblätterung vermeiden.

                              Nein, das kann man auch nicht durch Einzelschritte vermeiden. Es ist nicht ausgeschlossen, dass Du gerade einen Filterbereich verlassen ahst und jemand fügt sozusagen hinter deinem Rücken zwanzig neue Sätze ein. Aber dafür gibt es ja TimeStamp. Ich bin sowieso ein Metadaten-Fanatiker: Wann erstmalig angelegt, von wem, von wo (IP), wann letzmalig verändert, von wem, von wo (IP), Wem gehört der Datensatz (Owner, Gruppenliste  -- Sieht aus wie Unix, gell?) usw..

                              Ein Zeiger ist etwas, was zeigt. In diesem Fall auf den ersten Datensatz der auszugebenden Liste, basierend auf den Daten zum Zeitpunkt der Abfrage. :) Etwas, was auf Datensätze zeigt, ist ein Datensatzzeiger. :) Das Problem ist nicht der Zeiger, sondern was man in der Zukunft damit macht.

                              Das interessiert mich auch nochmal. Ist das resultset unter MySQL ein Dynaset oder ist es ein Snapshot?

                              Wenn ich das richtig verstanden habe, dann liegen im Resultset keinesfalls die Daten, sondern nur die Zeiger auf die angeforderten Felder der gefundenen Datensätze. Demnach müßte also eine Änderung an einem Datensatz, die nach meiner Abfrage, aber vor meiner Bearbeitung des Satzes liegt noch bis zu mir durchschlagen.

                              Durch die Verarbeitsroutine der DBE rauschen alle Sätze durch und werden auf Erfüllung des Kriteriums untersucht.

                              Wobei anzumerken ist: Wenn du nach meiner Methode in der gesamten Datenmenge blättern willst, brauchst du gar kein Kriterium anzugeben.

                              Ein Kriterium (match) hast Du ja angegeben (&such%). Mein Kriterium ist die Übereinstimmug eines Suchbegriffes mit dem ANFANG eines indizierten Feldes (Name) und dem absoluten Wert eines zweiten indizierten Feldes (ID). Das sit für eine mäßig gute DBE per Indes auflösbar.

                              Damit muß meine Lösung nicht die gesamte Datenmenge durchsuchen sondern erst ab der Stelle, an der Teilkriterium 1 (Anfang des Namen = Index auf Name) gilt.

                              Das nennt man den Aufsetzpunkt.

                              Ich vermute, der Unterschied zwischen meinem Ansatz, alle Datensätze zu sortieren und nur einen Ausschnitt zu holen, und deinem Ansatz, nur die nachfolgenden/vorhergehenden Datensätze abzufragen, zu sortieren und einen Ausschnitt zu holen, dürften annähernd identisch performen.

                              Ich hoffe nicht. Deine Lösung wird man für Deinen Fall nicht besser machen können. Du suchst nach einem Match mitten im Feldinhalt. Das lässt sich nur durch sehr komplizierte Hashtables erreichen und das Verfahren ist patentiert. Das kann sich eine GNU-Software niemals leisten. Du kannst deshalb keinen Indes verwenden und musst ALLE Datensätze durchlesen. Ich fange bei meiner Problemstellung erst ab Aufsetzpunkt an zu lesen.

                              Dein Ansatz hat den Vorteil, daß die zu sortierende Menge kleiner sein kann (durchschnittlich nur 50% meiner Datenmenge), aber den Nachteil, daß ein Kriteriums verglichen werden muß.

                              Die Menge IST kleiner, und ein Kriterium muss bei der SUCHE immer verglichen werden. Beim HOLEN von Daten sit das nicht notwendig, denn da weiß man, wo sie stehen. Soweit zur Begriffsbestimmung auf Deutsch. Ist vielleicht mein Problem, dass ich Deutsch rede. Da nimmt mich keiner Ernst  ;-)

                              b. brauchen der Auswahlprozedur keine Sätze zugeführt zu werden, die überhaupt nicht passen

                              Wenn man alle Datensätze haben will, kommt man nicht drum herum, alle Datensätze anzugucken. :)

                              Ich will ja nicht alle Datensätze haben, sondern z.B. nur den Bereich MA.... bis MZ... (Dynamsiche Sachbearbietertrennung). Und weil ich einen Index auf das relavanteste Feld lege, muss ich kir auch nicht alle Sätze angucken.

                              c. wird erkannt, wann der zu untersuchende Bereich der Tabelle garantiert beendet ist, nämlich wenn des nächste Index-Item größer ist, als das Suchkriterium (Das geht bei Dir batürlich nicht, da Du %bla% suchst, also es kein "Größer" gibt.)

                              Ähm???

                              Ja, Du suchst nach einem "Match", also nach der Übereinstimmung einer kurzen Schablone mit einem langen Datensatz. Die könnte sogar mehrfach in Deinem Satz vorkommen. Da muss man lesen, lesen, lesen

                              Ich denke, es gibt für unsere beiden Ansätze ein ganz grundlegendes Problem: Die gedachte komplette Liste der Datensätze kann sich mittendrin ändern.

                              Genau das isses!

                              Das bedeutet, daß ein "Blättern" natürlich nicht mehr so möglich ist, daß man alle Datensätze erhält. Dies ließe sich nur dadurch vermeiden, daß die eindeutige, bei jedem Datensatz incrementierte ID als einziges Sortierkriterium herangezogen wird - nur dann sind vorhergehender und folgender Datensatz eindeutig definiert: Es ist der nächste existierende Datensatz, dessen ID kleiner oder größer als die derzeitige ID ist. Neue Datensätze werden am Ende der Liste angefügt. Man könnte also solange den nächsten Datensatz anfordern, bis keiner mehr kommt. Und nach einer Wartezeit wäre vielleicht wieder einer da.

                              So ungefähr könnte man die Organiation betreiben. Als Tagesabschluß müssten dann immer noch die Nachträge bearbeitet werden, um tagesaktuell zu sein.

                              Diesen letzten Absatz möchte ich noch in der Diskussion halten. Hier ist noch Überlegungsbedarf und die Chance auf Pfiffige Lösungen.

                              Basierend auf dieser Überlegung dürfte klar sein: Ein Blättern in einer Namensliste ist so unmöglich hinzukriegen, da es immer doppelte Namen geben wird.

                              Doppelte Namen sind durch die Verbindung mit der ID überhaupt kein Problem mehr.

                              Und auch wenn du basierend auf dem Namen und der ID ein eindeutiges Sortierkriterium generierst, hast du immer noch das unlösbare Problem, daß neue Datensätze, wenn sie in der gewünschten Sortierung eingeordnet werden sollen, urplötzlich mitten in der Liste auftauchen.

                              Viel schlimmer: lange vor Beginn der Liste. Dafür braucht man dann wirklich einen separaten Bearbeitungsschritt.

                              Ja, die Gleichzeitigkeit ist ein Problem. Die Frage ist doch: Was soll per Blättern geschehen? Einen Datensatz bearbeiten? Das ist total unabhängig von anderen Datensätzen. Einem "Datensatz" eine Rechnung schicken? Auch kein Problem, wenn diese Aktion anderweitig ausgelöst wird, beispielsweise durch Vorliegen von Papier (Außendienstservicemeldung). Allen Datensätzen die Mitgliedsbeiträge abbuchen? Das wäre dann eher keine Aktion, die man per "Durchblättern" erledigen könnte.

                              Die einzige mir einleuchtende Lösung für solche Bearbeitungsschritte, die für alle Datensätze erledigt werden müssen, aber aus irgendwelchen Gründen nicht gleichzeitig erledigt werden können, wäre, daß man eine weitere Tabelle (oder Spalte - aber das könnte problematisch werden, weil zu starr) mit Statusmeldungen anlegt, in der genau verzeichnet wird, was mit welchen Datensätzen geschehen ist. Auf diese Weise findet man schnell heraus, welche Datensätze noch zu bearbeiten sind.

                              Ja, das wird ein Teil der Lösung werden.

                              Tja, dein Leben ist schwer, und eine richtige Lösung ist garnicht machbar - die Welt ist ungerecht.

                              Aber ich trink jetzt erst mal ein Schöööönes Hefeweizen - prost

                              Bleibt das oben erwähnte Problem: Was ist, wenn ein Datensatz, der auf diese Seite gehören würde, hinzukommt? ;)

                              Kann man nicht lösen mit HTML. Sollte man auch bei Echtzeit-dialogfähigen Systemen nciht versuchen. Da kann kein Mensch mehr mit arbeiten. Immer Serialisierung der Arbeitsschritte betreiben.

                              So Sven! Nun bin sich mit der Betrachtung durch Deine Hilfe schon wieder ein Stück weitergekommen. Wir sind da schon ganz schön tief eingestiegen. Habe auch schon einige Meldungen erhalten, dass es Andere auch interessiert, sie aber nicht mehr mitkommen. Vielleicht sollten wie diese beiden Fälle hinterher mal als Beispiele Aufbereiten. Das wär mir die Mühe wert.

                              Liebe Grüße
                              Tom

                              1. Yo!

                                So Sven! Nun bin sich mit der Betrachtung durch Deine Hilfe schon

                                wieder ein Stück weitergekommen. Wir sind da schon ganz schön tief eingestiegen. Habe auch schon einige Meldungen erhalten, dass es Andere auch interessiert, sie aber nicht mehr mitkommen. Vielleicht sollten wie diese beiden Fälle hinterher mal als Beispiele Aufbereiten. Das wär mir die Mühe wert.

                                Du weißt, daß die neue Sektion "Tipps und Tricks" von SelfAktuell (http://aktuell.de.selfhtml.org/tippstricks) noch auf Füllung wartet. Auch wenn die internen Grundlagen vielleicht etwas masseninkompatibel sind - über eine gute Lösung solch eines Problems freut sich sicherlich jeder. Ich melde mich mal per Mail. ;)

                                - Sven Rautenberg

                              2. Hi Tom,

                                Das interessiert mich auch nochmal. Ist das resultset unter MySQL ein
                                Dynaset oder ist es ein Snapshot?

                                könnte das nicht massiv vom verwendeten Tabellentreiber (und dessen
                                Transaktionssicherheit) abhängen?

                                Bei solchen Fragen antworte ich eigentlich mechanisch: "mySQL existiert
                                gar nicht wirklich - was existiert, das ist eine Menge von Tabellen-
                                treibern, die alle unterschiedlich viel können".

                                Ich denke, es gibt für unsere beiden Ansätze ein ganz grundlegendes
                                Problem: Die gedachte komplette Liste der Datensätze kann sich
                                mittendrin ändern.
                                Genau das isses!

                                Dann muß der Trick darin bestehen, bei der nachfolgenden Anfrage nur
                                noch relevante Datensätze zu berücksichtigen (siehe unten).

                                Das bedeutet, daß ein "Blättern" natürlich nicht mehr so möglich
                                ist, daß man alle Datensätze erhält.

                                Eventuell schon ...

                                Basierend auf dieser Überlegung dürfte klar sein: Ein Blättern in
                                einer Namensliste ist so unmöglich hinzukriegen, da es immer
                                doppelte Namen geben wird.
                                Doppelte Namen sind durch die Verbindung mit der ID überhaupt kein
                                Problem mehr.

                                Genau. Und ein Primärschlüssel (oder überhaupt ein UNIQUE INDEX) darf
                                ja sehr wohl auf einer Liste von Spalten liegen (was die ID erspart).

                                Ja, die Gleichzeitigkeit ist ein Problem.
                                Die Frage ist doch: Was soll per Blättern geschehen? Einen
                                Datensatz bearbeiten? Das ist total unabhängig von anderen
                                Datensätzen. Einem "Datensatz" eine Rechnung schicken? Auch kein
                                Problem, wenn diese Aktion anderweitig ausgelöst wird,
                                beispielsweise durch Vorliegen von Papier
                                (Außendienstservicemeldung).
                                Allen Datensätzen die Mitgliedsbeiträge abbuchen? Das wäre dann
                                eher keine Aktion, die man per "Durchblättern" erledigen könnte.

                                Doch - Du mußt nur eine entsprechende Buchführung machen (siehe unten).

                                Die einzige mir einleuchtende Lösung für solche Bearbeitungs-
                                schritte, die für alle Datensätze erledigt werden müssen, aber
                                aus irgendwelchen Gründen nicht gleichzeitig erledigt werden
                                können, wäre, daß man eine weitere Tabelle (oder Spalte - aber
                                das könnte problematisch werden, weil zu starr)

                                Finde ich nicht. Eine separate Tabelle fände ich viel schlimmer (weil
                                Du dann JOINen mußt). Wenn ein Datensatz genau einen Zustand haben
                                kann, dann gehört dieser m. E. zwingend in die Tabelle selbst hinein
                                (wegen der sauberen relationalen Zerlegung).

                                mit Statusmeldungen anlegt, in der genau verzeichnet wird, was
                                mit welchen Datensätzen geschehen ist. Auf diese Weise findet
                                man schnell heraus, welche Datensätze noch zu bearbeiten sind.

                                Genau.

                                Bisher haben wir immer das Blättern in beide Richtungen als Aufgaben-
                                stellung gesehen. Wenn es aber darum geht, sequentiell alle Datensätze
                                zu verarbeiten, dann sieht die Aufgabenstellung völlig anders aus.

                                Bleibt das oben erwähnte Problem: Was ist, wenn ein Datensatz,
                                der auf diese Seite gehören würde, hinzukommt? ;)

                                Stell Dir mal folgendes vor:
                                1. Du hast eine Spalte mit einem Zustand (boolean-Flag reicht für unsere
                                   Zwecke).
                                2. Zu Beginn der allgemeinen Abbuchung wird dieses Flag für alle
                                   existierenden Datensätze gelöscht; für neu angelegte wird es per
                                   Default auf "gelöscht" gesetzt.
                                3. Niemand außer Deiner Anwendung ist befugt, dieses Flag zu verändern.
                                4. Es esistiert ein UNIQUE Index über das Tripel (!) aus Flag, Name
                                   und ID.
                                5. Jeder Zugriff auf einen Datensatz der Tabelle sucht denjenigen, der
                                   das Flag nicht gesetzt hat und für die beiden anderen Datensätze
                                   den kleinstmöglichen Wert enthält. Ein so bearbeiteter Datensatz
                                   wird aber mit verändertem Flag zurück geschrieben.
                                   Wir blättern also nicht dadurch, daß wir uns die Vorgängerposition
                                   merken - wir "verbrauchen" einfach alle Datensätze mit gelöschtem
                                   Flag! Dabei ist uns völlig egal, ob neue Datensätze hinzu kommen -
                                   wenn wir beispielsweise beim Buchstaben N sind und ein neuer Name
                                   mit A eingetragen wird, dann bekommt der Bearbeiter als nächsten
                                   Datensatz diesen angeboten, weil er ja nun der kleinste "ungeflagte"
                                   ist.
                                Auf diese Weise werden definitiv alle Datensätze sequentiell bearbeitet

                                • zwar nicht zwingend in alphabetischer Reihenfolge ihrer Namen, aber
                                  so gut wir möglich.

                                Der Trick dabei ist, daß jeweils nur ein einziger, sehr performanter
                                Abstieg in den entsprechenden Indexbaum notwendig ist, um den nächsten
                                Datensatz zu finden - _wenn_ das Flag das _erste_ Feld des entsprechenden
                                Indexbaums ist! (Alle geflagten Datensätze werden gar nicht erst ange-
                                sehen, und von den ungeflagten eben wirklich nur der "ganz linke".)
                                Der Preis dafür ist natürlich, daß jede Änderung eines Datensatzes eine
                                Verschiebung innerhalb dieses Indexbaums kostet ... und daß der Index-
                                baum entsprechend schnell degenerieren wird. Aber den brauchen wir ja
                                nur für diese Bearbeitung und können ihn anschließend wegwerfen.

                                Natürlich darf niemand gleichzeitig einen solchen Datensatz ändern und
                                dabei unser Flag versehentlich zurücksetzen - das Verfahren verlangt
                                nach einem transaktionssicheren Tabellentreiber.

                                Viele Grüße
                                      Michael

                                1. Moin

                                  Stell Dir mal folgendes vor:

                                  [...]

                                  Wir blättern also nicht dadurch, daß wir uns die Vorgängerposition
                                     merken - wir "verbrauchen" einfach alle Datensätze mit gelöschtem
                                     Flag! Dabei ist uns völlig egal, ob neue Datensätze hinzu kommen -
                                     wenn wir beispielsweise beim Buchstaben N sind und ein neuer Name
                                     mit A eingetragen wird, dann bekommt der Bearbeiter als nächsten
                                     Datensatz diesen angeboten, weil er ja nun der kleinste "ungeflagte"
                                     ist.
                                  Auf diese Weise werden definitiv alle Datensätze sequentiell bearbeitet

                                  • zwar nicht zwingend in alphabetischer Reihenfolge ihrer Namen, aber
                                    so gut wir möglich.

                                  Tja, die Frage ist dabei aber nur: Ist das genau das, was man will?

                                  Zum einen: Wenn ich alphabetisch sortiert blättern will, dann kann ich es nicht gebrauchen, daß nach "Neumann" plötzlich "Adelbert" kommt, nur weil der gerade neu ist. Das ist nicht mein Begriff von "blättern".

                                  Und wenn deine Lösung garnicht alphabetisches Blättern heißt: Wenn man einfach aufsteigend nach der unique ID sortiert, kommen neue Datensätze immer ans Ende, tauchen aber nie zwischendrin auf.

                                  Die Probleme kommen, ganz klar, dann, wenn man nur einen Teilausschnitt aus dieser Tabelle betrachten will, beispielsweise alle Datensätze mit Namen "N".

                                  Es muß einfach die Entscheidung getroffen werden, daß entweder das alphabetische beim Blättern wichtig ist, oder die Beachtung aller im Laufe des Blätterns neu hinzukommenden Datensätze. Dabei ist ganz eindeutig der gewünschte Arbeitsvorgang mit zu berücksichtigen.

                                  Ich kann mir eigentlich nur zwei Szenarien vorstellen: Erstens geht es um ein zwangloses Blättern, bei dem man an gewissen Stellen auch Datensätze bearbeitet. Derselbe Vorgang des Bearbeitens wäre auch durchführbar, wenn man den Datensatz direkt sucht (also nach ID oder Namen) und bearbeitet. Das Blättern würde in diesem Falle eigentlich nur aufhalten, bzw. das Anzeigen einer blätterbaren Auswahlliste die Auswahl des richtigen Datensatzes erleichtern, wenn man dessen eindeutige ID nicht kennt, sondern nur "Neumann, Peter".

                                  Andererseits gibt es Arbeiten, die zwingenderweise für alle vorhandenen Datensätze ausgeführt werden müssen. Das wird man aber sinnvollerweise nicht per "Blättern" erledigen, sondern sich anhand der ID durcharbeiten. Da ist es dann garkein Problem, das blockweise zu machen und beispielsweise je 10.000 IDs zu verarbeiten (0-9.999, dann 10.000 bis 19.999) und sich nur zu merken, wie weit man gekommen ist. Neue Datensätze kommen immer nach hinten.

                                  Deine Lösung mit Flags bedeutet, daß du das "hinten" selbst definierst und für jeden Datensatz definierst, daß er sich entweder "dahinter" oder "davor" befindet, gesehen von dem Ort, an dem man sich in der Datenbank gerade befindet. Dadurch, daß du während des Blätterns diese Flags ändern mußt, hast du nochmal zusätzlich den Aufwand, in die Datenbank zu schreiben. Und das halte ich eigentlich für unnötigen Zusatzaufwand.

                                  Über Performance brauchen wir uns übrigens noch garnicht zu unterhalten, solange das Problem nicht ursächlich gelöst wurde. Daß es für alle Dinge irgendeine Index-Lösung gibt, ist klar. Das ist aber nur ein Nebeneffekt.

                                  - Sven Rautenberg

              2. Moin nochmal!

                die rote Fehlerlampe rotiert schon wieder. Au weia.

                Tja... :)

                Ich will deinen Ansatz auch noch mal grundsätzlich ins Wanken bringen:

                Wie sinnvoll ist es denn, in einer 1,5 Mio Datensätze umfassenden Datenbank die Einträge _einzeln_ durchzublättern? Sowas wird man doch eher nicht tun wollen, oder? Da sollten andere Strategien ins Spiel kommen, die den direkten Zugriff auf einen einzelnen Datensatz ermöglichen - das Durchblättern aller "Meiers" ist es sicherlich nicht.

                Wenns aber darum geht, gewisse Daten durchzublättern, und die Datenbank kann sich während des Blätterns ändern (Datensätze verschwinden, werden ergänzt, werden geändert), dann hast du ohnehin verloren beim Blättern, wenn du immer wieder den irgendwie definierten "nächsten" Datensatz abfragst. Denn dann kommt das blättern durcheinander, egal wie du deine Abfrage nun gestaltest. Dürfte auch klar sein, daß das unvermeidbar ist.

                Mir erscheint es in diesem Fall eher sinnvoll, lieber gleich alle Ergebnisse der Datenbank (möglichst mit einem Filter versehen, der hinreichend viele Einträge wegfiltert, so daß nur noch wenige Ergebnisse übrigbleiben) in eine HTML-Seite auszugeben und dann Javascript zu nutzen, um zu blättern. Geht viel schneller.

                für PREVIOUS:

                Select Kunde, ID from kontakte where ID < 19 order by kunde,id Desc limit 1

                ich müßte also nach "where kunde+ID < letzterKunde+ID ..." abfragen
                (Pseudecode)
                Geht das überhaupt? kann man in der whereklausel zwei Felder als Strings addieren?

                Du mußt dir derzeit die zuletzt benutzte ID merken. Abstrahiere (wie ich schon mindestens drei Postings lang fordere :) ) und merke dir stattdessen die Eintragsnummer in der Ergebnisliste, und filtere durch LIMIT x,y genau einen oder auch mehrere Einträge der Ergebnisliste heraus. Wenn derzeit der zweite Eintrag angezeigt wird, ist der nächste Eintrag Nummer 3. Egal was die Datenbank für Daten gespeichert hat.

                Dadurch kannst du nämlich ganz prima Initialisierungswerte festlegen: Der erste Eintrag, der gezeigt werden soll, ist immer Nummer 1. Wenn durchs blättern Eintrag Nummer 0 angezeigt werden soll, ist das eher doof, und wenn mehr als die vorhandenen Einträge angezeigt werden sollen, ist das ebenfalls doof und sollte korrigiert werden.

                In diesem Zusammenhang mein Tipp: Um nicht über das Ende der Datenbank hinauszublättern, habe ich mal bei einer Suchmaschine ganz billig immer einen Datensatz mehr im LIMIT angefordert, als ich pro Seite ausgeben wollte. Wenn dieser Extra-Datensatz existiert, gibts einen Button "Nächste Seite", ansonsten nicht.

                Ich frage mich, was dich davon abhält, einfach solch einen Zähler/Zeiger einzubauen.

                Ich bastel noch ein bisschen. Ich will vor allem, das das Resultset nicht wächst bis zum Abwinken.

                Wie groß darf das denn werden? Wird das auch auf die Platte ausgelagert, wenn es zu groß wird? Da stehen ja wohl nur Zeiger auf die eigentlichen Daten drin, oder? Dann wären es aber immer noch mindestens 8 Byte pro Feld, das man selected hat.

                Ich kann dir leider keine Tipps für die Gestaltung extrem großer Datenbanken geben, weil ich solche noch nie selbst benutzt oder erstellt habe. Im Zweifel ist deine Einflußnahme auf die Datenbank eher gering, und du mußt "nur" entsprechend ausgestattete Hardware und natürlich die für die Aufgabe passende Software zur Verfügung stellen. :) Toll, wie einfach doch Technik ist, oder? ;)

                Das einzige, was ich dir sagen kann und schon sage ist, wie ich dein Problem lösen würde - weil es nach meinen Erfahrungen mit SQL so sehr gut geht. Ok, TIMTOWTDI gilt natürlich, aber ich würde zuerst mal den ersten Gedanken verfolgen und bei Performanceproblemen dann über Alternativen nachdenken, nicht vorher.

                Du kommst um einen Punkt nämlich nicht herum: Wenn du eine sortierte Datenbanktabelle durchblättern willst, wirst du immer die gesamte Datenbanktabelle abfragen müssen, weil nur so die Datenbank feststellen kann, welches Element das nächste in der Liste ist - es sei denn, du kennst dessen ID und kannst direkt darauf zugreifen (also z.B. einfach nicht nur das nächste, sondern auch das übernächste Element abfragen, dieses aber noch nicht anzeigen). Dann hast du aber das Problem, daß du dessen Nachfolger nicht kennst und letztendlich doch immer wieder die komplette Datenbanktabelle nach der aktuellen Reihenfolge der Datensätze befragen mußt.

                Du hast also die Wahl: Entweder die Datenbank quälen und für jede Datensatzanzeige Zugriff auf die gesamte Tabelle, oder einmal Zugriff auf die gesamte Tabelle, dabei aber nur die IDs abfragen und als Reihenfolge irgendwo speichern - und Blätterzugriffe dann nur als "WHERE ID=$ID", was ziemlich schnell gehen dürfte. Dabei mußt du nur irgendwie dafür sorgen, daß 1,5 Mio IDs in ihrer Reihenfolge irgendwo abgespeichert und den jeweiligen Blätterscripten auch übergeben werden. IMO der eher unelegante Weg.

                - Sven Rautenberg

            2. Hi Sven,

              für NEXT:
              Select Kunde, ID from kontakte where ID > 19
              order by kunde,id  limit 1
              Angenommen, du bist jetzt bei der ID 4 - Dann wäre
              der nächste Datensatz die ID 1. Du selektierst aber
              nur die IDs, die größer als die 4 sind, also ID 5.
              Damit fällt der Müller/ID 1 aus deiner Liste heraus.

              Full ACK. Die WHERE-Bedingung müßte ungefähr lauten:

              WHERE (kunde=$kundenname AND ID >19
                      OR (kunde>$kundenname)

              bei ansonsten gleicher Sortierung.
              Also beide Sortier-Kriterien von Aufruf zu Aufruf
              durchreichen.

              Das löst übrigens gleichzeitig noch ein zweites
              Problem, nämlich das Verschwinden des vorherigen
              Datensatzes (durch Löschen in einem anderen Task)
              als Referenz für den nächsten.

              Ich verstehe nicht, wieso du nicht in der Lage
              bist, einfach einen Datensatzzeiger zu erfinden,
              der vollkommen unabhängig von irgendwelchen IDs
              ist, und einfach nur auf das derzeit angezeigte
              Ergebnis der sortierten Tabelle aus der Datenbank
              zeigt.

              Ich schon - denn der würde bei ständigem Einfügen
              und Löschen in dieser Tabelle massiv degenerieren.

              Im Prinzip müßte das ja (semantisch betrachtet) ein
              Binärstring sein, der die Position des Datensatzes
              innerhalb des Primärschlüsselindexbaums beschreibt.
              Dieser Baum kann aber beliebig tief werden ... und
              deshalb müßte dieses Schlüsselfeld variabel lang sein.
              Gleichzeitig wollen wir aber genau auf diesem Feld
              einen UNIQUE INDEX haben ... hm.

              Wenn du "WHERE ID > 19" abfragst und 1,5 Mio
              Datensätze hast, dann werden 1,499981 Mio
              Datensätze in eine Tabelle gelegt, dann sortiert
              nach Name und ID, und dann gekürzt auf einen
              Eintrag. Anders ist ein korrektes Ergebnis doch
              garnicht hinzukriegen.

              Wenn ein UNIQUE INDEX über dieser Spalte liegt, kann
              das RDMBS einfach diesen Baum traversieren, um ein
              ORDER BY zu realisieren.
              Es muß keineswegs alle Treffer erzeugen - nur die
              ersten 20 Stück.

              Das wird nur performant, wenn du Indices in der
              Tabelle benutzt.

              Genau das war vorausgesetzt (wg. Primärschlüssel-
              Eigenschaft der ID).

              Viele Grüße
                    Michael
              (der übrigens auch kein RDBMS kennt, welches vordefi-
              nierte PRED()- oder SUCC()-Funktionen kennt - Relationen
              sind per Definition Mengen und als solche unsortiert.)

  2. Hallo,

    Hallo Gemeinde,

    Sind wir hier in der Kirche? :)

    Wieso gibt es in SQL keine Abfrage auf NEXT und PREVIOUS?

    Wie willst du das realisieren?

    Habe ich da was übersehen? Jede vernünfte DBE hat sowas.

    Was ist eine "DBE"? Und welche Datenbank kann sowas ueber mehrere Sessions
    verteilt?

    Da kann ich mit dem Schlüssel des vorhandenen Satzes und der Angabe der
    gewünschten Sortierung einsteigen und den Nachfolger oder Vorgänger suchen
    lassen.

    Das kann man Problemlos auch mit SQL. Siehe LIMIT.

    Gruesse,
     CK

    1. Hallo,

      Hallo Gemeinde,

      Sind wir hier in der Kirche? :)

      Ich bete immer noch, dass ich mein Projekt morgen wieder auf Reihe bekomme. Mittwoch ist die erste Vorführung...

      Wieso gibt es in SQL keine Abfrage auf NEXT und PREVIOUS?

      Wie willst du das realisieren?

      Ganz einfach. Man übergibt die ID des aktiven Satzes und die gewünschte Sortierung sowie die Info, ob vorwärts oder Rückwärts (das steckt in den Funktionen NEXT(ID,ORDER) und PREV(ID,ORDER)

      Habe ich da was übersehen? Jede vernünfte DBE hat sowas.

      Was ist eine "DBE"? Und welche Datenbank kann sowas ueber mehrere Sessions
      verteilt?

      siehe oben

      Eine DBE ist eine D ata B ase E ngine, was soviel bedeutet wie Dampfmaschin vonne Datenbank...

      Da kann ich mit dem Schlüssel des vorhandenen Satzes und der Angabe der
      gewünschten Sortierung einsteigen und den Nachfolger oder Vorgänger suchen
      lassen.

      Das kann man Problemlos auch mit SQL. Siehe LIMIT.

      Nee nee nee. Das war jetzt ne Schnellschussantwort von Dir. Sooo problemlos geht das nicht. Was ist denn der nächste Datensatz von

      Meyer
      Meyer
      Meyer
      Meyer
      Meyer
      Müll
      Müller
      Opitz

      Wenn Du nicht sicher sein kannst, dass der erste Meyer dieser Liste bei Deiner nächsten Abfrage noch drin ist.

      Ich habe allerdings nicht fünf Meyers pro Tabelle, sondern 50.000 und die Meyers sind bei mir IPs...

      Grüsse

      Tom

      1. Hallo,

        Ganz einfach. Man übergibt die ID des aktiven Satzes und die gewünschte
        Sortierung sowie die Info, ob vorwärts oder Rückwärts (das steckt in den
        Funktionen NEXT(ID,ORDER) und PREV(ID,ORDER)

        Und wie sollte sortiert werden?

        Habe ich da was übersehen? Jede vernünfte DBE hat sowas.

        Was ist eine "DBE"? Und welche Datenbank kann sowas ueber mehrere Sessions
        verteilt?

        siehe oben

        Das beantwortet meine Frage nicht :) Ich habe gefragt, *welche* Datenbank sowas
        implementiert.

        Nee nee nee. Das war jetzt ne Schnellschussantwort von Dir.

        Noe.

        Sooo problemlos geht das nicht.

        Doch.

        Wenn Du nicht sicher sein kannst, dass der erste Meyer dieser Liste bei
        Deiner nächsten Abfrage noch drin ist.

        Deshalb habe ich gefragt, welche Datenbank das ueber mehrere Sessions verteilt
        kann. Das ist naemlich ein generelles Problem. Und nicht von Datenbanken,
        sondern vom Konzept her. Das wirst du mit keiner Datenbank so einfach
        hinbekommen.

        Gruesse,
         CK

  3. Huhu Tom

    Ich suche die beste Lösung für  Next und Previous

    naja die beste ist es vielleicht nicht aber sie funktioniert
    immerhin ein klein wenig.

    Ein Performance-Wunder ist es wahrscheinlich auch nicht da immer alle IDs der Datensätze eingelesen werden müssen.

    Die User-function "get_records" ist für den SELECT-query mit der entsprechenden Sortierung zuständig.

    Dann werden alle IDs in ein Array eingelesen und der Index der aktuellen ID "gemerkt".
    Dann einfach das nächste Array-Element zurückliefern.

    Previous dann entsprechend.

    function get_next_record_id($is_id)
    {
     global $data_table;
            $c=0;
     $arr_id=array();
     $result = get_records($data_table);
            while($row=mysql_fetch_array($result,MYSQL_ASSOC)){
                    $arr_id[]=$row['id'];
                    if($is_id==$row['id']) $is_row=$c;
                    $c++;
            }
            if($c==1) return $is_id;         # nur ein Datensatz vorhanden!
            if($c==($is_row+1)) return $arr_id[0];    # Vom Ende der Liste zum Anfang
            return $arr_id[$is_row+1];        # ID des nächsten Datensatzes
    }

    Viele Grüße

    lulu

    1. Hallo Lulu,

      [...]

      Warum das Ganze? Die LIMIT-Loesung ist performanter und schoener.

      Gruesse,
       CK

      1. Huhu CK

        Warum das Ganze? Die LIMIT-Loesung ist performanter und schoener.

        ja aber, angenommen man hat nur die ID des aktuell gewählten Datensatzes und das Feld nachdem sortiert wird und möchte nun zum "nächsten" Datensatz blättern, dann hilft einem doch LIMIT
        nicht weiter oder ? (zumindest wenn man den aktuellen offset nicht kennt)

        Viele Grüße

        lulu

        1. Halo LuLu,  (Halo mit einem l wie beim POP3)

          Du hast mein Problem voll erfasst.

          Warum das Ganze? Die LIMIT-Loesung ist performanter und schoener.

          ja aber, angenommen man hat nur die ID des aktuell gewählten Datensatzes und das Feld nachdem sortiert wird und möchte nun zum "nächsten" Datensatz blättern, dann hilft einem doch LIMIT
          nicht weiter oder ? (zumindest wenn man den aktuellen offset nicht kennt)

          Man kann sich mit Hilfe der ID, der ORDER, des unter Order stehenden aktuellen Wertes (können ja auch mehrere Felder sein) und der Angabe, ob vorwärts oder rückwärts ja den Rest wieder besorgen - dachte ich. Aber dann kamen die Duplicates. Meyer ist eben nicht größer als Meyer.

          Das bringt mich aber auf eine Idee. Die Sortierung muss immer über das eigentliche Sortierfeld UND den Primary Key gelegt werden. Das müßte doch gehen, oder?

          Dann gint es auch kein "gleich" mehr, sondern nur ein exactes "Größer" oder "Kleiner" und Limit 1 greift wieder.

          Ich kann Limit 1,x nämlich leider auch deshalb nicht benutzen, da die gleiche Sache nachher auch in ASP abgebildet werden soll und da kennt nur TOP x, wobei x die Anzahl der anzuzeigenden Sätze immer vom Beginn des gewählten Filterbereiches ist.

          Ich glaube, der Dialog mit Dir und Sven hat mich auf die Lösung gebracht. Jetzt muss ich das soch noch ausprobieren und kann noch nicht ins Bett...

          Tschüüüs

          Tom

          1. Yo!

            Ich kann Limit 1,x nämlich leider auch deshalb nicht benutzen, da die gleiche Sache nachher auch in ASP abgebildet werden soll und da kennt nur TOP x, wobei x die Anzahl der anzuzeigenden Sätze immer vom Beginn des gewählten Filterbereiches ist.

            Auch ASP kann an mySQL nur SQL-Kommandos schicken, die mySQL versteht. Solltest du mit "Abbildung in ASP" aber meinen, daß du hinterher eine Access-Datenbank anbinden mußt, hast du ohnehin ein Problem, weil du dann die SQL-Kommandos nochmal überarbeiten darfst - mySQLs LIMIT ist meines Wissens nur in dieser Datenbank verfügbar, andere Datenbanken haben andere Lösungen für die ausschnittsweise Abfrage.

            Ich glaube, der Dialog mit Dir und Sven hat mich auf die Lösung gebracht. Jetzt muss ich das soch noch ausprobieren und kann noch nicht ins Bett...

            Naja, solange dir die Ideen nicht ausgehen...

            - Sven Rautenberg

            1. Gähn, <-- das sollte ne Begrüßung werden

              Auch ASP kann an mySQL nur SQL-Kommandos schicken, die mySQL versteht. Solltest du mit "Abbildung in ASP" aber meinen, daß du hinterher eine Access-Datenbank anbinden mußt, hast du ohnehin ein Problem, weil du dann die SQL-Kommandos nochmal überarbeiten darfst - mySQLs LIMIT ist meines Wissens nur in dieser Datenbank verfügbar, andere Datenbanken haben andere Lösungen für die ausschnittsweise Abfrage.

              Die Statements müssen so gewählt werden, dass sie eine Entsprechnung in der "anderen SQL" haben. Der Datenbankteil der ASP-Lösung muss ja auch ganz neu in VBScript geschreieben werden. Wird eben so verlangt.

              Naja, solange dir die Ideen nicht ausgehen...

              ich werde mich bemühen

              Tom