{"id":55000089,"date":"2002-12-01T00:00:00","date_gmt":"2021-01-12T22:55:20","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=89"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Rezepte_verwalten_mit_Access","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/","title":{"rendered":"Rezepte verwalten mit Access"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg07.met.vgwort.de\/na\/3a354a1f2982415ba1dadcc08fe13b79\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Andr&eacute; Minhorst, Duisburg<\/b><\/p>\n<p><b>Verwalten von Rezepten &#8211; das h&ouml;rt sich gar nicht nach einer Musterl&ouml;sung f&uuml;r Unternehmen an. Oder sind nur Hotelk&ouml;che angesprochen Nein. Neben dem Anspruch, ein Muster f&uuml;r eine Vielzahl von Anwendungen zu bieten, soll die vorliegende Musterl&ouml;sung auch von einer Vielzahl von Anwendern auf ihre eigenen Bed&uuml;rfnisse zugeschnitten werden k&ouml;nnen. <\/b><\/p>\n<p>Schlie&szlig;lich gibt es zu vielen T&auml;tigkeiten &#8222;Rezepte&#8220; bzw. Verfahrensvorschriften, deren Durchf&uuml;hrung auch noch die Verwendung bestimmter Zutaten &#8211; z. B. bestimmter Formulare &#8211; erfordert. <\/p>\n<p>Neben der Verwaltung von Rezepten, Zutaten usw. werden Sie hier mit der Programmierung einer Schnittstelle konfrontiert. Diese dient dem Einlesen von fertigen Rezepten, von denen es im Internet Tausende gibt.<\/p>\n<p>Wenn Sie sich z. B. einmal unter dem Stichwort Meal-Master die in Google registrierten deutschsprachigen Seiten ausgeben lassen, finden Sie zurzeit etwa 1.200 Eintr&auml;ge. Von vielen Seiten k&ouml;nnen Sie Dateien herunterladen, die teilweise hunderte von Rezepten enthalten.<\/p>\n<p>Meal-Master ist ein amerikanisches Programm zur Verwaltung von Rezepten, das ein international anerkanntes Format f&uuml;r den Austausch von Rezepten enth&auml;lt &#8211; die meisten verf&uuml;gbaren Rezeptverwaltungen besitzen eine Funktion f&uuml;r den Import dieses Formats. <\/p>\n<p>In diesem Zusammenhang lernen Sie auch, wie Sie mit einer Schnittstelle Daten von anderen Anwendungen in Ihre Datenbank importieren k&ouml;nnen. Der hier vorgestellte Vorgang l&auml;sst sich allerdings nicht mit denjenigen Assistenten vergleichen, die beispielsweise den Import von Daten aus Excel- oder CSV-Dateien erleichtern. Vielmehr zeigt dieser Beitrag, wie Daten in eine komplexe Datenstruktur eingearbeitet werden k&ouml;nnen.<\/p>\n<p>Die Rezeptverwaltung soll neben ihrer eigentlichen Aufgabe, der Verwaltung von Rezepten, auch den Import und Export im Meal-Master-Format erlauben. Daher ber&uuml;cksichtigt das Datenmodell auch dessen weltweit g&uuml;ltiges Format, das in den folgenden Abschnitten kurz vorgestellt werden soll.<\/p>\n<p><b>Das Meal-Master-Format<\/b><\/p>\n<p>Meal-Master verwendet herk&ouml;mmliche Textdateien. Es gibt eine genaue Spezifikation zur Festlegung der einzelnen Abschnitte eines Rezeptes. Ein Rezept besteht demnach aus den folgenden Angaben:<\/p>\n<li>Rezeptname<\/li>\n<li>Kategorien<\/li>\n<li>Anzahl der Portionen<\/li>\n<li>Zutaten mit Einheit und Anzahl<\/li>\n<li>Anleitung<\/li>\n<p>Aus diesen Informationen k&ouml;nnen Sie das Datenmodell zur Abbildung der Rezepte in einem relationalen Datenbanksystem &#8211; wie es Access ist &#8211; direkt ableiten.<\/p>\n<p><IMG height=\"292\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic001.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 1:  Datenmodell der Rezeptverwaltung<\/span><\/b><\/p>\n<p>Das Rezept als Hauptobjekt des Datenmodells ben&ouml;tigt eine eigene Tabelle zur Speicherung der rezeptspezifischen Daten. In diese Tabelle geh&ouml;ren der Rezeptname, die Anzahl der Portionen und die Anleitung &#8211; Informationen, die f&uuml;r jedes Rezept genau einmal auftauchen.<\/p>\n<p>Anders verh&auml;lt es sich mit den Kategorien und Zutaten: Jedes Rezept kann einer oder mehreren Kategorien zugeordnet werden und f&uuml;r jedes Rezept ben&ouml;tigen Sie in der Regel mehrere Zutaten.<\/p>\n<p>Das gilt in beiden F&auml;llen sicher auch umgekehrt: Sie ordnen jeder Kategorie ein oder mehrere Rezepte zu und auch jede Zutat taucht in einem oder in mehreren Rezepten auf.<\/p>\n<p>Sie ben&ouml;tigen also zwei m:n-Beziehungen &#8211; sowohl zwischen Rezepten und Kategorien als auch zwischen Rezepten und Zutaten.<\/p>\n<p>Die erste Beziehung realisieren Sie mit einer einfachen Verkn&uuml;pfungstabelle. Die zweite zwischen Rezepten und Zutaten ist etwas komplizierter. Hier m&uuml;ssen Sie zus&auml;tzlich noch Informationen &uuml;ber Einheit und Anzahl der Zutaten hinzuf&uuml;gen.<\/p>\n<p>Da diese Informationen sich unter Umst&auml;nden bei jeder Kombination aus Rezepten und Zutaten unterscheiden, k&ouml;nnen Sie diese nur in der Verkn&uuml;pfungstabelle zwischen den Tabellen der Rezepte und der Zutaten unterbringen.<\/p>\n<p><b>Die Tabelle tblRezepte<\/b><\/p>\n<p>Der Rezeptname, die Anleitung und die Anzahl der Portionen f&uuml;r die angegebenen Zutatenmengen speichern Sie in einer Tabelle namens tblRezepte. Da die Anleitung vermutlich oft l&auml;nger als 255 Zeichen ist, verwenden Sie f&uuml;r diese Information ein Memo-Feld.<\/p>\n<p><b>Die Tabelle tblZutaten<\/b><\/p>\n<p>Alle in der Datenbank verwendeten Zutaten speichern Sie in der Tabelle tblZutaten. Neben der Bezeichnung der Zutat enth&auml;lt die Tabelle ein Bemerkungsfeld.<\/p>\n<p><b>Die Tabelle tblKategorien<\/b><\/p>\n<p>Die Tabelle tblKategorien dient dem Speichern der Kategorien. Auch hier ist ein Bemerkungsfeld vorgesehen.<\/p>\n<p><b>Die Tabelle tblEinheiten<\/b><\/p>\n<p>Da es im Meal-Master-Format fest vorgegebene Einheiten gibt, die immer wieder auftauchen, sollen sie in einer separaten Tabelle gespeichert werden. Da die Bezeichnungen sich der Herkunft des Formats entsprechend auf amerikanische Einheiten beziehen, soll die Tabelle neben der englischen Bezeichnung auch noch eine deutsche Bezeichnung f&uuml;r die Ausgabe enthalten.<\/p>\n<p><b>Die TabelletblRezepteZutaten<\/b><\/p>\n<p>Diese Tabelle speichert alle Zuordnungen zwischen Rezepten und Zutaten. Zus&auml;tzlich soll die Tabelle zu jeder Zuordnung die Einheit, die Anzahl der Einheiten und Bemerkungen speichern. Die Einheiten werden als Zahlenwert eingegeben, der sich auf die verkn&uuml;pfte Tabelle tblEinheiten bezieht.<\/p>\n<p><IMG height=\"208\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic002.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 2:  Beispiel eines Rezeptes im Meal-Master-Format<\/span><\/b><\/p>\n<p>Die beiden Felder RezeptID und ZutatID dienen als Fremdschl&uuml;sselfelder zu den entsprechenden Tabellen. Sie bilden allerdings keinen gemeinsamen Prim&auml;rschl&uuml;ssel.<\/p>\n<p><b>Die Tabelle tblRezepteKategorien<\/b><\/p>\n<p>Die Tabelle zur Herstellung der Beziehung zwischen Rezepten und Kategorien ist eine einfache Verkn&uuml;pfungstabelle mit den Fremdschl&uuml;sselfeldern RezeptID und KategorieID zu den Tabellen tblRezepte und tblKategorien.<\/p>\n<p><b>Die Beziehungen<\/b><\/p>\n<p>Die Beschreibung der verwendeten Tabellen enth&auml;lt bereits die wichtigsten Informationen zu den Beziehungen zwischen den Tabellen. Bild 1 zeigt eine Zusammenfassung der Tabellen und der Beziehungen zwischen den Tabellen. F&uuml;r alle Beziehungen soll referentielle Integrit&auml;t bestehen.<\/p>\n<p>Die Eingabe von Test- und anderen Daten ist in der Regel wenig unterhaltsam &#8211; zumindest, wenn Sie die Daten stur von einer Vorlage &uuml;bernehmen m&uuml;ssen.<\/p>\n<p>Daher sorgen Sie nun zun&auml;chst einmal f&uuml;r eine Schnittstelle zum Import von bestehenden Daten im Meal-Master-Format.<\/p>\n<h3>Hinweis<\/h3>\n<p>Zwar ist auch das Erstellen von Schnittstellen nicht gerade befl&uuml;gelnd, aber deren anschlie&szlig;ende Anwendung und die daraus resultierende Zeitersparnis ist ein guter Grund, diese Arbeit in Kauf zu nehmen. <\/p>\n<p><b>Das Import-Format<\/b><\/p>\n<p>Die Dateien mit den Meal-Master-Rezepten sind reine Textdateien. Gl&uuml;cklicherweise haben Sie eine einigerma&szlig;en regelm&auml;&szlig;ige Struktur &#8211; was bei einem weltweit verwendeten Format vorausgesetzt werden kann. Die Frage, warum ein solch verbreitetes Format nicht auf dem Stand der Zeit ist &#8211; beispielsweise in Form einer XML-Datei -, ist wohl ebenfalls mit der weltweiten Verwendung und der Beliebtheit zu erkl&auml;ren. Je mehr Anwender mit einem Produkt arbeiten, desto mehr Widerstand regt sich gegen die Einf&uuml;hrung neuer Standards.<\/p>\n<p>Eine Meal-Master-Datei besteht aus einem oder mehreren Rezepten, die untereinander in die Datei eingetragen sind. Jedes Rezept hat eine fest definierte erste und letzte Zeile. Die erste Zeile beginnt mit f&uuml;nf gro&szlig;en M oder f&uuml;nf Minuszeichen (-) und beinhaltet irgendwo dahinter die Zeichenfolge Meal-Master. Die letzte Zeile beginnt ebenso, ist aber nach diesen f&uuml;nf Zeichen bereits zu Ende.<\/p>\n<p>Dazwischen befinden sich drei Abschnitte: Im ersten, fest definierten Teil stehen Angaben zum Namen des Rezepts, zur Anzahl der Portionen f&uuml;r die angegebene Menge Zutaten und zu den Kategorien, denen das Rezept zugeordnet werden kann.<\/p>\n<p>Im zweiten Teil befinden sich die Zutaten. Die Zutaten werden in ein oder zwei Spalten aufgelistet, wobei feste Bereiche der Zeile f&uuml;r die Informationen Menge, Einheit und Zutat vorgesehen sind.<\/p>\n<p>Der dritte Teil beinhaltet schlie&szlig;lich die eigentliche Anleitung. Bild 2 zeigt ein Beispielrezept im Meal-Master-Format.<\/p>\n<p>Diese Darstellung kann als einfachste Ausf&uuml;hrung eines Rezeptes in diesem Format angesehen werden. Umfangreichere Rezepte besitzen weitere Zeilen, die z. B. die Zutaten nach den einzelnen Bestandteilen des Rezeptes aufteilen oder die einfach als Kommentarzeilen &#8211; beispielsweise zur Angabe der Herkunft eines Rezeptes &#8211; dienen. Solche Besonderheiten spart die im Folgenden erstellte Import-Routine aus Gr&uuml;nden der &uuml;bersichtlichkeit allerdings aus.<\/p>\n<p><b>Daten importieren<\/b><\/p>\n<pre>Function RezepttexteEinlesen(Quelldatei As String)\r\n    Dim Zeile As String\r\n    Dim Rezepttext As String\r\n    Dim Rezeptnummer As Integer\r\n    Dim Zeilennummer As Integer\r\n    Dim db As Database\r\n    Dim rstRezepttexte As Recordset\r\n    On Error GoTo RezepttexteEinlesen_Err\r\n    Set db = CurrentDb\r\n    Set rstRezepttexte = _        db.OpenRecordset(\"tblRezepttexte\", _        dbOpenDynaset)\r\n    Open Quelldatei For Input As #1\r\n    Do While Not EOF(1)\r\n        Line Input #1, Zeile\r\n        If (Left(Zeile, 5) = \"MMMMM\" _            Or Left(Zeile, 5) = \"-----\") _            And InStr(1, Zeile, \"Meal-Master\") &gt; 0 Then\r\n            Zeilennummer = 1\r\n            Rezeptnummer = Nz(DMax(\"Rezeptnummer\", _                \"tblRezepttexte\"), 0) + 1\r\n        End If\r\n        rstRezepttexte.AddNew\r\n        rstRezepttexte!Rezepttext = Zeile\r\n        rstRezepttexte!Rezeptnummer = Rezeptnummer\r\n        rstRezepttexte!Zeilennummer = Zeilennummer\r\n        rstRezepttexte!EingelesenAm = Date\r\n        rstRezepttexte.Update\r\n        Zeilennummer = Zeilennummer + 1\r\n    Loop\r\n    Close #1\r\n    Exit Sub\r\nRezepttexteEinlesen_Err:\r\n    If Err.Number = 76 Then\r\n        MsgBox \"Die Datei konnte nicht gefunden \" _            & \"werden.\", vbExclamation + vbOKOnly, _            \"Dateifehler\"\r\n        Exit Function\r\n    Else\r\n        MsgBox \"Fehler: \" & Err.Number & \" \" _            & Err.Description\r\n    End If\r\nEnd Function<\/pre>\n<p><b>Quellcode 1<\/b><\/p>\n<p>Die &uuml;bernahme von Daten aus Textdateien, die auf anderen Formaten als XML oder CSV basieren, bringt in der Regel Nacharbeit mit sich. Da die Dateien teilweise sehr gro&szlig;e Mengen Rezepte enthalten &#8211; tausend und mehr sind keine Seltenheit -, soll die Datenbank den Inhalt der Datei zun&auml;chst einmal einlesen. Anschlie&szlig;end kann der Anwender dann bestimmen, welche Rezepte er in seine eigene Sammlung aufnehmen m&ouml;chte.<\/p>\n<p>F&uuml;r die Zwischenspeicherung der Daten ben&ouml;tigen Sie eine Tabelle namens tblRezepttexte. Die Tabelle speichert die Daten so lange, bis der Anwender sie in seine Sammlung &uuml;bernimmt.<\/p>\n<p>Die Prozedur aus Quellcode 1 liest die Daten aus der Textdatei zeilenweise in die Tabelle tblRezepttexte ein.<\/p>\n<p>Nach dem Deklarieren und Initialisieren der Objektvariablen &ouml;ffnet die Prozedur mit der Open-Anweisung die Datei mit dem in dem Parameter Quelldatei angegebenen Namen.<\/p>\n<p>Anschlie&szlig;end liest sie die Datei bis zum Erreichen des Dateiendes zeilenweise ein. Dabei ber&uuml;cksichtigt die Prozedur, ob ein neues Rezept beginnt, und setzt die Variable Rezeptnummer auf den Wert, der um 1 gr&ouml;&szlig;er als der gr&ouml;&szlig;te bisher vergebene Wert ist. Die Variable Zeilennummer wird mit jeder Zeile um 1 erh&ouml;ht.<\/p>\n<p>Beide Variablen werden mit dem Inhalt der Zeile und dem Datum des Einlesens in je einem Datensatz f&uuml;r jede Zeile in der Tabelle tblRezepttexte gespeichert.<\/p>\n<p>Nach dem Einlesen ist kein weiterer Zugriff auf die Datei mehr erforderlich. Von nun an k&ouml;nnen alle ben&ouml;tigten Informationen zu den einzelnen Rezepten aus der Tabelle tblRezepttexte gelesen werden.<\/p>\n<p><IMG height=\"422\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic003.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 3:  Formular zur &uuml;bernahme von Rezepten<\/span><\/b><\/p>\n<p>Die Funktion beinhaltet eine kleine Fehlerbehandlung, die bei Nichtvorhandensein der Datei mit dem &uuml;bergebenen Namen eine entsprechende Meldung ausgibt.<\/p>\n<p><b>Daten &uuml;bernehmen<\/b><\/p>\n<p>Der Import von Daten ist mit dem Einlesen der Daten in die Tabelle tblRezepttexte abgeschlossen, da nunmehr kein weiterer Zugriff auf die verwendete Datei mehr erforderlich ist. Im weiteren Verlauf sollen die Daten allerdings noch in das beschriebene Datenmodell &uuml;bernommen werden. Zur komfortablen Auswahl der gew&uuml;nschten Rezepte und zur Einleitung der anschlie&szlig;enden Konvertierung der vorhandenen Daten in das Datenmodell verwenden Sie ein geeignetes Formular.<\/p>\n<p>Daten aus einer Textdatei in einer weiter verwertbaren Form in eine Datenbank zu bugsieren, ist keine besondere Kunst. Viel interessanter ist die &uuml;bernahme der eingelesenen Daten in ein Datenmodell, das aufgrund seiner relationalen Struktur zwar wesentlich komplexer ist als der Ursprung der Daten, aber auch vielf&auml;ltigere M&ouml;glichkeiten bietet.<\/p>\n<p><!--30percent--><\/p>\n<p>Nun gilt es, die eingelesenen Daten pr&auml;zise zu identifizieren und in den entsprechenden Tabellen zu speichern. F&uuml;r den Komfort des Anwenders ist da &#8211; wie &uuml;blich &#8211; ein Formular erforderlich.<\/p>\n<p>Das Formular soll alle eingelesenen Rezepte in einem Listenfeld anzeigen und die M&ouml;glichkeit bieten, per Knopfdruck beliebige Rezepte auszuw&auml;hlen und in die Datenbank zu &uuml;bernehmen. Au&szlig;erdem soll eine Schaltfl&auml;che zum L&ouml;schen und eine zum Einlesen weiterer Dateien vorhanden sein (siehe Bild 3).<\/p>\n<p><b>Datei einlesen<\/b><\/p>\n<p>Das Einlesen von Dateien sei hier nur in Grundz&uuml;gen dargestellt: Die Anwendung bietet einen Dialog zur Eingabe der gew&uuml;nschten Datei an. Der Dialog wird &uuml;ber eine herk&ouml;mmliche InputBox-Anweisung aufgerufen.<\/p>\n<p>Im Anschluss an die Eingabe des Dateinamens ruft die Prozedur aus Quellcode 2 direkt die Funktion RezepttexteEinlesen auf.<\/p>\n<p>Nach dem Einlesen der Datei aktualisiert die Prozedur die Liste mit den neuen Eintr&auml;gen per Requery-Anweisung.<\/p>\n<p><IMG height=\"184\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic004.png\" width=\"344\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 4:  Eingabe des Dateinamens<\/span><\/b><\/p>\n<p><b>Anzeige der Eintr&auml;ge<\/b><\/p>\n<pre>Private Sub cmdDateiEinlesen_Click()\r\n    Dim Dateiname As String\r\n    Dateiname = InputBox(\"Bitte geben Sie den Namen der Datei im \" _        & \"Meal-Master-Format ein.\", \"Dateinamen eingeben\")\r\n    RezepttexteEinlesen Dateiname\r\n    Me.lstRezepte.Requery\r\nEnd Sub<\/pre>\n<p><b>Quellcode 2<\/b><\/p>\n<p><IMG height=\"265\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic005.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 5:  Die Abfrage <\/span><\/b><\/p>\n<p>Nicht ganz einfach ist die Anzeige der Rezeptnamen anhand der Daten aus der Tabelle tblRezepttexte. Da die Tabelle alle Zeilen der eingelesenen Rezepte enth&auml;lt, m&uuml;ssen zun&auml;chst jene Zeilen ausfindig gemacht werden, die den Namen des Rezeptes enthalten. Nur diese sind anschlie&szlig;end zu extrahieren. <\/p>\n<p>Bei dieser Aufgabe hilft Ihnen eine Abfrage namens qryRezepttitel. Diese Abfrage verwendet zwei Funktionen, um die gesuchten Informationen in der Tabelle tblRezepttexte zu finden. Die erste Funktion ermittelt alle Zeilen, in denen die Zeichenkette Title: enthalten ist. Sie gibt einen Wert gr&ouml;&szlig;er 0 f&uuml;r alle entsprechenden Zeilen zur&uuml;ck:<\/p>\n<pre>TitelVorhanden: TeilStr(1;[Rezepttext];\"Title:\")<\/pre>\n<p>Die zweite Funktion ermittelt den Titel des Rezeptes in den gefundenen Zeilen:<\/p>\n<pre>Titel: TeilStr([Rezepttext];[TitelVorhanden]+7;L&auml;nge([Rezepttext])-[TitelVorhanden]+6)<\/pre>\n<p>Leider k&ouml;nnen Abfragen keine Sortierung auf Felder enthalten, die auf die beschriebene Weise ermittelt wurden. Daher ben&ouml;tigen Sie noch eine weitere Abfrage, um die gefundenen Werte zu sortieren. Diese Abfrage basiert auf der soeben beschriebenen Abfrage und sortiert diese nach dem Feld Titel (siehe Bild 6).<\/p>\n<p><IMG height=\"281\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic006.png\" width=\"337\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 6:  Abfrage zur Sortierung des Ergebnisses einer weiteren Abfrage<\/span><\/b><\/p>\n<p>Diese Abfrage dient schlie&szlig;lich als Datenherkunft f&uuml;r das Listenfeld in dem Formular frmUebernehmen.<\/p>\n<p><b>Rezept &uuml;bernehmen<\/b><\/p>\n<p>Das &uuml;bernehmen der Rezepte in das vorliegende Datenmodell ist relativ programmierintensiv. Daher k&ouml;nnen leider nicht alle verwendeten Prozeduren und Funktionen im Detail vorgestellt werden. Sie erhalten aber in jedem Fall einen &uuml;berblick &uuml;ber den gesamten Ablauf mit einer Vertiefung zu besonders wichtigen Abschnitten.<\/p>\n<h3>Hinweis<\/h3>\n<p>Nahezu alle Tabellen der Beispieldatenbank sind mit GUIDs als Prim&auml;rschl&uuml;sseln ausgestattet. GUIDs haben gegen&uuml;ber herk&ouml;mmlichen Prim&auml;rindizes den Vorteil, dass sie sicher einzigartig sind und daher bereits vor dem Abschlie&szlig;en von Datenbankoperationen als Prim&auml;rschl&uuml;sselwert bestimmter Datens&auml;tze angenommen und beliebig weiterverarbeitet werden k&ouml;nnen. Weitere Informationen &uuml;ber diese Art von Prim&auml;rschl&uuml;ssel und die Besonderheiten bei deren Verwendung finden Sie im Beitrag Die Geheimnisse der GUID, den Sie im .pdf-Format auf der Heft-CD finden. <\/p>\n<p>Die &uuml;bernahme eines Rezeptes erfolgt in folgenden Schritten:<\/p>\n<li>Pr&uuml;fung auf vorhandene gleichnamige Rezepte<\/li>\n<li>Einlesen der Kategorien<\/li>\n<li>Einlesen der Anzahl der Portionen bezogen auf die Zutatenmenge<\/li>\n<li>Einlesen der Zutaten und Speichern der Informationen in einer tempor&auml;ren Tabelle<\/li>\n<li>Einlesen der Kochanleitung<\/li>\n<li>Speichern der Kategorien<\/li>\n<li>Speichern der Zutaten<\/li>\n<p>Die Steuerung des gesamten Vorgangs erfolgt durch die Prozedur, die beim Bet&auml;tigen der Schaltfl&auml;che Rezept &uuml;bernehmen des Formulars frmUebernehmen ausgel&ouml;st wird.<\/p>\n<p>Diese Prozedur liest s&auml;mtliche Informationen in einer Form ein, die weitere Funktionen leicht weiterverarbeiten k&ouml;nnen.<\/p>\n<p>Die verwendeten Zutaten inklusive Einheit und Menge werden beispielsweise in der tempor&auml;ren Tabelle tblZutatenTemp gespeichert und die durch Komma getrennten Kategorien werden in einer String-Variablen abgelegt, um sp&auml;ter weiter verarbeitet werden zu k&ouml;nnen.<\/p>\n<p>Nach dem Einlesen der Informationen zum jeweiligen Rezept startet die Prozedur noch zwei weitere Prozeduren zum Eintragen der Kategorien und Zutaten in die entsprechenden Tabellen.<\/p>\n<p>Der Vorgang soll am Beispiel des Eintragens der Kategorien erl&auml;utert werden &#8211; das Eintragen der Zutaten ist wesentlich aufw&auml;ndiger und w&uuml;rde den Rahmen des vorliegenden Beitrags sprengen.<\/p>\n<pre>Function KategorienEintragen(Kategorien As String, RezeptID As String)\r\n    Dim Kategorie As String\r\n    Dim KategorieID As String\r\n    Dim strSQL As String\r\n    Do While Not Len(Trim(Kategorien)) = 0\r\n        If InStr(1, Kategorien, \",\") &gt; 0 Then\r\n            Kategorie = Trim(Left(Kategorien, InStr(1, Kategorien, \",\") - 1))\r\n            Kategorien = Mid(Kategorien, InStr(1, Kategorien, \",\") + 1, _                Len(Kategorien) - InStr(1, Kategorien, \",\"))\r\n        Else\r\n            Kategorie = Trim(Kategorien)\r\n            Kategorien = \"\"\r\n        End If\r\n        KategorieID = Nz(DLookup(\"StringFromGuid([KategorieID])\", \"tblKategorien\", _            \"Kategorie = ''\" & Kategorie & \"''\"), \"\")\r\n        If KategorieID = \"\" Then\r\n            KategorieID = CreateGUID\r\n            strSQL = \"INSERT INTO tblKategorien(KategorieID, Kategorie) \" _                & \"VALUES({guid \" & KategorieID & \"}, ''\" & Kategorie & \"'')\"\r\n            DoCmd.RunSQL strSQL\r\n        End If\r\n        DoCmd.RunSQL \"INSERT INTO tblRezepteKategorien(RezeptID, KategorieID) \" _            & \" VALUES({guid \" & RezeptID & \"}, {guid \" & KategorieID & \"})\"\r\n    Loop\r\nEnd Function<\/pre>\n<p><b>Quellcode 3<\/b><\/p>\n<p><b>Eintragen der Kategorien<\/b><\/p>\n<p>Die Kategorien liegen als Zeichenkette in einer entsprechenden Variablen vor. Ziel ist nun, die einzelnen Kategorien in die Tabelle tblKategorien einzutragen &#8211; sofern sie dort noch nicht vorhanden sind &#8211; und anschlie&szlig;end f&uuml;r jede Kategorie einen Eintrag in der Tabelle tblRezepteKategorien zu erstellen, um die Kategorien dem entsprechenden Rezept zuzuordnen. Diese Aufgabe &uuml;bernimmt die Funktion KategorienEintragen (s. Quellcode 3).<\/p>\n<p>Die aufrufende Prozedur &uuml;bergibt als Parameter die Kategorie-Liste und den Wert der RezeptID. In einer Do While-Schleife arbeitet die Funktion die einzelnen Elemente der durch Kommata getrennten Auflistung durch und tr&auml;gt sie einzeln in die Tabellen ein.<\/p>\n<p>Solange noch mehr als ein Eintrag in der Zeichenkette enthalten ist &#8211; also mindestens noch ein Komma gefunden wird -, schneidet die Funktion jeweils den Teil vor dem Komma ab und behandelt ihn als eigene Kategorie. Falls in der Zeichenkette kein Komma mehr vorhanden ist, wird der Rest der Zeichenkette als Kategorie ausgewertet.<\/p>\n<p>Mit einer DLookup-Funktion &uuml;berpr&uuml;ft die Funktion, ob die Tabelle tblKategorien bereits eine Kategorie gleichen Namens enth&auml;lt, und ermittelt ggf. die KategorieID des Eintrags in der Tabelle tblKategorien.<\/p>\n<p><IMG height=\"409\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic007.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 7:  Das Formular zur Eingabe und zum Bearbeiten der Rezepte<\/span><\/b><\/p>\n<p>Falls der Eintrag noch nicht vorhanden ist, legt die Funktion einen neuen Eintrag f&uuml;r diese Kategorie in der Tabelle tblKategorien mit einer neu ermittelten GUID als KategorieID an.<\/p>\n<p>In beiden F&auml;llen wird anschlie&szlig;end in der Tabelle tblRezepteKategorien ein neuer Eintrag mit den Werten RezeptID und KategorieID angelegt, um die Verkn&uuml;pfung zwischen Rezept und Kategorie herzustellen. Damit sind die Kategorien des Rezeptes in das Datenmodell eingebunden.<\/p>\n<p><b>Eintragen der Zutaten<\/b><\/p>\n<p>Aufgrund der gr&ouml;&szlig;eren Menge der zu erfassenden Daten und wesentlich komplizierteren Struktur der zu verwertenden Daten ist das Eintragen der Zutaten in die Tabellen tblZutaten und tblRezepteZutaten schwieriger als bei den Kategorien. Wenn Sie an dem Algorithmus interessiert sind, sehen Sie sich im Modul mdlSchnittstelle die Funktion ZutatenEintragen an.<\/p>\n<p>Die Benutzeroberfl&auml;che besteht aus drei Haupt- und zwei Unterformularen. Schaltzentrale ist das Formular frmRezepte mit seinen Funktionen zur Eingabe und Bearbeitung von Rezepten und zum Aufrufen der anderen beiden Hauptformulare. Das Formular beherbergt au&szlig;erdem beide Unterformulare der Anwendung.<\/p>\n<p>Das erste der beiden Formulare namens frmUebernehmen haben Sie bereits kennen gelernt.<\/p>\n<p>Das zweite ist das Formular frmSuche. Es bietet einfache Suchm&ouml;glichkeiten und kann gefundene Rezepte im Formular frmRezepte anzeigen.<\/p>\n<p><b>Das Hauptformular frmRezepte<\/b><\/p>\n<p>Das Hauptformular der Anwendung ist das Formular frmRezepte. Es dient der Anzeige eines Rezeptes und bietet die M&ouml;glichkeit, mit geeigneten Schaltfl&auml;chen weitere Funktionen aufzurufen.<\/p>\n<p>Dazu geh&ouml;ren der schon beschriebene Import von Rezeptdateien und einzelnen Rezepten, eine einfache Suche nach Rezepten sowie die Ausgabe eines Rezeptes in Form eines Berichtes.<\/p>\n<p>Bild 7 zeigt die Formularansicht des Formulars frmRezepte. Neben den Schaltfl&auml;chen beinhaltet das Formular die Steuerelemente zur Anzeige der Rezeptdaten. Dazu geh&ouml;ren drei Textfelder: f&uuml;r den Rezeptnamen, f&uuml;r die Anzahl der Portionen und f&uuml;r die Beschreibung.<\/p>\n<p><IMG height=\"154\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic008.png\" width=\"297\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 8:  Das Unterformular sfmKategorien<\/span><\/b><\/p>\n<p><IMG height=\"305\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic009.png\" width=\"452\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 9:  Datenherkunft des Unterformulars sfmKategorien<\/span><\/b><\/p>\n<p>Zwei Unterformulare dienen der Anzeige der Kategorien und der Zutaten, die dem Rezept zugeordnet sind.<\/p>\n<h3>Rezept drucken und Vorschau anzeigen<\/h3>\n<p>Das Formular besitzt zwei Schaltfl&auml;chen zum Anzeigen der Vorschau bzw. zum Ausdrucken des Rezepts in Form eines Berichtes. Beide Schaltfl&auml;chen verwenden fast die gleiche Ereignisprozedur, um den Bericht repRezepte aufzurufen. Der einzige Unterschied liegt im Parameter View:<\/p>\n<pre>Private Sub cmdRezeptDrucken_Click()\r\n    DoCmd.OpenReport \"repRezept\", _        View:=acNormal, _        WhereCondition:=\"RezeptID = \" _        & StringFromGUID _       (Forms!frmRezepte!RezeptID)\r\nEnd Sub<\/pre>\n<p><b>Das Unterformular sfmKategorien<\/b><\/p>\n<p>Das erste von zwei Unterformularen des Formulars frmRezepte dient der Anzeige der zugeordneten Kategorien in der Datenblattansicht. Die Entwurfsansicht des Formulars erscheint recht einfach &#8211; sie enth&auml;lt lediglich das Feld KategorieID (siehe Bild 8). Dieses ist an das Feld KategorieID der Datenherkunft des Formulars, der Abfrage qryRezepteKategorien (siehe Bild 9), gebunden und hat als Datensatzherkunft die folgende SQL-Anweisung:<\/p>\n<pre>SELECT tblKategorien.KategorieID, tblKategorien.Kategorie\r\nFROM tblKategorien\r\nORDER BY tblKategorien.Kategorie;<\/pre>\n<p>Zusammengefasst bedeutet dies, dass das Unterformular alle Datens&auml;tze der Tabelle tblKategorien anzeigt, die mit dem aktuellen Datensatz des Hauptformulars frmRezepte verkn&uuml;pft sind &#8211; und das in aufsteigender alphabetischer Reihenfolge.<\/p>\n<p>Das Kombinationsfeld KategorieID bietet alle Datens&auml;tze der Tabelle tblKategorien zur Auswahl an.<\/p>\n<p>Wenn Sie das Unterformular in das Hauptformular einbinden, stellt Access normalerweise automatisch die beiden Eigenschaften Verkn&uuml;pft von und Verkn&uuml;pft nach auf den Wert RezeptID ein.<\/p>\n<h3>Unterbinden von Eingabefehlern<\/h3>\n<p>Diese Verkn&uuml;pfung kann zu Fehlern f&uuml;hren: Sie haben ja in der Tabelle tblRezepteKategorien einen zusammengesetzten Prim&auml;rschl&uuml;ssel festgelegt, der aus den beiden Feldern RezeptID und KategorieID besteht.<\/p>\n<p>Der erste denkbare Fehler kann durch die zweimalige Zuordnung einer Kategorie zu ein und demselben Rezept entstehen &#8211; der klassische Fall einer Schl&uuml;sselverletzung. Die zweite klassische M&ouml;glichkeit, einen Fehler in einem mit dem Hauptformular verkn&uuml;pften Unterformular auszul&ouml;sen, ist das Anlegen eines Datensatzes im Unterformular vor dem Anlegen eines Datensatzes im Hauptformular.<\/p>\n<p>Die resultierende Fehlermeldung k&ouml;nnen Sie umgehen und durch eine eigene, f&uuml;r den Benutzer aussagekr&auml;ftigere Fehlermeldung ersetzen. Dazu hinterlegen Sie f&uuml;r die Ereigniseigenschaft Bei Fehler des Formulars die Prozedur aus Quellcode 4.<\/p>\n<pre>Private Sub Form_Error(DataErr As Integer, Response As Integer)\r\n    Select Case DataErr\r\n        Case 3058\r\n            MsgBox \"Bitte geben Sie zun&auml;chst einen Rezeptnamen ein.\", _                vbExclamation + vbOKOnly, \"Eingabefehler\"\r\n            Me.Undo\r\n            Response = False\r\n        Case 3022\r\n            MsgBox \"Sie haben diese Kategorie bereits ausgew&auml;hlt. Bitte w&auml;hlen Sie \" _                & \" eine andere Kategorie aus.\", vbExclamation + vbOKOnly, _                \"Eingabefehler\"\r\n            Me.Undo\r\n            Response = False\r\n        Case Else\r\n            MsgBox DataErr\r\n            Response = False\r\n    End Select\r\nEnd Sub<\/pre>\n<p><b>Quellcode 4<\/b><\/p>\n<p>Die Prozedur hat zwei Parameter &#8211; die Nummer des ausl&ouml;senden Fehlers, die mit dem Parameter DataErr an die Prozedur &uuml;bergeben wird, und den R&uuml;ckgabewert Response. Die Prozedur fragt die Fehlernummer ab und reagiert in einem Select Case-Konstrukt mit einer entsprechenden Aktion.<\/p>\n<p>F&uuml;r den Fall, dass der Anwender eine Kategorie anlegt, bevor der Datensatz des Hauptformulars gespeichert ist, zeigt die Prozedur eine Meldung an und macht die Eingabe r&uuml;ckg&auml;ngig.<\/p>\n<p>Falls der Benutzer eine bereits ausgew&auml;hlte Kategorie erneut ausw&auml;hlt, erscheint ebenfalls eine Meldung. Durch die Angabe des Wertes False f&uuml;r den R&uuml;ckgabeparameter Response unterbinden Sie die Ausgabe der herk&ouml;mmlichen Fehlermeldung.<\/p>\n<p><b>Das Unterformular sfmRezepteZutaten<\/b><\/p>\n<p>Das zweite Unterformular arbeitet prinzipiell wie das Unterformular frmKategorien. Die zwei wesentlichen Unterschiede sind die h&ouml;here Anzahl von Feldern sowie die M&ouml;glichkeit, eine Zutat auch mehr als einmal auszuw&auml;hlen. Das ist erforderlich, da Meal-Master die M&ouml;glichkeit bietet, die Zutaten auf die einzelnen Bestandteile des Rezeptes aufzuteilen &#8211; z. B. So&szlig;e, Gem&uuml;se, Salat usw.<\/p>\n<p><b>Das Hauptformular frmSuche<\/b><\/p>\n<p>Das Suchformular dient als kleine Hilfe bei der Auswahl von Rezepten. Dabei bietet es die M&ouml;glichkeit, einen Text einzugeben, der im Namen des Rezeptes gesucht wird. Au&szlig;erdem k&ouml;nnen Sie gezielt nach den Zutaten suchen, falls Sie Appetit auf etwas Spezielles entwickeln. Wenn Sie beispielsweise etwas Pikantes suchen, wird die Auswahl von Peperoni, Knoblauch und Chili wohl ein geeignetes Rezept liefern &#8211; wenn ein entsprechendes gespeichert ist.<\/p>\n<p>Bild 10 zeigt das Suchformular mit den Steuerelementen zum Filtern der Eintr&auml;ge des Listenfeldes.<\/p>\n<p>Die drei Kombinationsfelder haben jeweils die Abfrage qryZutaten als Datensatzherkunft. Die Abfrage hat folgenden SQL-Ausdruck:<\/p>\n<pre>SELECT tblZutaten.ZutatID, tblZutaten.Zutat\r\nFROM tblZutaten\r\nORDER BY tblZutaten.Zutat;<\/pre>\n<p><IMG height=\"310\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic010.png\" width=\"432\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 10:  Formular zur Suche von Rezepten<\/span><\/b><\/p>\n<p><IMG height=\"514\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic011.png\" width=\"465\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 11:  Bericht zur Ausgabe von Rezepten<\/span><\/b><\/p>\n<pre>Private Sub SucheStarten()\r\n    Dim strSQL As String\r\n    strSQL = \"SELECT tblRezepte.RezeptID, \" _        & \"tblRezepte.Rezept FROM tblRezepte WHERE \" _        & \"Rezept LIKE ''*\" & Me.txtRezeptname & \"*''\"<\/pre>\n<p><b>Quellcode 5 (erster Teil)<\/b><\/p>\n<p>Das Textfeld und die drei Kombinationsfelder l&ouml;sen nach ihrer Aktualisierung eine Prozedur aus, die Sie f&uuml;r die entsprechende Ereigniseigenschaft hinterlegen (s. Quellcode 5).<\/p>\n<p>Die Prozedur setzt anhand der gew&auml;hlten Parameter einen SQL-Ausdruck zusammen.<\/p>\n<p>Dann weist sie den SQL-Ausdruck der Eigenschaft Datensatzherkunft des Listenfeldes zu. Das Listenfeld zeigt die gefundenen Datens&auml;tze an und erm&ouml;glicht den Aufruf einer Detailansicht durch einen Doppelklick auf den gew&uuml;nschten Eintrag. Daf&uuml;r ist eine Prozedur verantwortlich, die Sie f&uuml;r die Ereigniseigenschaft Beim Doppelklicken hinterlegen (s. Quellcode 6).<\/p>\n<p>Die ungewohnte Schreibweise des Wertes, der mit dem Parameter WhereCondition &uuml;bergeben wird, ist f&uuml;r GUIDs erforderlich. Wenn Sie sich die Beispieldatenbank genau ansehen, werden Sie noch weitere Besonderheiten bez&uuml;glich des Umgangs mit GUIDs herausfinden.<\/p>\n<p>Der Bericht repRezepte ist der einzige Bericht der Datenbank und dient der Ausgabe jeweils eines einzigen Rezeptes. Bild 11 zeigt die Vorschauansicht des Berichts f&uuml;r ein Beispielrezept.<\/p>\n<p>Als Datenherkunft des Berichts dient die Tabelle tblRezepte. Sie beinhaltet die wesentlichen Daten mit Ausnahme der Kategorien und der Zutaten. Die Kategorien werden w&auml;hrend des Formatierens des Berichts automatisch zusammengestellt. Die Zutaten befinden sich in einem in den Bericht integrierten Unterbericht namens srpRezepte.<\/p>\n<p><b>Zusammenstellung der Kategorien<\/b><\/p>\n<pre>    If Not IsNull(Me.cboZutat1) Then\r\n        strSQL = strSQL & \" AND RezeptID IN (SELECT \" _            & \" tblRezepteZutaten.RezeptID FROM \" _            & \"tblRezepteZutaten WHERE ZutatID = \" _            & \"{guid \" & Me.cboZutat1 & \"})\"\r\n    End If\r\n    '' entsprechende Anweisungen f&uuml;r die beiden weiteren Kombinationsfelder\r\n    Me.lstSuchergebnis.RowSource = strSQL\r\n    Me.lstSuchergebnis.Requery\r\nEnd Sub<\/pre>\n<p><b>Quellcode 5 (Fortsetzung)<\/b><\/p>\n<pre>Private Sub lstSuchergebnis_DblClick(Cancel As Integer)\r\n    DoCmd.OpenForm \"frmRezepte\", WhereCondition:=\"RezeptID = {guid \" & Me.lstSuchergebnis & \"}\"\r\n    DoCmd.Close acForm, Me.Name\r\nEnd Sub<\/pre>\n<p><b>Quellcode 6<\/b><\/p>\n<pre>Private Sub Detailbereich_Format(Cancel As Integer, _    FormatCount As Integer)\r\n    Dim db As Database\r\n    Dim rstKategorien As Recordset\r\n    Dim Kategorien As String\r\n    Set db = CurrentDb\r\n    Set rstKategorien = db.OpenRecordset(\"SELECT \" _        & \"Kategorie FROM qryRezepteKategorien WHERE \" _        & \" RezeptID = \" & _        StringFromGUID(Forms!frmRezepte!RezeptID), _        dbOpenDynaset)\r\n    Do While Not rstKategorien.EOF\r\n        Kategorien = Kategorien & \", \" _            & rstKategorien!Kategorie\r\n        rstKategorien.MoveNext\r\n    Loop\r\n    If Len(Trim(Kategorien)) &gt; 0 Then\r\n        Me.txtKategorien = \"Kategorien: \" _            & Trim(Mid(Kategorien, 2, _\r\n            Len(Kategorien) - 1))\r\n    End If\r\nEnd Sub<\/pre>\n<p><b>Quellcode 7<\/b><\/p>\n<p>Die Kategorien werden zum Zeitpunkt des Formatierens des Detailbereichs des Berichts dynamisch zusammengestellt. Dazu benutzt die Anwendung die Ereigniseigenschaft Beim Formatieren, die beim Aufrufen des Berichts mindestens einmal (in Abh&auml;ngigkeit von der Komplexit&auml;t des Berichts kann das auch mehrmals geschehen) aufgerufen wird.<\/p>\n<p>Die verantwortliche Prozedur finden Sie in Quellcode 7. Nach den erforderlichen Deklarationen weist die Prozedur dem Objekt rstKategorien eine Datensatzgruppe mit allen Kategorien zu, die mit dem angezeigten Rezept verkn&uuml;pft sind.<\/p>\n<p>Anschlie&szlig;end durchl&auml;uft sie per Do While-Schleife alle gefundenen Kategorien und setzt diese zu einer durch Kommata getrennten, vom Wort Kategorien: angef&uuml;hrten Liste zusammen. <\/p>\n<p><b>Der Unterbericht zur Anzeige der Zutaten<\/b><\/p>\n<p>Der Unterbericht srpRezepteZutaten dient der Anzeige der Zutaten des im Hauptbericht angezeigten Rezeptes.<\/p>\n<p>Es enth&auml;lt die drei Felder Anzahl, Einheit (in der Abbildung nicht genau zu erkennen) und Zutat. Wichtig ist hier, dass Sie die Eigenschaft Vergr&ouml;&szlig;erbar des Feldes Zutat auf den Wert Ja einstellen. Anderenfalls zeigt der Bericht nur den Text an, der in die erste Zeile des Textfeldes passt und unterschl&auml;gt den Rest.<\/p>\n<p><IMG height=\"202\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic012.png\" width=\"420\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 12:  Unterbericht zur Anzeige der Zutaten eines Rezeptes<\/span><\/b><\/p>\n<p><IMG height=\"292\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic013.png\" width=\"491\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 13:  Datenherkunft des Unterberichts<\/span><\/b><\/p>\n<p><IMG height=\"405\" src=\"..\/fileadmin\/_temp_\/{87641AC0-06C4-4CCF-99DD-320F3284CC08}\/pic014.png\" width=\"342\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 14:  Seiteneigenschaften des Unterberichts<\/span><\/b><\/p>\n<p>Als Datenherkunft des Unterberichts verwenden Sie die Abfrage qryRezepteZutaten (siehe Bild 13). Der Wert des Feldes RezeptID wird zwar nicht im Unterbericht angezeigt, aber Sie ben&ouml;tigen ihn f&uuml;r die Verkn&uuml;pfung zum Hauptbericht. Der Unterbericht soll schlie&szlig;lich nur die Zutaten anzeigen, die mit dem im Hauptbericht angezeigten Rezept verkn&uuml;pft sind.<\/p>\n<p>Die Datens&auml;tze sollen in zwei Spalten angezeigt werden. Die daf&uuml;r n&ouml;tige Einstellung nehmen Sie bei aktivierter Entwurfsansicht in den Seiteneigenschaften vor, die Sie nur &uuml;ber den Men&uuml;befehl Datei\/Seiten einrichten&#8230; aufrufen k&ouml;nnen.<\/p>\n<p>Passen Sie die Werte entsprechend Bild 14 an. Wichtig ist vor allem die Einstellung des Spaltenlayouts. Wenn Sie die erste H&auml;lfte der Zutaten in der entsprechenden Reihenfolge auf der linken Seite und die zweite H&auml;lfte auf der rechten Seite sehen m&ouml;chten, werden Sie hier entt&auml;uscht:<\/p>\n<p>Wenn Sie n&auml;mlich  die Option Nach unten, dann quer w&auml;hlen, teilt Access die Zutaten nicht auf beide Spalten gleich auf, sondern f&uuml;llt erst die linke Spalte bis zum unteren Rand. Beachten Sie bei Angabe der Spaltenbreite und des Spaltenabstands, dass die Summe der Breiten und Abst&auml;nde nicht gr&ouml;&szlig;er als die Breite des verf&uuml;gbaren Bereichs im Hauptbericht werden darf.<\/p>\n<p><b>Aufbau des Hauptberichts<\/b><\/p>\n<p>Der Hauptbericht birgt keine weiteren Besonderheiten. Beachten Sie, dass die Eigenschaften Verkn&uuml;pft von und Verkn&uuml;pft nach des Unterberichts beide auf den Wert RezeptID eingestellt sind.<\/p>\n<p>Die Musterl&ouml;sung enth&auml;lt eine Menge Stoff, den Sie vermutlich erst bei genauerer Untersuchung der Beispieldatenbank finden werden.<\/p>\n<p>Die Anwendung bietet zahllose Erweiterungsm&ouml;glichkeiten:<\/p>\n<li>Erstellen einer Export-Prozedur<\/li>\n<li>Erstellen weiterer Berichte, z. B. zum Ausdruck eines ganzen Kochbuchs<\/li>\n<li>Einf&uuml;gen von Bildern <\/li>\n<li>Erweiterung der Suchmaske<\/li>\n<li>Erweiterung um ein Kochlexikon<\/li>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>Rezepte2000.mdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/1115E262-2D92-47A9-8D9D-2AD4CC8EB972\/aiu_89.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Verwalten von Rezepten &#8211; das h&ouml;rt sich gar nicht nach einer Musterl&ouml;sung f&uuml;r Unternehmen an. Oder sind nur Hotelk&ouml;che angesprochen Nein. Neben dem Anspruch, ein Muster f&uuml;r eine Vielzahl von Anwendungen zu bieten, soll die vorliegende Musterl&ouml;sung auch von einer Vielzahl von Anwendern auf ihre eigenen Bed&uuml;rfnisse zugeschnitten werden k&ouml;nnen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662002,66062002,44000027],"tags":[],"class_list":["post-55000089","post","type-post","status-publish","format-standard","hentry","category-662002","category-66062002","category-Loesungen"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Rezepte verwalten mit Access - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Rezepte verwalten mit Access\" \/>\n<meta property=\"og:description\" content=\"Verwalten von Rezepten - das h&ouml;rt sich gar nicht nach einer Musterl&ouml;sung f&uuml;r Unternehmen an. Oder sind nur Hotelk&ouml;che angesprochen Nein. Neben dem Anspruch, ein Muster f&uuml;r eine Vielzahl von Anwendungen zu bieten, soll die vorliegende Musterl&ouml;sung auch von einer Vielzahl von Anwendern auf ihre eigenen Bed&uuml;rfnisse zugeschnitten werden k&ouml;nnen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2021-01-12T22:55:20+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg07.met.vgwort.de\/na\/3a354a1f2982415ba1dadcc08fe13b79\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"24\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Rezepte verwalten mit Access\",\"datePublished\":\"2021-01-12T22:55:20+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/\"},\"wordCount\":4284,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/3a354a1f2982415ba1dadcc08fe13b79\",\"articleSection\":[\"2002\",\"6\\\/2002\",\"L\u00f6sungen\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/\",\"name\":\"Rezepte verwalten mit Access - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/3a354a1f2982415ba1dadcc08fe13b79\",\"datePublished\":\"2021-01-12T22:55:20+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/3a354a1f2982415ba1dadcc08fe13b79\",\"contentUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/3a354a1f2982415ba1dadcc08fe13b79\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rezepte_verwalten_mit_Access\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Rezepte verwalten mit Access\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Rezepte verwalten mit Access - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/","og_locale":"de_DE","og_type":"article","og_title":"Rezepte verwalten mit Access","og_description":"Verwalten von Rezepten - das h&ouml;rt sich gar nicht nach einer Musterl&ouml;sung f&uuml;r Unternehmen an. Oder sind nur Hotelk&ouml;che angesprochen Nein. Neben dem Anspruch, ein Muster f&uuml;r eine Vielzahl von Anwendungen zu bieten, soll die vorliegende Musterl&ouml;sung auch von einer Vielzahl von Anwendern auf ihre eigenen Bed&uuml;rfnisse zugeschnitten werden k&ouml;nnen.","og_url":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/","og_site_name":"Access im Unternehmen","article_published_time":"2021-01-12T22:55:20+00:00","og_image":[{"url":"http:\/\/vg07.met.vgwort.de\/na\/3a354a1f2982415ba1dadcc08fe13b79","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"24\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Rezepte verwalten mit Access","datePublished":"2021-01-12T22:55:20+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/"},"wordCount":4284,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/3a354a1f2982415ba1dadcc08fe13b79","articleSection":["2002","6\/2002","L\u00f6sungen"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/","url":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/","name":"Rezepte verwalten mit Access - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/3a354a1f2982415ba1dadcc08fe13b79","datePublished":"2021-01-12T22:55:20+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/#primaryimage","url":"http:\/\/vg07.met.vgwort.de\/na\/3a354a1f2982415ba1dadcc08fe13b79","contentUrl":"http:\/\/vg07.met.vgwort.de\/na\/3a354a1f2982415ba1dadcc08fe13b79"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Rezepte_verwalten_mit_Access\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Rezepte verwalten mit Access"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000089","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55000089"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000089\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55000089"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55000089"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55000089"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}