Neuigkeiten:

Ist euer Problem gelöst, dann bitte den Knopf "Thema gelöst" drücken!

Mobiles Hauptmenü

Normalisierung / Datenimport aus Excel

Begonnen von Mr. Ahnungslos, März 27, 2014, 13:31:10

⏪ vorheriges - nächstes ⏩

Mr. Ahnungslos

Hallo Forum,

bei der Erstellung einer Datenbank und dem damit verbundenen Import einer Excel-Datei incl. der Normalisierung der Daten würde ich mich sehr über Eure Hilfe freuen.

Meine Excel-Datei incl. aller Daten sieht wie folgt aus: Marktgebiet, Filiale, Betreuer, Kundennummer, Name, diverse weiter Felder. Die Excel-Tabelle habe ich zur weiteren Bearbeitung nach Access importiert und in die Tabelle "Daten" gespeichert.

Diese soll in folgende Tabellen überführt werden: Marktgebiete, Filialen, Kundenbetreuer, Kunden

Die Tabellen und Beziehungen stehen soweit, mein Problem ist die vernünftige Programmierung einer Prozedur, die die Tabelle "Daten" durchläuft und die jeweiligen Werte in den Zieltabellen auf Vorhandensein prüft, ansonsten den entsprechenden Datensatz anfügt und hierbei auch die entsprechenden Fremdschlüssel setzt. Ein wenig VBA-Erfahrung habe ich zwar, aber es reicht nicht. Aber ich würde mir zutrauen ein entsprechendes Muster auf meine Bedürfnisse umzuschreiben. Toll wäre es noch, wenn ich in einem Arbeitsschritt alle Tabellen entsprechend befüllen könnte.

Ich danke Euch für Eure Mithilfe

Michael

database

Hallo Michael,

bei der Erstellung einer Datenbank sind nicht die Daten zu normalisieren sondern das Datenmodell selbst.

ZitatDie Tabellen und Beziehungen stehen soweit

stell doch mal einen Screenshot des Beziehungsfensters oder die leere DB hier rein.

Marktgebiete und Filialen sind vermutlich Nachschlagetabellen, die kannst du per Abfrage relativ einfach in deine neuen Tabellen importieren.

z.B.:

INSERT INTO Filialen (Filialbezeichnung) SELECT DISTINCT Filialbezeichnung FROM Daten



Mr. Ahnungslos

Hallo,

anbei die Beziehungen. Die Tabelle Daten_Alt ist in Wirklichkeit Ellenlang und soll in die entsprechenden Tabellen aufgeteilt werden. Wichtig wären dann die korrekten Fremdschlüssel.

Danke

ebs17

Abfragen sind übersichtlicher und vor allem schneller als VBA-Prozeduren.
Vergleiche Importtabelle in m:n-Beziehung auflösen
Mit freundlichem Glück Auf!

Eberhard

Mr. Ahnungslos

Hallo Eberhard,

vielen Dank, das geht schon sehr in die richtige Richtung, jedoch habe ich nur 1:n-Beziehungen, so dass bei meinen doch recht eingeschränkten SQL-Kenntnissen die m:n-Aufteilung ziemlich komplex erscheint und ich Probleme habe diese auf meine Datenbank umzuschreiben. Gibt es das Ganze auch als Beispiel für 1:n? Ich stelle mir das so vor, dass ich über die INSERT INTO-Funktion jeweils eine komplette Tabelle mit den entsprechenden Daten aus der Datensatzherkunft befülle, und hierbei gleichzeitig die Fremdschlüssel der mit der Tabelle in Beziehung stehenden Tabellen eingetragen wird.

Ich weiß, hört sich jetzt verworren an, aber wie soll ich es anders ausdrücken?

Wäre toll, wenn ihr hier nochmal helfen könntet.

Danke!

Michael

ebs17

#5
Eine m:n-Beziehung ist eigentlich die Zusammensetzung von zwei 1:n-Beziehungen.
Wenn Du also die zweite Primärtabelle und deren Verknüpfung in die Sekundärtabelle entfallen lässt, hast Du die einfachere 1:n-Beziehung.

Zitatjedoch habe ich nur 1:n-Beziehungen
KBS und Kunden sind dann aber doch Verknüpfungstabellen in jeweils einer m:n-Beziehung ...!

ZitatIch stelle mir das so vor, dass ich über die INSERT INTO-Funktion jeweils eine komplette Tabelle mit den entsprechenden Daten aus der Datensatzherkunft befülle, und hierbei gleichzeitig die Fremdschlüssel der mit der Tabelle in Beziehung stehenden Tabellen eingetragen wird.
Genau das erfolgt doch im verlinkten Beispiel. Pro Tabelle gibt es genau eine Anfügeabfrage. Für zu wiederholende Pflege- und Aktualisierungsaufgaben kämen dann pro Tabelle noch Aktualisierungen (und Löschungen?) dazu, vergleiche SQL ist leicht (4) - Aktualisierung einer Tabelle.

Zitat
Probleme habe diese auf meine Datenbank umzuschreiben
Übersichtlich wäre es, wenn Du eine Demo mit Deinen Tabellen und Beziehungen sowie der Importtabelle (einige wenige datenschutztechnisch unkritische Datensätze genügen) und Deinen Versuchen hier als Anlage einstellst.
Mit freundlichem Glück Auf!

Eberhard

Mr. Ahnungslos

Sorry, hat etwas gedauert, hier die Datenbank.

Am Ende sollen alle Daten aus der Tabelle Daten_Alt in die anderen Tabellen übertragen sein, so dass man die Ursprungstabelle wieder löschen kann. Ich verzweifle am Verständnis der SQL-Zeilen, die Unterabfragen bringen mich um den Verstand. Leider habe ich noch keine praktische Lösungsmöglichkeit gefunden wie ich den SQL-Text mal einfach verstehen kann. Immer wenn die nächste Klammer aufgeht verzweifle ich noch mehr.

Danke für die Hilfe

Michael

MzKlMu

Hallo,
wenn Du die DB nach Access2003 konvertierst, findest Du mehr die Dir helfen können. Viele haben kein Access2010.
Gruß Klaus

Mr. Ahnungslos

geht leider nicht - keine Ahnung warum bzw. was ich ändern müsste

database

#9
Hallo,

EDIT: habe überlesen, dass die *.accdb schon im Forum ist.
Konvertieren macht keinerlei Probleme!
Menü 'Datei' --> 'Speichern und Veröffentlichen' --> 'Access 2002 - 2003 - Datenbank' --> 'Speichern unter'

*.mdb ist im Anhang

ebs17

#10
Den einfachen Teil (3 Tabellen, die keine Fremdschlüssel benötigen) hast Du schon einmal gelöst. Bei der Tabelle Filialen wird es dann etwas umfangreicher (ist bis hier unvollständig).

Als Hinweis: Die Abfragen kannst Du natürlich im Abfrageeditor erzeugen und belassen und im Code dann nur mit dem Namen aufrufen (db.Execute "NameAbfrage", dbFailOnError).
Im Beispiel sind die Abfragen nur der Übersicht wegen als SQL-Strings im VBA-Code hinterlegt, Übersicht aber (nur) dann, wenn man SQL lesen und verstehen kann. Das Erzeugen der Strings an der Stelle wäre aber mehr als anstrengend (würde ich nicht tun).

Zweiter Hinweis: Die genannten Abfragen funktionieren als solches schon (Teststart: F5-Taste). Dabei kannst Du den Testlauf unendlich wiederholen, durch die eingebaute Inkonsistenzprüfung werden keine Einträge verdoppelt.

ZitatIch verzweifle am Verständnis der SQL-Zeilen ...
Wenn Du diese Abfragen fehlerfrei selber erstellen kannst, bist Du in der Fortgeschrittenengruppe schon etwas weiter fortgeschritten. Das ist also ein etwas größerer Schritt, der bewältigt werden will.

Wir widmen uns nun mal der Tabelle Filialen:
Zu füllen sind Filialbezeichnung (aus Daten_Alt) und Marktgebiet (PK aus Marktgebiete als FK). In Daten_Alt ist zudem die Zuordnung Marktgebietsbezeichung-Filiale (in Klarnamen)  enthalten, die nachfolgend benötigt und genutzt wird.

SELECT M.ID, DA.Filialbezeichnung
FROM Daten_ALT AS DA INNER JOIN Marktgebiete AS M
ON DA.Marktgebiet = M.Marktgebietsbezeichnung


Jetzt sollten wir aber dafür sorgen, dass Filialen jeweils nur einmalig eingetragen werden können. Also legen wir in der Tabelle einen eindeutigen Index auf Filialbezeichnung, und die SQL-Anweisung wird nachgerüstet, um keine Schlüsselfehler zu erzeugen: Ergänzung Inkonsistenzprüfung.
SELECT DISTINCT M.ID, DA.Filialbezeichnung
FROM Daten_ALT AS DA INNER JOIN Marktgebiete AS M
ON DA.Marktgebiet = M.Marktgebietsbezeichnung
WHERE NOT EXISTS
(SELECT NULL FROM Filialen AS F
WHERE F.Filialbezeichnung = DA.Filialbezeichnung)

Das DISTINCT dient dazu, in der Quelle für das Anfügen selber Duplikate zu vermeiden.

Nun machen wir noch eine Anfügeabfrage daraus: Voranstellen der INSERT-Zeile.
INSERT INTO Filialen ( Marktgebiet, Filialbezeichnung )
SELECT DISTINCT M.ID, DA.Filialbezeichnung
FROM Daten_ALT AS DA INNER JOIN Marktgebiete AS M ON DA.Marktgebiet = M.Marktgebietsbezeichnung
WHERE NOT EXISTS
(SELECT NULL FROM Filialen AS F
WHERE F.Filialbezeichnung = DA.Filialbezeichnung)


Die nächste(n) Tabelle(n) darfst Du wieder selber probieren. Ich hoffe, die Anleitung hilft ein wenig.

Anhang im Acc2000-Format:
Mit freundlichem Glück Auf!

Eberhard

Mr. Ahnungslos

Hallo Eberhard, ich mal wieder.

Nochmal vielen Dank für Deine Unterstützung bis hierher. Der Hinweis mit dem Abfrageeditor war super, hiermit kann ich mir zumindest bildlich etwas besser vorstellen wie die Abfragen funktionieren. Jetzt dachte ich mir "sei mal schlau" und nimm die fertige Abfrage vom Eberhard zur Befüllung der Filial-Tabelle und schreibe sie einfach nur zur Befüllung der Beratertabelle um. Ich habe also den SQL-Text in den Abfrageeditor kopiert und mir den Abfrageentwurf erst mal angesehen. Dann habe ich die beiden Tabellen "Berater" und "Funktionen" geöffnet und einfach nur das wiederholt, was Du vorher mit den Tabellen "Filialen" und "Marktgebiete" gemacht hast (also Beziehungen entsprechend angepasst, siehe Screenshot).

Das Ergebnis ist aber: es passiert gar nichts, und die 3. Spalte im Abfrageeditor schreibt auf einmal ein Ausdr1 vor den SQL-Text. Was mache ich denn immer falsch? Ich hoffe die Screenshots sind verständlich.

Michael

ebs17

#12
ZitatIch hoffe die Screenshots sind verständlich.
Für mich nicht. Ich lese SQL-Anweisungen. Da steht nämlich alles drin, was ausgeführt wird.

Meine Variante:
INSERT INTO Berater ( Funktion, Beratername )
SELECT DISTINCT F.ID, DA.Kundenbetreuer
FROM Daten_ALT AS DA INNER JOIN Funktionen AS F ON DA.Funktion = F.Funktionsbezeichnung
WHERE NOT EXISTS
(SELECT NULL FROM Berater AS B
WHERE B.Beratername = DA.Kundenbetreuer)


Zusätzlich muss die Abfrage auf Berater aus der 1. Schritt lt. VBA-Code entfernt werden (hatte ich übersehen), und natürlich muss die Tabelle geleert werden, da sonst nichts (gleiches) angefügt wird.

Ergänzung: Wie Du bemerkst, verwende ich Aliase für die Tabellenbezeichnungen. Diese sind zwar frei wählbar, sollten aber doch "sprechend" auf den vollständigen Tabellennamen hinweisen, um eine Übersicht zu gewährleisten:
Berater AS B
Marktgebiete AS M
Mit freundlichem Glück Auf!

Eberhard

Mr. Ahnungslos

OK OK, so langsam glaube wird's vernünftig.

Für die Tabelle KBS bin ich nun mit folgendem Code zu korrekten Einträgen gekommen:

INSERT INTO KBS ( Berater, Filiale )
SELECT DISTINCT Berater.ID, Filialen.ID
FROM Filialen INNER JOIN (Berater INNER JOIN Daten_ALT ON Berater.Beratername = Daten_ALT.Kundenbetreuer) ON Filialen.Filialbezeichnung = Daten_ALT.Filialbezeichnung;


Wie muss ich den Code denn noch ergänzen, damit bei Vorhandensein eines entsprechenden Eintrags in der Tabelle KBS (bestehen immer aus dem Wertepaar Filiale, Berater (hierbei jeweils die Fremdschlüssel aus den Tabellen Filialen und Berater) nicht weitere Datensätze in der Tabelle KBS hinzugefügt werden?

Michael

ebs17

A) Werte oder Wertkombinationen, die in der Tabelle eindeutig sein sollen, sichert man über einen eindeutigen (zusammengesetzten) Index ab. Ein solcher Index verhindert in jedem Fall das Anlegen eines ungewünschten Duplikats, egal ob man das Eintragen per Hand, per Abfrage, per Recordsetaktion oder über gebundene Formulare versucht.

B) Die Abfrage unterstützt obigen Vorgang:
INSERT INTO KBS ( Berater, Filiale )
SELECT DISTINCT B.ID, F.ID
FROM Filialen AS F INNER JOIN
(Berater AS B INNER JOIN Daten_ALT AS DA ON B.Beratername = DA.Kundenbetreuer)
ON F.Filialbezeichnung = DA.Filialbezeichnung
WHERE NOT EXISTS
(SELECT NULL FROM KBS
WHERE KBS.Berater = B.ID AND KBS.Filiale = F.ID)


In der Abfrage fehlen übrigens noch die Inhalte für das Zielfeld Kundenbetreuerschlüssel.

Als Ergänzung: Der Gesamtimport betrifft ja das Ergänzen von sieben Tabellen. Ein guter Import wäre das fehlerfreie Ausführen von dann sieben Anfügeabfragen. Wenn jetzt aber bei der (z.B.) fünften Abfrage ein Fehler auftreten würde, hätte man hinsichtlich des Gesamtimports einen undefinierten Zustand (Teilergebnis, unbekannter Stand). Da wäre es günstig, den gesamten Import auf den Ursprungszustand zurücksetzen zu können, um eine Fehlerbehebung und einen Neuimport starten zu können. Das ermöglicht eine Transaktion (nachzulesen in der Hilfe).
Mit freundlichem Glück Auf!

Eberhard