In ACCESS gruppierte Spalte sortiert hochzählen

Hallo mindflat,

eine Beispiel-Datenbank ist gar nicht notwendig.
Schreib einfach ein Beispiel als Text.

Quelle:
Land Stadt Str.
D Dortmund Bahnhofstr.
D München Leopoldstr.
D München …
GB London …

Zeil:

Aber bitte mit mehr Daten.

Gruß
Andreas

Hallo JOGI,

also ich habe eine Tabelle mit folgenden Spalten:

  • Land
  • Stadt
  • Straße
  • Nachname
  • Vorname
  • SortNr

Gruppiert werden sollen diese Spalten:

  • Land
  • Stadt
  • Straße

Sortiert werden soll über (in der Reihenfolge):

  • Land
  • Stadt
  • Straße
  • Nachname
  • Vorname

In der letzten Spalte „SortNr“ soll jetzt ein Wert hochgezählt werden, solange die Einträge für die Gruppierung gleich bleiben und unter Berücksichtigung der Sortierung.

Solange also in den ersten drei Spalten „Deutschland“, „Düsseldorf“ und „Hansa-Allee“ steht, soll hochgezählt werden, der Schmidt-Anton vor dem Schmidt-Egon.

Danach wieder bei „0“ anfangen, usw.

Zu schade, dass man keine Dateien hochladen kann. Ich habe nämlich eine Beispiel-Datei vorbereitet…

Danke und Gruß!

mindflat

Hallo Andreas,

anbei ein paar Zeile mit Beispielen:

Land Stadt Strasse Nachname Vorname SortNr
D Köln Oststr. Schmidt Dieter 1
D Köln Oststr. Schmidt Johannes 2
D Köln Oststr. Schmidt Peter 3
D Köln Südring Schüssler Dieter 1
D Köln Südring Schüssler Günther 2
D Bern Bachstr. Müller Anton 1
D Bern Seestr. Meier Egon 2
D Bern Seestr. Kopp Petra 1
FR Paris Rue Pierro Jaques 1
FR Paris Ave Kaas Pat 1

Danke und Gruß!

mindflat

Hallo fonti46,

das ist ja bis hierher wunderbar. Der Code macht genau das, was ich wollte. Danke dafür.

Jetzt habe ich noch zwei Fragen:

Wenn ich sehr viele Daten nehme (1.600.000 Datensätze), bekomme ich relativ schnell (bei Datensatz 9.494) eine Fehlermeldung, die da lautet:

„Anzahl der Dateisperrungen überschritten. (Fehler 3052)“

Wenn ich dann debugge zeigt der gelbe Marker auf den Code-Eintrag „rs.Edit“.

Was könnte das sein?

Wäre es auch möglich, die Sortierung nicht über eine Abfrage zu machen, sondern ebenfalls in den Code einzubauen?

Denken Sie es wäre grundsätzlich möglich, die ganze Sache in einen SQL-String einzubauen? Andere schlaue Leute schrieben etwas von einer Count-Anweisung…?

Danke für eine Antwort und ein schönes Wochenende noch!

Gruß!

mindflat

mit sovielen Datensätzen habe ich nicht gerechnet. Der Grund dafür ist: die geänderten Datensätze werden immer zurückbehalten um die Aenderungen wieder rückgängig machen zu können. Nach ca 9000 Aenderungen ist Schluss damit, darum erledige ich das jetzt alle 1000 Datensätze im Programm. Diese Datenmenge könnte bei der Auswertung (Zeit-)Probleme schaffen, um diese zu beheben müsste ich allerdings mehr über den Gebrauch nachher wissen (müssen die Daten noch bearbeitet werden, ist das einlesen einmalig usw.) Es könnte auch sein, dass das Aendern immer langsamer wird. Ich habe drum einen Timer eingebaut, der alle 100000 die verwendete Zeit auflistet. SQL ist natürlich auch möglich, bietet aber keine Vorteile, das Resultat ist ja eh nur mit der Abfrage ersichtlich. Der Count Befehl funktioniert m.E. nicht weil drei Kriterien abgefragt werden müssen


Public Sub Numerieren()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim lgZähler, lgCommit As Long
Dim strLand, strStadt, strStrasse As String
Dim datAnf, datEnd, datCalc As Date
lgZähler = 0
lgCommit = 0
Set db = CurrentDb
'Set rs = db.OpenRecordset(„qrySortNr“)
Set rs = db.OpenRecordset(„SELECT Adressen.Land, Adressen.Stadt, Adressen.Strasse, Adressen.Nachname, Adressen.Vorname, Adressen.SortNr FROM Adressen ORDER BY [Adressen].[Land], [Adressen.Stadt], [Adressen.Strasse], [Adressen.Nachname], [Adressen.Vorname]“)
rs.MoveFirst
strLand = rs!land
strStadt = rs!stadt
strStrasse = rs!strasse
datAnf = Now
Do While Not rs.EOF
If strLand = rs!land _
And strStadt = rs!stadt _
And strStrasse = rs!strasse _
Then GoTo zählen
’ Gruppenbruch festgestellt
lgZähler = 0
strLand = rs!land
strStadt = rs!stadt
strStrasse = rs!strasse
lgZähler = 0
’ kein Gruppenbruch
zählen:
lgZähler = lgZähler + 1
rs.Edit
rs!SortNr = lgZähler
rs.Update
lgCommit = lgCommit + 1
’ immer nach 1000 Datensätze deren Lock wieder aufheben
If (lgCommit Mod 10) = 0 Then
DBEngine.BeginTrans: DBEngine.CommitTrans
End If
’ gegebenenfals wieder löschen
'--------------------
If (lgCommit Mod 100000) = 0 Then
datEnd = Now
datCalc = datEnd - datAnf
MsgBox lgCommit & " Datensätze in " & datCalc & " Sekunden", vbOKOnly
End If
'--------------------
rs.MoveNext
Loop
Set rs = Nothing
Set db = Nothing
End Sub

Hallo mindflat,

um sicher zu stellen, dass ich mir über das Richtige Gedanken mache:
Du brauchst eine Abfrage in welchem die Spalte SortNr berechnet wird und entsprechend ein anderes Ergebnis liefert wenn Datensätze hinzugefügt oder gelöscht werden.
Habe ich das so richtig verstanden?

Gruß

Andreas

Hallo mindflat,

ich nehme mal an, dass die SortNr nicht in der Tabelle Land/Stadt/Strasse erscheinen soll. Bei Änderung der Datensätze muss diese dann auch geändert werden. Ich würde ein Unterformular der Tabelle Land/Stadt/Strasse erstellen, dieses um ein ungebundenes Textfeld ergänzen, in der die SortNr erscheinen soll.
Die Generierung der SortNr erfolgt in einen Formular über eine Ereignisprozedur, z.B die einer Befehlsschaltfläche. In der Prozedur wird die Tabelle Land/Stadt/Strasse in der Sortierreihenfolge als Recordset geöffnet und in einer Schleife jede Recordsetnummer dem ungebundenen Textfeld zugeordnet.

Gruß
Horst Müller

Hallo mindflat,

so in etwa könnte die Prozedur aussehen

dim rsin as recordset
dim zaehler as integer
dim gruppe_alt as string
dim gruppe_neu as string
dim str as string

str=„select * from tabellenname order by
land,stadt,strasse,nachname,vorname“

set rsin=currentdb.Openrecordset(str)
do until rsin.eof
gruppe_neu=rsin!land & rsin stadt & rsin!strasse
if gruppe_alt gruppe_neu then
zaehler=0
gruppe_alt=gruppe_neu
else
zaehler=zaehler + 1
end if
rsin.edit
rsin!SortNr=zaehler
rsin.update
rsin.movenext
loop

ist aber nicht gestestet.

Gruß
JOGI

Hallo und entschuldigung, dass ich mich nicht melden konnte.

Was ich brauche ist eine Abfrage, Modul oder Makro, welches statisch einmalig aufgrund der Parameter Einträge in der Spalte „SortNr“ vornimmt. Also keine dynamische Aktionen. Wenn ein neuer Datensatz hinzugefügt wird, oder ein vorhandener editiert wird, hat das keinen Einfluss auf die bisherigen Einträge.

Am liebsten wäre mir eine Abfrage.

Danke und Gruß!

Hallo Horst Müller,

ich benötige keine dynamischen Aktionen, sondern lediglich eine Abfrage, Makro oder Modul, welches an den vorhandenen Werten und Parametern einmalig Einträge in der Spalte „SortNr“ vornimmt. Sollten neue Datensätze hinzukommen oder vorhandene editiert werden, beeinflusst dieses nicht die bereits gemachten Einträge.

Die Parameter:

also ich habe eine Tabelle mit folgenden Spalten:

  • Land
  • Stadt
  • Straße
  • Nachname
  • Vorname
  • SortNr

Gruppiert werden sollen diese Spalten:

  • Land
  • Stadt
  • Straße

Sortiert werden soll über (in der Reihenfolge):

  • Land
  • Stadt
  • Straße
  • Nachname
  • Vorname

In der letzten Spalte „SortNr“ soll jetzt ein Wert hochgezählt werden, solange die Einträge für die Gruppierung gleich bleiben und unter Berücksichtigung der Sortierung.

Solange also in den ersten drei Spalten „Deutschland“, „Düsseldorf“ und „Hansa-Allee“ steht, soll hochgezählt werden, der Schmidt-Anton vor dem Schmidt-Egon.

Danach wieder bei „0“ anfangen, usw.

Danke und Gruß!

mindflat

Hallo fonti46,

herzlichen Dank für diese erneut präzise Ausfertigung. Alle Datensätze (immerhin 1.600.000) werden exakt und in guter Geschwindigkeit abgearbeitet. Ich bin wirklich sehr begeistert und würde gerne mit Ihnen Kontakt aufnehmen, um über eine generelle Zusammenarbeit zu sprechen. Wenn Sie Interesse haben, können Sie mir gerne Ihre Mail-Adresse oder Tel.-Nr. zukommen lassen.

Herzlichen Dank und Gruß!

mindflat

Hallo mindflat

Freut mich, dass ich Ihnen helfen konnte. Falls noch weitere Probleme auftauchen bei der Weiterverarbeitung bin ich Ihnen natürlich gerne noch behilflich. Ich bin diese Jahr, nach 15 Jahren selbständiger Access-Programmierung in Rente gegangen und es dürfte natürlich nicht in Stress ausarten :smile:. Es würde mich noch interessieren wie lange es etwa gedauert hat. Meine e-Mail Adresse ist:

[email protected]

Herzliche Grüsse

fonti46

Hallo JOGI,

bitte entschuldigen Sie die späte Reaktion. Ihre Antwort muss ich wohl übersehen haben.

Habe die Zeilen jetzt mal in einem Modul eingebaut. Nach geraumer Zeit erscheint eine Fehlermeldung:

„Anzahl der Dateisperrungen überschritten (Fehler 3052)“

Nach dem debuggen wird der Eintrag „rsin.Edit“ gelb hinterlegt.

Das Modul aktualisiert aber bis zum Datensatz 9.495 die Spalte „SortNr“ absolut korrekt, somit ist Funktion einwandfrei!

Fairerweise muss ich noch zwei Dinge hinzufügen:

  • Ich habe das Modul an einer Tabelle mit ca. 1.600.000 Datensätzen ausprobiert. Das ist ungefähr die Menge, für die ich das Modul zukünftig verwenden muss (eher noch mehr).

  • Das Aktualisieren der Spalte „SortNr“ ist rein statisch. Wenn ein neuer Datensatz hinzugefügt, oder ein vorhandener Datensatz editiert wird, muss dieses nicht berücksichtigt werden. Die Funktion wird nur zur einmaligen Verwendung benötigt. Vielleicht ist das wichtig für Sie.

Schon jetzt möchte ich mich bei Ihnen für diesen fundierten Beitrag bedanken.

Mit freundlichen Grüßen!

mindflat

Hallo Andreas,

hattest Du mal geschaut, ob Du eine Lösung für mein Problem finden kannst? Wäre sehr nett!

Danke und Gruß!

mindflat

Hallo mindflat,

sowas passiert, wenn man nicht alle Informationen hat.
Setze noch Folgendes ein:

dim i as long

ergänze die Zeile set rsin=…
set rsin=currentdb.Openrecordset(str,dbOpenDynaset)

vor der Zeile rsin.update:
i=i+1
if i>1000 then
DBEngine.BeginTrans: DBEngine.CommitTrans
i=0
end if

Dadurch wird eine NULL-Transaktion durchgeführt.
Es werden die durch die Edit-Aktion gesperrten Datensätze in die Tabelle gespeichert und die Locks wieder freigegeben.

Gruß
JOGI

Hallo JOGI,

bitte entschuldige, dass ich nicht gleich alle Informationen bereitgestellt habe. Aber ich habe (leider) so wenig Ahnung vom Programmieren, dass ich nicht mal eindeutig entscheiden kann, was wichtig ist und was nicht…

Das Modul läuft einwandfrei durch! 1.647.201 Datensätze in unter einer Minute verarbeitet.

Das ist echt super!

Wäre es eigentlich grundsätzlich auch möglich, die Spalte „SortNr“ als Text (Länge = 9 Zeichen) mit einer festen Formatierung, z.B. „000000237“ zu füllen, also mit vorlaufenden Nullen? Somit wäre es nämlich möglich, Text so zu sortieren, als wäre es eine Zahlenspalte.
Welche Änderungen im Modul wären nötig? Wird die Performance darunter leiden?

Würde gerne auch zukünftig Deine Hilfe in Anspruch nehmen. Gegebenenfalls gegen Bezahlung. Vielleicht kannst Du Dir ja auch eine Zusammenarbeit vorstellen. Wenn Du Interesse hast, kannst Du mir ja Deine Kontaktdaten zukommen lassen.

Herzlichen Dank!

mindflat

Hallo mindflat,

das erreichst Du, wenn die Spalte ‚SortNr‘ als Text definiert ist und die Zeile

rsin!SortNr=zaehler

durch

rsin!SortNr=format(zaehler,„000000000“)

ersetzt wird

Gruß
JOGI

Hallo mindlat,

entschuldige dass ich erst heute Antworte.
Hier eine Lösung für die Aufgabe.
Erstelle ein neues Modul in Deiner Datenbank und kopiere folgenden Code rein:

Option Explicit

Function ergänzeZähler()

Dim dbs As Database
Dim rst As Recordset
Dim sql As String

Dim str_lastVergleich As String

Dim lng_SortNr As Long

sql = "SELECT [Land] & [Stadt] & [Strasse] AS Vergleich, SortNr " _
& "FROM Tabelle1 " _
& „ORDER BY Land, Stadt, Strasse“

Set dbs = CurrentDb
Set rst = dbs.OpenRecordset(sql, dbOpenDynaset)

With rst
Do While Not .EOF
If !Vergleich str_lastVergleich Then
str_lastVergleich = !Vergleich
lng_SortNr = 1
Else
lng_SortNr = lng_SortNr + 1
End If
.Edit
!SortNr = lng_SortNr
.Update
.MoveNext
Loop
.Close
End With

Set rst = Nothing

End Function

Ersetzte ‚Tabelle1‘ im sql durch den Namen Deiner Tabelle.

Dann erstellst Du ein neues Makro.
Wähle als Aktion „AusführenCode“ und füge unten bei Funktionsname "ergänzeZähler () " hinzu.
Dann alles speichern

Jetzt das Makro nur noch doppelklicken oder mit Rechtsklick ausführen.
Jetzt ist die Spalte SortNr Deiner Tabelle wie gewünscht gefüllt.

Viel Spaß

Gruß Andreas

Hallo Andreas,

herzlichen Dank für Deine Antwort. Das ist von allen mir zugestellten Lösungen diejenige, welche am schnellsten läuft. Geschwindigkeit ist hier deswegen so gefragt, da teilweise mehrere Millionen Datensätze verarbeitet werden. Dein Modul schafft 1.6 Mio. Datensätze in unter 30 sec., was ca. doppelt so schnell ist, als die beste andere Lösung.

Jetzt habe ich nur eine Frage:

Es ist jetzt so, das die Spalte „SortNr“ nicht als „Zahl“ formatiert ist, sondern als „Text“ mit einer Länge von 5 Zeichen. Die hochgezählten Werte sollen hierin mit vorgestellten Nullen erscheinen, z.B. 00001 oder 00002 usw. In den Abfragen benutze ich dafür die Funktion „Format“. Wie könnte ich das in Dein Modul einbauen?

Gruß!

mindflat

Hallo mindflat,

danke für die Blumen :smiley:
Freut mich, dass es für die richtig Lösung ist.
Das mach ich den ganzen Tag :smiley:
Schnelligkeit ist da wichtig.
Schneller wirst Du es aber nicht mehr bekommen, da es keine direkteren Datenzugriffsbefehle gibt.

Aber zurück zu Deiner Anfrage.
Die Lösung ist ganz einfach und Du hast schon den richtigen Befehl gebracht.

Ersetzt einfach im Modul die Zeile
!SortNr = lng_SortNr
durch
!SortNr = Format(lng_SortNr, „00000“)

Viel Spaß

Gruß
Andreas