Datenbanken verbinden/verzweigen
Moderator: Moderatoren
Datenbanken verbinden/verzweigen
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
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
- Tom
- 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:
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.
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
Tom
- brandelh
- Foren-Moderator
- Beiträge: 15697
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 66 Mal
- Danksagung erhalten: 33 Mal
- Kontaktdaten:
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.
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
Hubert
- Rolf Ramacher
- Der Entwickler von "Deep Thought"
- Beiträge: 1930
- Registriert: Do, 09. Nov 2006 10:33
- Wohnort: Bergheim
- Danksagung erhalten: 3 Mal
- Kontaktdaten:
- brandelh
- Foren-Moderator
- Beiträge: 15697
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 66 Mal
- Danksagung erhalten: 33 Mal
- Kontaktdaten:
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.
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
Zahlenfelder haben den Vorteil, dass man ohne Programmänderung später die Feldlänge anpassen kann.
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
...
Zahlenfelder haben den Vorteil, dass man ohne Programmänderung später die Feldlänge anpassen kann.
Gruß
Hubert
Hubert
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.
<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
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
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
- AUGE_OHR
- Marvin
- Beiträge: 12909
- Registriert: Do, 16. Mär 2006 7:55
- Wohnort: Hamburg
- Hat sich bedankt: 19 Mal
- Danksagung erhalten: 46 Mal
hi,
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.
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
jeder hier im Forum hilft dir gerne, aber meinst du wirklich das jemandsamy88 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 adressenCode: Alles auswählen
...
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.
oder auch "SET RELATION feld INTO alias" stellt einesamy88 hat geschrieben: DbSetRelation()
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.
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.
zuerst erstelle ich die Datenbanken. Beide haben ein Feld Nummer. Dann öffne ich die Datenbanken und lege den Index auf das Feld Nummer:
Dann erstelle ich die verbindung:
Die Nummern werden auch richtig eingetragen:
LOCAL ldatensatz
ADR->(DBGOBOTTOM())
ldatensatz := ADR->NUMMER + 1
.... speichern: ADR->NUMMER := ldatensatz
memo: speichern: MEM->NUMMER := ADR->NUMMER
Code: Alles auswählen
CheckdatabaseAdressen()
CheckdatabaseMemos()
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
Code: Alles auswählen
ADR->(DbSetRelation( "MEM" , ;
{|| ADR->NUMMER } , ;
"ADR->NUMMER"))
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.
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.
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.
- brandelh
- Foren-Moderator
- Beiträge: 15697
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 66 Mal
- Danksagung erhalten: 33 Mal
- Kontaktdaten:
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.
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.
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
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
Hubert
- AUGE_OHR
- Marvin
- Beiträge: 12909
- Registriert: Do, 16. Mär 2006 7:55
- Wohnort: Hamburg
- Hat sich bedankt: 19 Mal
- Danksagung erhalten: 46 Mal
moin,
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
compilierst so macht er eine *.PPO daraus. schau dir sowas mal an.
gruss by OHR
Jimmy
du lernst schnellsamy88 hat geschrieben: HI, der Fehler war dass ich den 6. Parameter (SELECTIVE) nicht auf .T. gesetzt habe.
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
gruss by OHR
Jimmy
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?
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?
- brandelh
- Foren-Moderator
- Beiträge: 15697
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 66 Mal
- Danksagung erhalten: 33 Mal
- Kontaktdaten:
Mit INDEX ON werden sie erzeugt, set index to öffnet oder schließt die wieder, aber du darfst keinen Alias in einem INDEX verwenden !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
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
Code: Alles auswählen
INDEX ON Upper(field->NACHNAME) TO Adressen
INDEX ON field->NUMMER TO Nummer
Gruß
Hubert
Hubert
- Tom
- 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:
@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 ), 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:
und "Adressen" dann immer mit allen Indexen öffnen:
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.)
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.
Code: Alles auswählen
USE Adressen INDEX ADRESSEN1, ADRESSEN2 usw.
(Das geht auch alles sehr viel eleganter, ist in dieser Notation aber leichter zu verstehen.)
Herzlich,
Tom
Tom
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
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
- Martin Altmann
- Foren-Administrator
- Beiträge: 16517
- Registriert: Fr, 23. Sep 2005 4:58
- Wohnort: Berlin
- Hat sich bedankt: 111 Mal
- Danksagung erhalten: 48 Mal
- Kontaktdaten:
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
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
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.