AutoNr.zip
Autor: Krzysztof Pozorek
Baza w formacie MsAccess 97
Opis problemu:
Dziury w polu Autonumer powstają na skutek kasowania rekordów lub zaniechania wprowadzenia rekordu. Zdarza się, że dziury w numeracji są niepożądane.
Rozwiązanie:
Prezentowany przykład pokazuje sposób zapisywania nowych rekordów bez dziur. Przykład testowano na zestawie rekordów ok. 60 tys. rekordów. Uzyskane wyniki czasowe wynoszą ok. 1,8 sek. na dodanie nowego rekordu.
Rewelacyjne wyniki rzędu kilkudziesięciu milisekund(!) uzyskał Krzysztof Naworyta,
którego rozwiązanie cytuję poniżej (rozwiązanie Krzysztofa polega
na bardzo szybkim zawężaniu zestawu rekordów do przeszukania)
Poniżej zamieszczam rozwiązanie Krzysztofa (wersja
uaktualniona):
Option Compare Database Option Explicit Public Declare Function GetTickCount Lib "kernel32" () As Long Function APITimer() As Long APITimer = GetTickCount End Function Function FindDziura() As Long Dim db As Database Dim rs As Recordset Dim krok As Long Dim poz As Long Dim fd As String Dim mx As Long, mn As Long Dim t t = APITimer() Set db = CurrentDb Set rs = db.OpenRecordset("T", dbOpenTable)' procedura otwiera rekordset na tabeli lokalnej ' w stosunku do bazy db. ' właściwe jej posortowanie wymuszane jest ustawieniem indeksuWith rs' *** brak rekordówIf .BOF And .EOF Then FindDziura = 1 Exit Function End If' od tego momentu zaczyna się właściwe szukanie ' można szukać dziur nie tylko w kluczu głównym ' ale w którymkolwiek polu, dla którego ustawiono indeks unikalny ' ustawienie właściwości Index recordsetu typu tabela jest duuużo szybszym ' sposobem właściwego posortowania niż instrukcja "Select ... Order By" ' tu następuje główne opóźnienie - ustawienie porządku.Index = "LP" fd = "Lp"' *** dziura na początku zestawuIf .Fields(fd) <> 1 Then FindDziura = 1 Exit Function End If' *** są rekordy.MoveLast'krok = .RecordCountmn = 0 '1 mx = .RecordCount poz = mx'jeśli nie ma dziurIf .Fields(fd) = poz Then FindDziura = poz + 1 Exit Function End If' *** jesli znaleziono "przesunięcie", zacieśniaj obszarkrok = -(mx - mn) / 2 Do .Move krok poz = poz + krok'Debug.Print .Fields(fd), pozIf .Fields(fd) <> poz Then mx = poz'znak = -1, krok w stronę BOFkrok = -Int((mx - mn) / 2) Else'znak = +1, krok w stronę EOFmn = poz krok = Int((mx - mn) / 2) End If Loop Until mx <= mn + 1' *** korektaIf .Fields(fd) = poz Then Do Until .Fields(fd) <> poz'Debug.Print 1.Move 1 poz = poz + 1 Loop FindDziura = poz Else Do Until .Fields(fd) = poz'Debug.Print -1.Move -1 poz = poz - 1 Loop FindDziura = poz + 1 End If t = APITimer() - t Debug.Print "milisek: " & t End With rs.Close: Set rs = Nothing db.Close: Set db = Nothing End Function
Powyższy przykład wymaga istnienia tabeli o nazwie T i indeksowanego pola Lp (nazwa indeksu, to również Lp).
Krzysztof Pozorek