Announcement

Collapse
No announcement yet.

Datensatz n - m zurückliefern, nicht die kompletten Daten

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Datensatz n - m zurückliefern, nicht die kompletten Daten

    Hallo Forum,

    suche eine SQL Abfrage, die mir aus einer Datenbank den z.b. 1. - 3. oder 4. - 20. Datensatz zurückliefert.

    Die Daten möchte ich vorher nach Datum sortieren. Nach dieser Sortierung sollen eben dann der 3. oder 2. - 24. Datensatz zurückkommen.

    Danke, Micha

  • #2
    Welche Datenbank-System.

    Je nach System kann man mit TOP (MS-SQL) oder LIMIT (MySQL) die zurückgelieferte Datenmenge einschränken. Genauere Infos liefern dazu dann die SQL-Beschreibungen der Datenbanken

    Comment


    • #3
      Hallo,

      falls der MS SQL Server verwendet wird, stehen verschiedene Techniken zur Verfügung. Am einfachsten ist der Rückgriff über IDENTITY. Angenommen, in der Datenbank wird die folgende Tabelle verwendet:
      <pre>
      <b>USE</b> tempdb
      <b>GO</b>
      <br>
      <b>CREATE</b> <b>TABLE</b> Customers (
      CustNo <b>INTEGER</b> <b>NOT</b> <b>NULL</b> <b>PRIMARY</b> <b>KEY</b>,
      LastName <b>VARCHAR</b>(10) <b>NOT</b> <b>NULL</b>,
      FirstName <b>VARCHAR</b>(10) <b>NOT</b> <b>NULL</b>)
      <b>GO</b>
      </pre>
      Solange die Ergebnismenge nicht nach einer anderen Spalte sortiert werden muss, könnte man dann zum folgendne Trick greifen: Es wird in einer aus 2 Aufrufen bestehenden Batch-Anweisung zuerst eine temporäre Tabelle erstellt, die von INDENTITY durchnummeriert wird. Danch greift man auf eine <b>BETWEEN</b>-Einschränkung der Ergebnismenge zurück, um eine Teilmenge abzufordern:
      <pre>
      <b>SELECT</b> <b>IDENTITY</b>(<b>INT</b>,1,1) <b>AS</b> RowNumber, *
      <b>INTO</b> #TmpCustomerTbl
      <b>FROM</b> Customers;
      <b>SELECT</b> * <b>FROM</b> #TmpCustomerTbl
      <b>WHERE</b> RowNumber <b>BETWEEN</b> 3 <b>AND</b> 6
      </pre>
      Alternativ kann man auch auf die folgende Technik zurückgreifen: Es wird SELECT TOP x genutzt, um die Anzahl der Ergebnismenge zu begrenzen. Zusätzlich schränkt eine WHERE-Einschränkung mit der Bedingung <i>Sortierspalte > @DerZuletztVerwendeteWert</i> die Ergebnismenge ein. Die bedeutet aber, dass der Client in einer Variablen den jeweils letzten (höchsten) Spaltenwert speichern muss

      Comment


      • #4
        Hallo nochmal, DBMS ist Oracle in der Version 9.

        Comment


        • #5
          Hallo, also

          "select * FROM Tabelle WHERE RowNumber BETWEEN 1 AND 3"

          versteht die Enterprise Manager Console hier nicht, Fehler "Ungültiger Spaltenname"

          Bye, Mich

          Comment


          • #6
            Vieleicht hilfts:

            select * from (
            select rownum id, object_name from user_objects
            )
            where id between 3 and 5

            und eine TempTabelle zu benutzen... also wirklich nicht Oracle like

            Comment


            • #7
              hallo,

              ja, dass mit der ID habe ich hinbekommen, nur es ist das Problem: ich bekomme jetzt zwar datensätze, die gemäß der ID zwischen 3. und 5. Satz liegen, nur diese Datensätze entsprechen nicht der Eingabesequenz, soll heißen:

              ein ergebnis, geordnet nach aufsteigender ID heißt nicht, dass die Datensätze in dieser Reihenfolge auch eingegeben wurden. Dies verdeutlicht erst die Spalte Datum.

              Acuh folgendes Problem: ersten 3 datensätrze liefern: ID BETWEEN 1 AND 3
              -> Problem: Meine IDs beginnen bei 400 z.B.?

              Ich müsste also irgendwie zuerst ein Count(*) machen, und dann von dieser Anzahl eben die ersten drei ausgeben oder eben 10. - 24. z.B

              Comment


              • #8
                die rownum ist eine Pseudospalte und zählt die Zeilen also 1,2,...
                Du kannst also jede Query benutzen
                und einschränkende Bedingungen haben.
                Statt id nenn sie einfach Zeile.
                Pass aber beim order by in Verbindung
                mit rownum auf.
                1. select rownum zeile, object_name from user_objects order by last_ddl_time

                und dann:
                select * from (
                select rownum zeile, object_name from user_objects order by last_ddl_time
                )
                where zeile between 3 and

                Comment


                • #9
                  Hallo Mich und Achim,

                  um unter Oracle nur eine bestimmte Anzahl von Zeilen einer <b>sortierten></b> Menge zurückzugeben wird es noch ein wenig komplizierter Die Pseudospalte ROWNUM wird nämlich <b>vor</b> dem Ausführen der Sortierung hinzugefügt. (Zumindest ist das bis 8i so) Die Abfrage im o.g. Bsp. wird also nicht das gewünschte Ergebnis bringen. Man müßte also ein dreifach geschachteltes SELECT machen:
                  1. Eigentliche Abfrage mit Sortierung
                  2. Hinzufügen der Pseudospalte ROWNUM
                  3. Abfrage mit Einschränckung auf den Bereich<pre>
                  select inner.* from (
                  select rownum zeile, absolut_inner.*
                  from (
                  select object_name
                  from user_objects
                  order by last_ddl_time) absolut_inner
                  ) inner
                  where zeile between x and y</pre>
                  Wenn ich mir jetzt noch überlege, was passiert wenn zwischen dem Abrufen der DS 1 - 100 und 101 - 200 ein anderer Nutzer einen DS aus diesem Bereich löscht oder einen darin passenden Einfügt, dann könnte ich mich eher mit einer Temporären Tabelle anfreunden

                  Gruß Fal
                  Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

                  Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

                  Comment


                  • #10
                    deswegen mein Hinweis.
                    So würde das dann aussehen:
                    select * from (
                    select rownum, zeile, object_name from (
                    select rownum zeile, object_name from user_objects
                    order by last_ddl_time
                    ))where zeile between 3 and 5.

                    Ich glaube aber nicht, dass das Löschen eines Datensatzes von einem anderen User mein Select beeinträchtigt. Ich habe ja eine Lesekonsistenz.

                    Evtl. gibt es ab 9 auch Funktionnen, die mir so ein Sample generieren.

                    Gruß Joachi

                    Comment


                    • #11
                      Hallo Joachim,

                      natürlich hast du Lesekonsistenz, das hindert aber niemanden, in der Zwischenzeit die Datenmenge zu verändern. Bsp.: Du laßt dir zuerst die Sätze 1-10 anzeigen. Jetzt löscht jemand DS 8. Danach rufst du die Sätze 11 - 20 ab. Das ist ein völlig neuer Cursor, der mit der Lesekonsistenz des ersten nichts mehr zu tun hat. Der aus erster Sicht 11. Satz ist jetzt Satz 10 (da ja zwischendrin einer gelöscht wurde) Du würdest also beim "Durchblättern" den alten DS 11 glatt "übersehen".
                      Ich wollte damit sagen, das dieses Verfahren seine Tücken hat um damit eine Datenmenge "Blockweise" durchblättern zu wollen. Wenn ich eh nur eine Stichprobe brauche dann ist es OK, um aber eine Datenmenge in Blöcken zu X-Stück durchzuackern ist es nicht geeignet, da ich nie sicher sein kann, das mir ein DS verlorengeht (ein DS der bereits "gesehenen" wird gelöscht) oder ich einen doppelt erwische (zwischen die bereits "gesehenen" wird einer eingefügt)

                      Gruß Fal
                      Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

                      Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

                      Comment


                      • #12
                        Hallo Joachim,

                        RDMS arbeitet auf die Schritten
                        1. Die Sortierung der Daten
                        2. Select
                        Im zweiten Punkt funktionieren alle Methoden (b.w. einer Cursor und ähnlich)
                        Aber du wirst nicht den ersten Punkt umgehen.

                        Gruß Ale

                        Comment


                        • #13
                          Ja hallo nochmal, wie macht man das da mit der Konsistenz?

                          Nehmen wir an: 2 Nutzer haben Datensatz mit der ID 1 geöffnet, der eine will ihn löchen, der andere hat ihn geöffnet zwecks Bearbeiten,

                          So, Nutzer 1 löscht den.
                          Wenn der andere Nutzer dann auf Aktualisieren feuert, dann steht der Datensatz ja wieder drinne sozusagen?

                          Kann man da was machen? einen LOG auf eine Datenreihe setzen, dass dieser gerade in Benutzung? Macht das die DB, ORACLE, automatisch und liefert dann keine Datensätze zurück, wenn andere diese Bearbeiten, oder kann man da via SQL ne Schreibsperre setzen, sodaß andere User dann eine Meldung erhalten á la "Da is gerade jemand am Werkeln" ?

                          Danke, Mich

                          Comment


                          • #14
                            Hallo Micha,

                            ORACLE setzt entsprechende Sperren auf die Datensätze automatisch. D.h. bei jedem DML (Insert, Update, Delete) wird der DS und ggf. die Tabelle für weitere Aktionen gesperrt - und zwar solange bis ein COMMIT oder ROLLBACK (als Transaktionsende gegeben wird). Versucht in der Zwischenzeit jemand ein weiteres Update auf den gleichen DS, dann wartet die Transaktion solange, bis die erste Transaktion abgeschlossen wird. (ES sei denn es wird NOWAIT angegeben).

                            Nun kann es natürlich vorkommen, das ein User A die Daten in die Änderungsmaske holt (SELECT), dann ewig wartet - in der Zwischenzeit ändert die gleichen Daten der User B erfolgreich - und dann irgendwann abspeichert. Ergebnis: Nur die Änderungen von A sind sichtbar, das von B wurde komplett überschrieben. Um dies zu verhindern mußt du die Applikationslogik ändern. Das SELECT zum holen der Daten in die Änderungsmaske sollte dann am Ende ein FOR UPDATE [NOWAIT] enthalten. Dabei werden sämtliche durch die Abfrage betroffenen DS (wie bei einem Update gesperrt). Ein Anderer User bekommt jetzt die Daten erst in die Änderungsmaske, wenn User A seine Änderungen gespeichert oder Verworfen hat.
                            Ohne NOWAIT wartet die Transaktion B bis Transaktion A abgeschlossen wurde. Bei Angabe von FOR UPDATE NOWAIT schlägt das komplette SELECT mit einer Exception ORA-00054: resource busy and acquire with NOWAIT specified fehl, wenn der betreffende DS bereits gesperrt ist - eine gute Gelegenheit die Meldung "Da is gerade jemand am Werkeln" auszugeben.

                            Gruß Fal
                            Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

                            Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

                            Comment


                            • #15
                              Hallo Falk und Forum,

                              soll heißen, wenn Nutzer B Datensätze in sein FrontEnd laden möchte, sagen wir 100, und Nutzer A macht gerade im Satz 33 rum, dann bekommt Nutzer B diese ORA Exception gefeuert und somit keinen einzigen Datensatz zurück?

                              Gibts da eine Variante, das er nur die Sätze bekommt, die eben nicht gesperrt sind, also das ORACLE automatisch ausssiebt? Ich meine , sonst könnte der Nutzer B ja verhungern, wenn er was modifizieren will, und immer sind gewisse andere Nutzer am Start, die die gewünschten Sätze gerade in Ihre Maske geladen haben und ändern könnten.

                              Okay, Danke, Mich

                              Comment

                              Working...
                              X