Datenbanken verbinden/verzweigen

Alle Fragen um die Programmierung, die sich sonst nicht kategorisieren lassen. Von Makro bis Codeblock, von IF bis ENDIF

Moderator: Moderatoren

Antworten
samy88

Datenbanken verbinden/verzweigen

Beitrag von samy88 »

Hallo,

mein Ziel ist es eine oder mehrere Adresse anzulegen für die die Datenbank Adressen benutzt wird. Für jede einzelne Adresse soll es möglich sein mehrere Memos anzulegen die auch wiederrum in einer Datenbank gespeichert werden sollen. Das problem ist wie verknüpfe ich diese 2 Datenbanken.

wie soll das gehen?

ABER JETZT MACH ICH ERST MAL MITTAGSPAUSE
einen guten appetit an alle
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9367
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 102 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Beitrag von Tom »

Hallo, Samy.

Das nennt man "Normalisierung". Daten, die mehrfach genutzt werden, sind nur einfach in einer Tabelle (oder mehreren verschachtelten) gespeichert, zum Beispiel Adressen, Kontakte undsoweiter. Tabellen verknüpft man hierfür mit eindeutigen Nummern (zur Vergabe eindeutiger Nummern findest Du mehrere Threads im Forum), die dann (einfachster Weg) indexiert mit DbSeek() gesucht werden, feiner und eleganter geht das mit Scopes und Relationen, gerade auch, wenn man diese Daten browsen will. Schau Dir einfach mal die Doku zu DbSetScope() und zu DbSetRelation() an.
Herzlich,
Tom
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15697
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 66 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

Hi,

wobei bei MEMOs ein eigener Feldtyp existiert. Du kannst davon mehrere Felder in einer DBF anlegen und die verbrauchen dann nur Platz für Zeiger. Die Memo Datei wird nur größer wenn auch tatsächlich Text hinterlegt wurde. Allerdings sind Memos von DBFNTX recht verschwenderisch mit dem Platz (512 Byte Blöcke). FOXCDX kann man da konfigurieren (32 Byte bis 64KByte - Standard 52 ? )

Für diese Memos brauchst du nix vorsehen, dass macht Xbase++ alleine.
Gruß
Hubert
Benutzeravatar
Rolf Ramacher
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1930
Registriert: Do, 09. Nov 2006 10:33
Wohnort: Bergheim
Danksagung erhalten: 3 Mal
Kontaktdaten:

Beitrag von Rolf Ramacher »

Hallo Sammy,

na Mittagspause beendet ? - Ich halte die Methode mit Index setzen und
dbseek zu suchen für am besten. Wie Tom geschrieben hat ist eine eindeutige Nummer wohl am sinnvollsten.
Gruß Rolf

Mitglied der Gruppe XUG-Cologne
www.xug-cologne.de
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15697
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 66 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

Hi,

da ich früher leider öffter Probleme mit defekten Indexen hatte, die nicht in einer Fehlermeldung endeten, prüfe ich bei wichtigen Sachen ob der tatsächliche Feldinhalt mit dem gewünschten übereinstimmt. Wenn nicht -> Fehlermeldung und Index neu aufbauen.

Code: Alles auswählen

if ADR->(dbseek(KUN->KundenID))
   if ADR->ID # KUN->KundenID
      Fehlermeldung neu indizieren !
   else
      ...
mit Xbase++ und Citrix-Server sind diese Probleme zwar weniger geworden, aber wer einmal nach 4 Wochen gemerkt hat, dass die Datein irgendwie nicht mehr passen (vorher viel es nicht auf :-( ) wird übervorsichtig :wink:

Zahlenfelder haben den Vorteil, dass man ohne Programmänderung später die Feldlänge anpassen kann.
Gruß
Hubert
samy88

Beitrag von samy88 »

DbSetRelation( <nWorkArea> | <cAlias>, ;
<bRelation> , ;
[<cRelation>], ;
[<cTagName>] , ;
[<cRelName>] , ;

[<lSelective>] ) --> NIL

ich hab mir des ganze zeugs mal durchgelesen. aber ich hab keine ahnung wie ich anfangen soll.

Code: Alles auswählen

///////////////////////////////////////////////////////////////////////////////
//
//  Vom Xbase++ FormDesigner generierter Klassen Code
//    Erstellt am: 02.10.2007 Zeit: 09:09:19
//
//  Contents  :
//    Diese Datei enth„lt das Ger
samy88

Beitrag von samy88 »

hier meine exe datei

http://www.file-upload.net/download-433 ... r.exe.html

um den Tabpage Memos sehen zu können muss ein Datensatz in Adressen angelegt werden
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

Beitrag von AUGE_OHR »

hi,
samy88 hat geschrieben: ich hab mir des ganze zeugs mal durchgelesen. aber ich hab keine ahnung wie ich anfangen soll. hier mein quellcode für das childwindow adressen
jeder hier im Forum hilft dir gerne, aber meinst du wirklich das jemand
deinen ganzen Source durchsieht ?
Ich muss mal die Frage stellen ob du vor Xbase++ schon mal mit Cl*pper
oder so programmiert hast damit ich weiss wie ich die Antwort verfassen
muss damit wir auf dem gleichen Level sind.
samy88 hat geschrieben: DbSetRelation()
oder auch "SET RELATION feld INTO alias" stellt eine
automatische verknüpfung zweier (oder mehr) DBF dar. Dazu gilt :
Es muss ein FELD in beiden DBF sein z.b. Kunden Nummer. Die 2st DBF
muss über das FELD einen Index haben sodas du per SEEK(Kdnr) ein
Ergebniss bekommen würdest.
Wenn du nun in der 1st. DBF eine "Bewegung" (up/down etc.) machst
wird durch das "SET RELATION TO kdnr INTO memodbf" eine automatische
syncronisation erfolgen die mit einem SEEK() in der 2st DBF zu
vergleichen ist. Du musst dich also nicht um die 2st. DBF kümmern ausser
du hast kein passendes Memo (= memodbf->( EOF() )

hoffe das beantwortet dir erstmal deine Frage. weiter Fragen gerne
willkommen aber bitte nicht deinen ganzen Source ...

gruss by OHR
Jimmy
Zuletzt geändert von AUGE_OHR am Fr, 05. Okt 2007 11:24, insgesamt 1-mal geändert.
samy88

Beitrag von samy88 »

Danke erstmal für deine/eure Hilfe. Nein, ich habe vorher noch nicht mit Clipper programmiert. Bin ganz neu in der Branche. Hatte mal vorher Java Unterricht in der Schule aber da haben wir nicht mal annähernd sowas gemacht. Ich habs schon vom prinzip verstanden.

Code: Alles auswählen

 CheckdatabaseAdressen()
   CheckdatabaseMemos()
zuerst erstelle ich die Datenbanken. Beide haben ein Feld Nummer. Dann öffne ich die Datenbanken und lege den Index auf das Feld Nummer:

Code: Alles auswählen

   IF Select( "ADR" ) > 0
   ELSE
      USE ADRESSEN ALIAS ADR NEW
      INDEX ON Upper(ADR->NACHNAME) TO Adressen
   ENDIF

   IF Select( "MEM" ) > 0
   ELSE
      USE MEMOS ALIAS MEM NEW
      INDEX ON(MEM->NUMMER) TO Memos
   ENDIF
Dann erstelle ich die verbindung:

Code: Alles auswählen

ADR->(DbSetRelation( "MEM" , ;
               {|| ADR->NUMMER } , ;
              "ADR->NUMMER")) 
Die Nummern werden auch richtig eingetragen:

LOCAL ldatensatz

ADR->(DBGOBOTTOM())
ldatensatz := ADR->NUMMER + 1

.... speichern: ADR->NUMMER := ldatensatz

memo: speichern: MEM->NUMMER := ADR->NUMMER
Zuletzt geändert von samy88 am Fr, 05. Okt 2007 11:13, insgesamt 1-mal geändert.
samy88

Beitrag von samy88 »

Fazit: Die Nummern stimmen in beiden Datenbanken.
Bei den Adressen addiert sich die Nummer immer um eins. Und die Memos bekommen die Nummer eingetragen, die in dem Feld Nummer bei den Adressen eingetragen ist.

Irgendwas sollte dann bei der Relation nicht stimmen. Es werden immer alle Memos im 2. Browse angezeigt.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15697
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 66 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

Hallo,

wenn du nur die Memos sehen möchtest, die zu deinem Hauptsatz gehören, dann musst du die Datensätze die zu diesem gehören herausfiltern. dbSetFilter() ist sehr langsam, aber dbsetScope() müsste gehen, da du ja eh einen Index haben mußt. Ich persönlich arbeite nicht mit Relationen, sondern mach das per Hand.

Code: Alles auswählen

if ADR->(dbSeek(nID))
   MEM->(dbsetScope(SCOPE_BOTH,nID))
else
   // auf EOF
   ADR->(dbGoBottom())
   ADR->(dbSkip())      
   MEM->(dbClearScope(SCOPE_BOTH))
   // auf EOF
   MEM->(dbGoBottom())
   MEM->(dbSkip())      
endif
Auf diese Weise weiß ich genau was das Programm macht, SET RELATION hat so seine Tücken - je nach Xbase++ Version.

PS:

Beim Programmieren lernen reicht es nicht aus ab und zu einige fertige Lösungen zu bekommen. Ich habe die komplette Doku zu Clipper damals etwa 3 mal gelesen, nur um zu lernen wie Clipper arbeitet, konnte damals aber schon gut BASIC programmieren. Xbase++ habe ich 2 mal komplett durchgelesen und wenn ich als etwas Zeit habe schaue ich mir Beispiele und Funktionen an, die ich selten nutze. Man vergisst einfach eine ganze Menge. Bei jeder Version arbeite ich die Unterschiede zur Vorversion durch. Auch sollte man sich allgemeiner mit Programmierung als solcher beschäftigen - die Grundlagen eben.
Gruß
Hubert
samy88

Beitrag von samy88 »

HI, der Fehler war dass ich den 6. Parameter (SELECTIVE) nicht auf .T. gesetzt habe.
Danke für eure Hilfe
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

Beitrag von AUGE_OHR »

moin,
samy88 hat geschrieben: HI, der Fehler war dass ich den 6. Parameter (SELECTIVE) nicht auf .T. gesetzt habe.
du lernst schnell :)

Tip : zu den DB... Funktionen gibt es meistens noch die "alte" Kommando
Befehle unter "siehe auch". Wenn du ein solches Beispiel per copy/paste
nimmst und mit

Code: Alles auswählen

XPP.EXE myTest.PRG /P
compilierst so macht er eine *.PPO daraus. schau dir sowas mal an.

gruss by OHR
Jimmy
samy88

Beitrag von samy88 »

Danke Jimmy, werd ich mir mal später anschauen nach der mittagspause.

Das einzigste was mir eben noch probleme bereitet hat waren die Indexe

INDEX ON Upper(ADR->NACHNAME) TO Adressen
INDEX ON (ADR->NUMMER) TO Nummer

SET INDEX TO Adressen,Nummer

ADR->(ORDSETFOCUS(1))
ADR->(ORDSETFOCUS(2))

je nach dem wie mans brauch muss man den Index auch auswählen..
das wusste ich, aber ich wusste nicht dass man vorher ein SET INDEX machen muss.

Soll ich die Lösung in die Wissensbasis eintragen?
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15697
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 66 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

samy88 hat geschrieben: Das einzigste was mir eben noch probleme bereitet hat waren die Indexe

INDEX ON Upper(ADR->NACHNAME) TO Adressen
INDEX ON ADR->NUMMER TO Nummer
Mit INDEX ON werden sie erzeugt, set index to öffnet oder schließt die wieder, aber du darfst keinen Alias in einem INDEX verwenden !
Diese Bedingung wird nämlich in der Indexdatei gespeichert, falls du nun beim nächsten Mal den Alias von ADR weg auf was anderes setzt knallt es. Außerdem kannst du nicht mit DBU etc. die Indexdatei öffnen.

Wenn du die Warnungen weg haben willst kann man entweder das Kommando FIELD oder den allgemeinen Alias field-> verwenden.

Code: Alles auswählen

LOCAL...
FIELD Nachname, nummer
...
INDEX ON Upper(NACHNAME) TO Adressen
INDEX ON NUMMER TO Nummer
oder

Code: Alles auswählen

INDEX ON Upper(field->NACHNAME) TO Adressen
INDEX ON field->NUMMER TO Nummer
Gruß
Hubert
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15697
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 66 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

samy88 hat geschrieben:Soll ich die Lösung in die Wissensbasis eintragen?
Die Wissenbasis soll Lösungen von Problemen aufzeigen, das zählt eher zu den Angangsschwierigkeiten :wink:
Gruß
Hubert
samy88

Beitrag von samy88 »

Hehe, ok :D
Dann sollte es noch ne Wissensbasis für Anfänger geben :D

Mit manchen Beispielen von der xBase++ Hilfe komm ich nämlich überhaupt nicht zurecht.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15697
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 66 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

dafür sind ja die normalen Foren da ... und die Hilfe könnte besser sein,
aber ist das nicht in vielen Programmen der Fall :wink:
Gruß
Hubert
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9367
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 102 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Beitrag von Tom »

@Samy: Es scheint mir noch wichtig, anzumerken, daß "INDEX ON" immer wieder die Indexe erzeugt, was eigentlich nicht nötig ist, da Indexe bei jeder Aktualisierung der Tabelle automatisch mitaktualisiert werden, sofern sie bei der Änderung von Datensätzen geöffnet sind. Das ist übrigens nicht ganz ungefährlich (aber das wirst Du schon noch merken :lol:), weil die Änderung des Feldwertes für einen führenden Index auch die Reihenfolge der Tabelle ändert. DbSetOrder(0) setzt - auch bei geöffneten Indexdateien - die Tabellenreihenfolge immer auf die Record Nummer.

Also: Einmalig (Programminitialisierung, für Servicezwecke in einer Routine "Datenreorganisation" oder so) alle Indexe erstellen:

Code: Alles auswählen

USE Adressen
* PACK // um ggf. gelöschte Datensätze physikalisch zu entfernen
INDEX ON Upper(name) TO ADRESSEN1
INDEX ON PLZ TO ADRESSEN2 usw.
und "Adressen" dann immer mit allen Indexen öffnen:

Code: Alles auswählen

USE Adressen INDEX ADRESSEN1, ADRESSEN2 usw.
Dadurch werden sich alle Indexe immer mitaktualisieren. "INDEX ON" zur Neuerzeugung eines Indexes verschlingt ggf. sehr viel Zeit, wenn die Tabelle viele Datensätze enthält.

(Das geht auch alles sehr viel eleganter, ist in dieser Notation aber leichter zu verstehen.)
Herzlich,
Tom
samy88

Beitrag von samy88 »

Hi,

jetzt hab ich doch noch ein Problem. Vorher war das glaub ich noch nicht so. Ich weiß aber nicht was daran schuld ist.

Wenn ich jetzt eine Adresse markiere und mir die Memos anschaue zeigt es mir immer nur ein Memo an auch wenn es mehrere Memos mit der gleichen Nummer gibt.

Ich kann irgendwie nicht ganu nachvollziehen woher das Problem jetzt kommt
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16517
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Samuel,
um das Anzeigen mehrere Memos (inhaltlich) musst Du Dich schon selber kümmern.
Xbase++ kann höchstens mehrere Memos finden und Du musst dann natürlich entsprechend genug MLEs (oder worin auch immer Du die einzelnen Texte anzeigen willst) bereithalten und entsprechend füllen...
Oder meinst Du jetzt, dass nur noch immer nur 1 Memo gefunden wird, obwohl es mehrere gibt?

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
samy88

Beitrag von samy88 »

ja es wird immer nur eins gefunden obwohl es mehrere gibt. dementsprechend wird auch immer nur eins im browse dargestellt...
samy88

Beitrag von samy88 »

naja egal, nach langem hin und her hab ich mich dann doch für Set Scope entschieden.

Fazit: viel einfacher, und es geht auch :D

trotzdem danke an alle die mir geholfen haben
Antworten