Seite 1 von 3

Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:07
von Jan
Gerade habe ich folgendes Problem festgestellt: Wir haben eine dbf mit einen Unique-Index. Die wird etwas aufwändig gepflegt, wenn Datensätze geändert werden sollen.
- Zu ändernde Datensätze mit eine Sperrflag versehen (spezielles Datenbankfeld mit dem Bearbeiternamen füllen)
- Datensätze exportieren in eine Bearbeitungs-dbf
- Geänderte Datensätze zurückkopieren
- Datensätze mit Sperrkennzeichen löschen.

Dadurch ist gewährleistet, das auch nach einem Programmabsturz die Daten immer vorhanden sind. Entweder die alten, unveränderten, oder die neuen. Zur Not auch doppelt, aber immer unterschieden durch das Sperrkennzeichen.

Diese Vorgehensweise ist auch nicht einfach abzuändern, ich muß also prinzipiell erstmal damit klar kommen.

Nun das Problem. Der Index ist Unique. Hat also immer den ersten Datenstz im Index stehen. Wenn ich den nun lösche, ist anscheinend jeder Datensatz mit diesem Wert im Indexfeld raus. Warum? Wie kann ich das umgehen?

Jan

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:09
von Tom
DbSetOrder(0) - alle Indexe sind aktiv, aber keiner ist führend. Damit werden auch gedoppelte Einträge, die ein UNIQUE-Index eigentlich ausschließt, berücksichtigt.

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:18
von Manfred
Oder einen 2.Index mitführen, der nicht UNique ist.

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:20
von Jan
Moin Tom,

öhm, versteh ich jetzt nicht.

Alle Indizee sind geöffnet (auch der Unique), bei der ganzen Löschaktion ist ein anderer Index aktiv (nicht der Unique), da ich hier die abzuarbeitendenen Datensetze mit SCOPE eingrenze.

Jan

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:21
von Jan
Moin Manfred,

da laufen 7 oder 8 Indizee parallel mit. nicht nur der Unique. Und alle sind immer geöffnet.

Jan

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:22
von Manfred
Mit einem 2. meinte ich nicht, dass einer zu wenig ist, sondern den Unique parallel führen, aber ohne Unique eben.

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:22
von Tom
Im Prinzip hat man immer einen Index automatisch "dabei", nämlich die Datensatznummer. Keine Suche ist schneller als diese (DbGoto()). Wenn man nicht-eindeutig über einen Wert suchen will, für den es ansonsten nur einen UNIQUE-Index gibt, muss man allerdings tatsächlich einen weiteren Index aufbauen.

Was mich aber ein wenig wundert, ist die Mitteilung, die Löschung eines Datensatzes, der mit einem UNIQUE-Index referenziert ist, würde auch alle (anderen) Datensätze löschen, die dem Wert entsprechen. Das widerspricht dem gesamten Datenbankmodell; man "steht" immer nur auf einem Datensatz - bei UNIQUE eben dem (historisch) ersten, der mit diesem Wert erfasst wurde. Wenn man den löscht, müsste eigentlich der nächste Datensatz "auftauchen", der dem Wert entspricht. Es sei denn, die Löschroutine ist falsch programmiert.

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:26
von Jan
Tom,

genau das hatte ich auch erwartet - wird der Satz mit dem Unique-Zeiger gelöscht, kommt der nächste mit dem passenden Wert in den Index. Vor Allem, weil das Löschen nicht nur Löschen bedeutet, sondern vorher wird der Indexwert noch auf 0 gesetzt. Und es bleiben immer noch Sätze über mit dem Indexwert, denn es gibt ja die geänderten zurückkopierten.

Jan

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:26
von Tom
Hä?

Du löschst in einer Tabelle, die x Indexe hat, davon ist einer UNIQUE. Und der ist beim Löschen nicht aktiv? Oha. Du denkst aber daran, ihn nach dem Löschen neu zu erzeugen, ja? Was hat die Frage dann mit UNIQUE zu tun? Grundsätzlich sollte man bei Änderungen/Löschungen immer alle Indexe geöffnet haben, sonst muss man sie manuell pflegen.

Du hast da irgendwo ein Problem in Deiner Löschroutine. Ein bisschen Beispielcode könnte nicht schaden.

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:48
von Jan
Tom,

was meinst Du mit "Index ist nicht aktiv"? Alle zur dbf gehörenden Indizee sind offen. Und werden dadurch natürlich auch mitgeführt. Auch der Unique ist offen. Sollte also ebenfalls aktualisiert werden. Oder mißverstehe ich da etwas Grundlegendes?

Jan

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 11:53
von Tom
Hallo, Jan.

Ich verstehe Deine Problembeschreibung nach wie vor nicht, vermute aber, dass Du in ein simples Problem läufst. Du hast eine Tabelle geöffnet, irgendein Index ist aktiv. Jetzt setzt Du beispielsweise ein Scope auf diese Tabelle. Du bist nun der Meinung, alle Datensätze, die der Scope-Bedingung entsprechen, einfach so löschen zu können:

Code: Alles auswählen

DO WHILE !Eof()
  DbDelete()
  DbSkip()
ENDDO
Das ist aber nicht richtig. Du löschst einen Datensatz, der dem Scope entspricht, also dem führenden Index genügt. Damit fällt dieser Datensatz automatisch aus dem Scope, nur nicht mit SET DELETED OFF. Der Datensatzzeiger bewegt sich automatisch weiter auf den nächsten Datensatz, sonst wäre der Scope falsch. Du überspringst also immer einen Datensatz und löschst nur die Hälfte. :wink:

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:08
von Jan
Hallo Tom,

nene, da achte ich schon drauf. Das Löschen funktioniert einwandfrei. Kein Datensatz wird übersprungen. Aber es steht auch keiner der übriggeblieben, also geänderten, Sätze mehr im Unique-Index. Und DAS ist das Problem.

Wie wir beide oben schon gemutmaßt haben, sollte beim Löschen des Datensatzes, der den Unique-Zeiger hat, der Zeiger auf den nächsten Satz gehen, der der Indexbedingung entspricht (sofern es noch einen weiteren gibt). Tut der aber offensichtlich nicht. Und DAS Problem muß ich lösen.

Jan

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:14
von AUGE_OHR
Jan hat geschrieben:genau das hatte ich auch erwartet - wird der Satz mit dem Unique-Zeiger gelöscht, kommt der nächste mit dem passenden Wert in den Index.
... probiere mal diesen Code

Code: Alles auswählen

PROCEDURE MAIN
LOCAL i,j

   CLS
   SET DELETE ON

   IF !FILE("TEST.DBF")
      C_TEST("TEST.DBF")
   ENDIF

   USE TEST.DBF EXCLUSIVE
   ZAP

   FOR i := 1 TO 3
      j := 1
      FOR j := 1 TO 16
         APPEND BLANK
         REPLACE TEXT   WITH CHR(j+64)
         REPLACE NUMMER WITH RECNO()
      NEXT
   NEXT
   GO TOP
   BROWSE()

   GO TOP
   INDEX ON TEST->TEXT TO TEST.NTX UNIQUE
   BROWSE()

   SEEK "J"
   IF FOUND()
      ? "l”sche record :"+STR(RECNO())
      WAIT
      DELETE
   ENDIF
   BROWSE()

   SEEK "J"
   IF FOUND()
      ? "GEFUNDEN ??? ...record :"+STR(RECNO())
      WAIT
   ELSE
      ALERT("NICHT GEFUNDEN !!!")
   ENDIF
   BROWSE()

RETURN

FUNCTION C_TEST(datei,alias,id)
LOCAL p,field_list:={}
  if valtype(datei)!="C"
    datei="TEST.DBF"
  endif
  if valtype(alias)!="C"
    p=at(".",datei)
    alias=if(p>0,substr(datei,1,p-1),datei)
  endif
  if valtype(id)!="N"
    id=0
  endif
  select (id)
  if !file(datei)
    aadd(field_list,{"TEXT","C",10,0})
    aadd(field_list,{"NUMMER","N",10,0})
    dbcreate(datei,field_list)
  endif
return(.t.)
da "rückt nichts auf" !

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:21
von Jan
Jimmy,

ist ja nett, das Du den ganzen Code hier schreibst. Aber wie bitte löst das jetzt mein Problem? Nur weil EIN Datensatz in einer dbf gelöscht wird, dürfen doch nicht alle Datensätze, die den gleichen Indexwert haben, aus dem Unique-Index rausfliegen!

Jan

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:24
von Manfred
nochmal kurz nachgefragt:

Wird der Satz nur als gelöscht gekennzeichnet, oder wird der auch "genullt"? Das konnte ich jetzt aus dem ganzen Text nicht genau erkennen.

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:26
von Tom
Manfreds Nachfrage ist so uninteressant nicht. Wenn man Inhalte ändert, ändert sich natürlich auch die Datensatzfolge gemäß kontrollierendem Index. Das ist auch so eine Falle.

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:28
von Tom
Übrigens, Jimmy:

Tabelle Kunden, Index UNIQUE auf Name. Tabelle enthält "Meier", "Meier", "Müller", "Schulz".

Code: Alles auswählen

DbSeek('Meier') -> Datensatz 1
DbSkip() -> Datensatz 3

DbGoTo(1)
DbDelete()
DbSeek('Meier') -> Datensatz 2

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:32
von Jan
Wie ich oben schon schrieb, wird der erst genullt, dann gelöscht. Aber Das kann doch nicht der Grund sein, das der aus dem Unique-Index komplett rausfliegt! Es gibt immerhin noch reihenweise (ungelöschte) Sätze, die ebenfalls den Wert haben. Die sind danach aber unauffindbar, wenn ich den Unique aktiviere. Nach meinem bescheidenen Vorstellungsvermögen ist das aber grundsätzlich falsch.

Jan

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:41
von Manfred
Nur mal so eingeworfen, hast Du schonmal versucht ein DbSkip(0) oder irgendeine Datensatzbewegeung danach zu machen? Vielleicht ist es ja so wie wie bei Filter, das man erstmal das Teil wieder aktualisieren muß?

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:45
von brandelh
Hallo Jan,

dein Verständnis für Indexdateien ist falsch !

Beim Anlegen werden alle Datensätze durchsucht und in den Index einbebaut, die der FOR / WHILE Bedingung entsprechen.
Ändert sich ein Indexkey Datenfeld, werden die Verweise auf den Vorgänger, Nachfolger neu gesetzt.
Beim Löschen ist es genauso, der Vorgänger wird mit dem Nachfolger verbunden, der einzelne Satz fliegt aus dem Index raus
(bei FOR ! deleted), bzw. wird übersprungen.
Neue Datensätze werden durch APPEND in die DBF und den Index eingefügt.

Was ist nun bei UNIQUE ?

Der einzelne Satz mit dem KEY fliegt raus oder wird übersprungen, der Vorgänger wird mit dem Nachfolger verbunden.
Eine erneute SUCHE ob eventuell noch andere mit dem Schlüssel vorhanden sind findet nicht statt !
Dafür wäre ja ein Reindex nötig, der sehr viel Zeit benötigt !

Du könntest einen REINDEX auf dem UNIQUE machen oder die Indexe nach Löschung neu aufbauen ...
oder überdenken ob du ohne auskommst !

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:50
von Manfred
Hubert,

ich glaube da hast Du Jan falsch verstanden, oder wie auch immer. Er meint sicherlich nur, dass der nächste (so wie Du beschreibst) nachrücken müßte. Und das sollte ja wohl sein. Aber die Frage ist, warum es nicht aktualisiert wird?

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:53
von brandelh
Manfred hat geschrieben:Hubert,
ich glaube da hast Du Jan falsch verstanden, oder wie auch immer.
Er meint sicherlich nur, dass der nächste (so wie Du beschreibst) nachrücken müßte. Und das sollte ja wohl sein. Aber die Frage ist, warum es nicht aktualisiert wird?
Ne Manfred,
du bist auch auf dem Holzweg ;-)
Im Index ist genau ein Eintrag pro Datensatz !
Bei UNIQUE wird kein zweiter Eintrag mit dem gleichen Indexschlüssel angelegt, die Indexdatei kennt also keine weiteren Datensätze mit gleichem Index.
Wenn der einzelne Datensatz der im Index ist nun per set deleted on übersprungen wird, oder mit FOR ! DELETED() direkt rausfliegt
wird da nicht noch gesucht ob eventuell ein anderer passen könnte ! Das wäre nämlich ein implizietes reindex, was viel zu lahm ist und eventuell auch die Rechte nicht passen !

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:57
von brandelh
Man könnte einem CUSTOM Index das gewünschte Verhalten beibringen, aber ich würde mir eher überlegen den normalen Index zu nutzen
und das UNIQUE wenn nötig über eine Filterfunktion zu realisieren.

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 12:58
von Tom
Nein, Hubert hat Recht.

Ich erzeuge eine Tabelle mit 4 Einträgen, Index UNIQUE auf "NAME", wie im obigen Beispiel. Ich aktiviere den Index, wobei keine Rolle spielt, ob er führend ist oder nicht. Dann lösche ich den ersten Eintrag "Meier". Schalte ich auf den führenden UNIQUE-Index, wird mir jetzt auch der zweite "Meier" nicht angezeigt. Er ist aber NICHT GELÖSCHT, er fehlt nur im Index - tatsächlich gelöscht (Markierung im Datensatz) ist lediglich der erste Meier. Trotzdem ist der zweite Datensatz weg, solange der Index aktiv und führend ist - mit SET ORDER TO 0 erscheint er wieder. Wenn ich die Tabelle ohne Index öffne, sehe ich den zweiten Meier ebenfalls. Nach einem Reindex sehe ich ihn auch wieder. Aber ein UNIQUE-Eintrag wird nicht "nachgerückt".

Re: Vorgehensweise bei Unique Index

Verfasst: Mo, 02. Apr 2012 13:05
von Jan
Tom,

nur zum Verständnis: Wenn ich den ersten und den zweiten und den dritten Satz lösche, dann ein DbSetOrder(0) mache, und dann auf den Unique-Index gehe, dann wird der vierte Datensatz (bzw. dann natürlich der neue erste) angezeigt?

Ich frag nur, weil mir das etwas nach geheimnissvolle magische Blackbox klingt.

Jan