{"id":55000280,"date":"2005-06-01T00:00:00","date_gmt":"2020-05-06T15:18:01","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=280"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Artikelverwaltung_Teil_2","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/","title":{"rendered":"Artikelverwaltung, Teil 2"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg03.met.vgwort.de\/na\/0156e3af372a426e8183da5c9746fd93\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Andr&eacute; Minhorst, Duisburg<\/b><\/p>\n<p><b>Im ersten Teil dieser Beitragsreihe haben Sie das Datenmodell und die wesentlichen Formulare der Artikelverwaltung kennen gelernt. Nun besch&auml;ftigen Sie sich mit den Inventuren: Welche Faktoren sind daf&uuml;r wichtig Wie werden bereits in einer Inventur ber&uuml;cksichtigte Daten bei folgenden Inventuren ausgeschlossen Au&szlig;erdem erfahren Sie in dieser Folge, wie Sie Berichte f&uuml;r die Ausgabe von Artikel- und Inventurdaten erstellen.<\/b><\/p>\n<h3>Hinweis<\/h3>\n<p>Die Musterl&ouml;sung zu diesem Beitrag hei&szlig;t Artikelverwaltung00.mdb und funktioniert mit Access 2000 und h&ouml;her. Sie finden die Datenbank auf der Heft-CD oder im Internet unter http:\/\/www.access-im-unternehmen.de (Shortlink 280). Der erste Teil dieses Beitrags steht an gleicher Stelle unter dem Shortlink 273 bereit. <\/p>\n<p>Eine Inventur ist die Aufnahme des Bestands aller Verm&ouml;genswerte eines Unternehmens, also auch der vorhandenen Artikel. Die in die Artikelverwaltung integrierte Inventurfunktion erm&ouml;glicht dies ausschlie&szlig;lich f&uuml;r die Artikel; die Aufnahme aller f&uuml;r eine Inventur notwendigen Informationen w&uuml;rde den Umfang des Beitrags leider sprengen. Diese Inventurfunktion ber&uuml;cksichtigt lediglich die in der Datenbank gespeicherten Artikel. Die Menge der vorhandenen Artikel sowie deren Ma&szlig;einheiten sollten regelm&auml;&szlig;ig zum Bilanzstichtag bekannt sein, um eine ordnungsgem&auml;&szlig;e Buchhaltung zu erm&ouml;glichen. Der Artikelbestand muss allerdings nicht genau an diesem Tag gez&auml;hlt werden.<\/p>\n<h2>Inventurarten<\/h2>\n<p><IMG height=\"344\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic001.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 1:  Aufruf der Inventur<\/span><\/b><\/p>\n<p>Es gibt mehrere Varianten von Inventuren, unter anderem die folgenden:<\/p>\n<li>Stichtagsinventur: Findet innerhalb von zehn Tagen vor und zehn Tagen nach dem Abschluss-Stichtag statt. Das Ergebnis wird auf den Abschluss-Stichtag hochgerechnet.<\/li>\n<li>Verlegte Inventur: Erfolgt zwischen drei Monaten vor und zwei Monaten nach dem Abschluss-Stichtag. Die Z&auml;hlung der unterschiedlichen Artikel muss nicht an einem Tag erfolgen. Die Werte f&uuml;r jeden einzelnen Artikel werden auf den Abschluss-Stichtag hochgerechnet.<\/li>\n<li>Permanente Inventur: Die Inventur erfolgt fast ausschlie&szlig;lich &uuml;ber die Bewertung der Ein- und Ausg&auml;nge eines Artikels. Der Soll- und der Ist-Zustand m&uuml;ssen einmal im Jahr abgeglichen werden.<\/li>\n<p>Die Anwendung unterst&uuml;tzt alle genannten Inventurarten. Der einzige Unterschied zwischen den Arten ist der Zeitpunkt, an dem Soll- und Istwert des Bestands eines Artikels ermittelt werden m&uuml;ssen. Mit der Artikelverwaltung k&ouml;nnen Sie den Zeitpunkt der Z&auml;hlung f&uuml;r jeden einzelnen Artikel festlegen.<\/p>\n<h2>Wie arbeitet die Inventurfunktion<\/h2>\n<p>Die Inventurfunktion kann f&uuml;r jeden Artikel einzeln aufgerufen werden. Der Aufruf erfolgt &uuml;ber die Schaltfl&auml;che Inventur starten der Detailansicht eines Artikels im Formular frmArtikel (siehe Bild 1).<\/p>\n<p>Die dadurch ausgel&ouml;ste Ereignisprozedur &ouml;ffnet das Formular frmInventur f&uuml;r den aktuell im Artikelformular angezeigten Artikel (siehe Bild 2).<\/p>\n<p><IMG height=\"269\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic002.png\" width=\"348\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 2:  Eingabe des gez&auml;hlten Bestands<\/span><\/b><\/p>\n<p>Dieses Formular zeigt folgende Informationen an:<\/p>\n<li>Datum der letzten Inventur<\/li>\n<li>Bestand bei der letzten Inventur<\/li>\n<li>Datum der aktuellen Inventur<\/li>\n<li>Berechneter Bestand (aktuelle Inventur)<\/li>\n<li>Tats&auml;chlicher Bestand (aktuelle Inventur)<\/li>\n<li>Differenz zwischen tats&auml;chlichem und berechnetem Bestand<\/li>\n<p>Die mit einem roten Rahmen versehenen Informationen kann der Benutzer selbst &auml;ndern. Das Datum wird automatisch mit dem aktuellen Datum vorgelegt, es kann aber nachtr&auml;glich ge&auml;ndert werden.<\/p>\n<p>Bei der Programmierung des Formulars frmInventur und der enthaltenen Funktionen sind einige Punkte zu beachten, die im nachfolgenden Abschnitt gekl&auml;rt werden. Anschlie&szlig;end finden Sie eine Beschreibung der Funktion selbst.<\/p>\n<h2>Wichtige Voraussetzungen<\/h2>\n<p>Die Inventurfunktion startet mit dem Mausklick auf die Schaltfl&auml;che Inventur starten des Artikelformulars. Das Formular frmInventur zur Eingabe der Inventurdaten bezieht seine Daten &uuml;ber diverse Zugriffe auf die in der Datenbank enthaltenen Tabellen.<\/p>\n<p>So durchsucht das Formular die Tabelle tblInventuren, ob es bereits eine Inventur zu dem zu untersuchenden Artikel gibt, und liest gegebenenfalls das Datum der Inventur und den Bestand in die entsprechenden Felder des Formulars ein.<\/p>\n<p>Ist noch kein Inventurdatensatz vorhanden und dementsprechend noch keine Z&auml;hlung des Artikels erfolgt, verwendet das Formular Standardwerte: als Datum den 1.1.1900 und als Bestand den Wert 0.<\/p>\n<p>Der im Feld Berechneter Bestand angezeigte Wert ist die Anzahl des Artikels, die sich aus dem Stand bei der letzten Inventur und den seitdem erfolgten Zu- und Abg&auml;ngen berechnet.<\/p>\n<p>Dabei spielt nat&uuml;rlich das Datum der aktuellen Inventur eine wichtige Rolle: Beim &ouml;ffnen des Formulars zeigt dieses das aktuelle Datum und den Bestand zu diesem Datum an. Wenn der Benutzer das Datum ver&auml;ndert, wird auch der berechnete Bestand angepasst. Neben dem Inventurdatum muss der Benutzer auch die tats&auml;chliche Anzahl des Artikels angeben. Erst dann wird die Differenz berechnet und die Inventurdaten k&ouml;nnen gespeichert werden.<\/p>\n<pre>Private Sub Form_Current()\r\n    Dim datLetzteInventur As Date\r\n    Dim lngBestandLetzteInventur As Long\r\n    Me!txtArtikel = Artikelbezeichnung(lngArtikelID)\r\n    Call LetzteInventur(lngArtikelID, datLetzteInventur, lngBestandLetzteInventur)\r\n    Me!txtDatumLetzteInventur = datLetzteInventur\r\n    Me!txtBestandLetzteInventur = lngBestandLetzteInventur\r\n    Me!txtDatumAktuelleInventur = Date\r\n    Me!txtBestandAktuelleInventurBerechnet = lngBestandLetzteInventur + _        BestandsaenderungSumme(lngArtikelID, Date)\r\nEnd Sub<\/pre>\n<p><b>Quellcode 1<\/b><\/p>\n<pre>Private Function Artikelbezeichnung(lngArtikelID As Long) As String\r\n    Dim db As DAO.Database\r\n    Dim rstArtikel As DAO.Recordset\r\n    Set db = CurrentDb\r\n    Set rstArtikel = db.OpenRecordset(\"SELECT Bezeichnung FROM tblArtikel \" _        & \"WHERE ArtikelID = \" & lngArtikelID, dbOpenDynaset)\r\n    Artikelbezeichnung = rstArtikel!Bezeichnung\r\n    Set db = Nothing\r\nEnd Function<\/pre>\n<p><b>Quellcode 2<\/b><\/p>\n<h2>Technische Umsetzung<\/h2>\n<p>Die erste Prozedur, die bei der Verwendung des Formulars frmInventuren zum Zuge kommt, ist die Ereignisprozedur, die beim &ouml;ffnen des Formulars ausgel&ouml;st wird. Sie weist der modulweit deklarierten Variablen lngArtikel die per &ouml;ffnungsargument von der aufrufenden Instanz &uuml;bergebene Artikelnummer zu.<\/p>\n<pre>Private Sub Form_Open(Cancel As Integer)\r\n    lngArtikelID = Me.OpenArgs\r\nEnd Sub<\/pre>\n<p>Die Ermittlung der im Formular angezeigten Werte erfolgt in der Ereignisprozedur, die durch das Ereignis Beim Anzeigen ausgel&ouml;st wird (s. Quellcode 1). Die Prozedur ermittelt zun&auml;chst anhand des Werts des Feldes ArtikelID die Artikelbezeichnung und tr&auml;gt diese in das Textfeld txtArtikel ein. Dazu verwendet sie die Prozedur aus Quellcode 2. Diese Prozedur liefert die Artikelbezeichnung f&uuml;r die als Parameter &uuml;bergebene Artikel-ID. Dabei instanziert sie ein Database-Objekt und ein Recordset-Objekt und ermittelt &uuml;ber eine entsprechende Abfrage eine Datensatzgruppe mit dem gesuchten Artikeldatensatz.<\/p>\n<h3>Performance statt Dlookup<\/h3>\n<p>Statt dieser Funktion h&auml;tte man auch einen entsprechenden Aufruf der Dlookup-Funktion verwenden k&ouml;nnen (in einer Zeile):<\/p>\n<pre>Me!txtArtikel = DLookup(\"Bezeichnung\", \"tblArtikel\", \"ArtikelID = \" & lngArtikelID)<\/pre>\n<p>Das w&auml;re zwar wesentlich platzsparender und damit auch &uuml;bersichtlicher gewesen, allerdings ist die Performance der Dom&auml;nenfunktionen relativ schlecht. Ein konkreter Test mit je 1000 Aufrufen jeder Funktion in einer Schleife brachte ein eindeutiges Ergebnis: &uuml;ber mehrere L&auml;ufe hinweg war die DAO-Variante circa 50-100% schneller als die Dlookup-Funktion.<\/p>\n<pre>Private Sub LetzteInventur(lngArtikelID As Long, datLetzteInventur As Date, _    lngBestandLetzteInventur As Long)\r\n    Dim db As DAO.Database\r\n    Dim rstInventuren As DAO.Recordset\r\n    Dim rstBestandsaenderungen As DAO.Recordset\r\n    Set db = CurrentDb\r\n    Set rstInventuren = db.OpenRecordset(\"SELECT TOP 1 Inventurdatum, \" _        & \"Lagerbestand FROM tblInventuren WHERE ArtikelID = \" & lngArtikelID _        & \" ORDER BY Inventurdatum DESC\", dbOpenDynaset)\r\n    If Not rstInventuren.EOF Then\r\n        datLetzteInventur = rstInventuren!Inventurdatum\r\n        lngBestandLetzteInventur = rstInventuren!Lagerbestand\r\n    Else\r\n        Set rstBestandsaenderungen = db.OpenRecordset(\"SELECT Datum \" _            & \"FROM tblBestandsaenderungen WHERE ArtikelID = \" & lngArtikelID _            & \" ORDER BY Datum DESC\", dbOpenDynaset)\r\n        If Not rstBestandsaenderungen.EOF Then\r\n            datLetzteInventur = rstBestandsaenderungen!Datum\r\n        Else\r\n            datLetzteInventur = \"1.1.1900\"\r\n        End If\r\n        lngBestandLetzteInventur = 0\r\n        rstBestandsaenderungen.Close\r\n    End If\r\n    rstInventuren.Close\r\n    Set rstInventuren = Nothing\r\n    Set rstBestandsaenderungen = Nothing\r\nEnd Sub<\/pre>\n<p><b>Quellcode 3<\/b><\/p>\n<h3>Daten der letzten Inventur ermitteln<\/h3>\n<p>In einer weiteren externen Routine ermittelt die Prozedur Form_Current das Datum der letzten Inventur und den Bestand bei der letzten Inventur.<\/p>\n<p>Da die beiden zu ermittelnden Werte aus der gleichen Tabelle stammen und gleichzeitig mit einer Routine ermittelt werden sollen, k&ouml;nnen nicht beide per R&uuml;ckgabewert an die aufrufende Prozedur &uuml;bermittelt werden. <\/p>\n<p>Die betroffene Routine hei&szlig;t LetzteInventur und hat drei Parameter, von denen einer als Eingangs- und zwei als Ausgangsparameter verwendet werden. Die Ausgangsparameter werden bereits in der aufrufenden Prozedur Form_Current deklariert und als Variable &uuml;bergeben (in einer Zeile):<\/p>\n<pre>Call LetzteInventur(lngArtikelID, datLetzteInventur, lngBestandLetzteInventur)<\/pre>\n<p>Die beiden letzten Parameter dieses Aufrufs werden in der Prozedur LetzteInventur mit den gew&uuml;nschten Daten gef&uuml;llt (s. Quellcode 3).<\/p>\n<p>Um diese Daten zu ermitteln, greift die Prozedur auf zwei Tabellen zu. Zun&auml;chst sucht sie in der Tabelle tblInventuren nach der aktuellsten Inventur f&uuml;r diesen Artikel. Die dazu verwendete Abfrage ist nach dem Inventurdatum sortiert und gibt durch die Option TOP 1 nur den ersten Eintrag der Datensatzgruppe zur&uuml;ck. Ist dieser Datensatz vorhanden, liest die Prozedur das Inventurdatum und den Lagerbestand aus der Tabelle aus und schreibt sie in die entsprechenden R&uuml;ckgabeparameter.<\/p>\n<pre>Private Function BestandsaenderungSumme(lngArtikelID As Long, _    datAktuelleInventur As Date) As Long\r\n    Dim db As DAO.Database\r\n    Dim rstBestandsaenderungSumme As DAO.Recordset\r\n    Set db = CurrentDb\r\n    Set rstBestandsaenderungSumme = _        db.OpenRecordset(\"SELECT Sum(Anzahl * Vorzeichen) AS LagerbestandGesamt \" _        & \"FROM tblBestandsaenderungen WHERE ArtikelID = \" & lngArtikelID _        & \" AND Inventur = False AND Datum &lt;= \" _        & ISODatum(Me.txtDatumAktuelleInventur), dbOpenDynaset)\r\n    BestandsaenderungSumme = Nz(rstBestandsaenderungSumme!LagerbestandGesamt, 0)\r\n    rstBestandsaenderungSumme.Close\r\n    Set rstBestandsaenderungSumme = Nothing\r\n    Set db = Nothing\r\nEnd Function<\/pre>\n<p><b>Quellcode 4<\/b><\/p>\n<p>Wenn die Datensatzgruppe leer ist, wurde noch keine Inventur f&uuml;r diesen Artikel durchgef&uuml;hrt. In dem Fall sind weitere Untersuchungen erforderlich, um halbwegs sinnvolle Werte zur&uuml;ckzugeben. Wenn noch keine Inventur stattgefunden hat, w&auml;re der Stand vor der ersten Bestands&auml;nderung der letzte best&auml;tigte Stand &#8211; und der ist immer 0. Als Datum stellt die Prozedur in dem Fall das Datum der ersten Bestands&auml;nderung ein. Wenn weder eine Bestands&auml;nderung noch eine Inventur f&uuml;r einen Artikel stattgefunden hat, ist Fantasie gefragt: Als Datum wird dann der 1.1.1900 und als Bestand der Wert 0 zur&uuml;ckgegeben.<\/p>\n<h3>Einstellen des Datums der aktuellen Inventur<\/h3>\n<p>Als Datum f&uuml;r die aktuelle Inventur tr&auml;gt die Prozedur Form_Current das aktuelle Datum ein.<\/p>\n<h3>Bestands&auml;nderung berechnen<\/h3>\n<p>Fehlt noch die berechnete Bestands&auml;nderung seit der letzten Inventur. F&uuml;r deren Ermittlung ist wiederum eine Funktion zust&auml;ndig. Diese hei&szlig;t BestandsaenderungSumme und erwartet die Artikel-ID und das Datum der aktuellen Inventur, das auch in diesem Fall mit der Date-Funktion ermittelt wird (s. Quellcode 4).<\/p>\n<p>Diese Funktion berechnet mit der Sum-Funktion in einer Abfrage &uuml;ber die Datens&auml;tze der Tabelle tblBestandsaenderungen die Gr&ouml;&szlig;e der &auml;nderung am Bestand des betroffenen Artikels.<\/p>\n<p>Dabei offenbart sich die Technik, mit der eine Bestandsver&auml;nderung als inventarisiert gekennzeichnet wird: Die Tabelle tblBestandsaenderungen enth&auml;lt ein Feld namens Inventur, das nach der Ber&uuml;cksichtigung in einer Inventur den Wert True erh&auml;lt.<\/p>\n<p><!--30percent--><\/p>\n<p>Die Abfrage zum Summieren der neuen Bestands&auml;nderungen ber&uuml;cksichtigt dementsprechend nur jene Eintr&auml;ge, bei denen das Feld Inventur den Wert False hat und deren Datum kleiner oder gleich dem Inventurdatum ist. Das F&uuml;llen der Felder des Formulars ist somit abgeschlossen, was den automatischen Part angeht. Nun folgen noch die Verarbeitung der Benutzereingaben und das Speichern der Inventurdaten.<\/p>\n<h3>Datum der aktuellen Inventur &auml;ndern<\/h3>\n<p>Das Datum der aktuellen Inventur wird standardm&auml;&szlig;ig auf das aktuelle Datum eingestellt. Unter Umst&auml;nden sollen aber Daten von einer Inventur eingetragen werden, deren Datum in der Vergangenheit liegt. Daher kann der Benutzer das Datum der aktuellen Inventur nachtr&auml;glich &auml;ndern.<\/p>\n<pre>Private Sub txtDatumAktuelleInventur_BeforeUpdate(Cancel As Integer)\r\n    If CDate(Me.txtDatumAktuelleInventur) &lt;= CDate(Me.txtDatumLetzteInventur) Then\r\n        MsgBox \"Das Datum der aktuellen Inventur muss nach dem Datum der \" _            & \"letzten Inventur liegen.\", vbExclamation + vbOKOnly, \"Ung&uuml;ltiges Datum\"\r\n        Cancel = True\r\n        Me!txtDatumAktuelleInventur = Date\r\n    End If\r\nEnd Sub<\/pre>\n<p><b>Quellcode 5<\/b><\/p>\n<pre>Private Sub txtDatumAktuelleInventur_AfterUpdate()\r\n    Dim lngBestandLetzteInventur As Long\r\n    Dim datAktuelleInventur As Date\r\n    lngBestandLetzteInventur = Me.txtBestandLetzteInventur\r\n    datAktuelleInventur = Me.txtDatumAktuelleInventur\r\n    Me!txtBestandAktuelleInventurBerechnet = lngBestandLetzteInventur + _        BestandsaenderungSumme(lngArtikelID, datAktuelleInventur)\r\nEnd Sub<\/pre>\n<p><b>Quellcode 6<\/b><\/p>\n<p>Bevor sich die &auml;nderung auswirkt, &uuml;berpr&uuml;ft die Vor Aktualisierung-Ereignisprozedur des Textfeldes txtDatumAktuelleInventur, ob das Datum mindestens einen Tag sp&auml;ter als der Tag der letzten Inventur liegt. Die entsprechende Prozedur finden Sie in Quellcode 5.<\/p>\n<h3>Angezeigte Werte im Inventurformular an neues Inventurdatum anpassen<\/h3>\n<p>Wenn das neue Inventurdatum g&uuml;ltig ist, muss der aktuell berechnete Bestand neu ermittelt werden. Die notwendigen Anweisungen befinden sich in der Prozedur, die durch das Ereignis Nach Aktualisierung des Textfeldes txtDatumAktuelleInventur ausgel&ouml;st wird (s. Quellcode 6).<\/p>\n<h3>Inventurdaten speichern<\/h3>\n<p>Wenn der Benutzer das Datum der aktuellen Inventur sowie den gez&auml;hlten Lagerbestand in die entsprechenden Textfelder eingegeben hat, k&ouml;nnen die Inventurdaten gespeichert werden. Diesen Vorgang kann der Benutzer mit der Schaltfl&auml;che Inventur speichern starten.<\/p>\n<p>Die dadurch ausgel&ouml;ste Ereignisprozedur (s. Quellcode 7) pr&uuml;ft zun&auml;chst, ob die beiden Felder txtDatumAktuelleInventur und txtBestandAktuelleInventurGezaehlt g&uuml;ltige Werte enthalten, und bricht die Prozedur gegebenenfalls mit einer entsprechenden Fehlermeldung ab.<\/p>\n<p>Anderenfalls steht dem Speichern der neuen Inventur nichts mehr im Wege: Eine weitere If&#8230;Then-Abfrage &uuml;berpr&uuml;ft, ob zwischen dem berechneten und dem gez&auml;hlten Bestand des betroffenen Artikels eine Differenz besteht.<\/p>\n<p>Falls ja, wird ein entsprechender Umbuchungsdatensatz in den Tabellen tblUmbuchungen und tblBestandsaenderungen angelegt (siehe Bild 3). Von dem Vorgang sind zwei Tabellen betroffen, weil es mehrere Auspr&auml;gungen einer Bestandsver&auml;nderung gibt &#8211; Eing&auml;nge, Ausg&auml;nge und Umbuchungen. Alle haben spezielle Eigenschaften, die jeweils in unterschiedlichen Tabellen gespeichert und mit der Tabelle tblBestandsaenderungen per 1:1-Beziehung verbunden werden. Weitere Informationen zum Datenmodell und zu dieser Vorgehensweise finden Sie im ersten Teil dieser Beitragsreihe in Ausgabe 2\/2005.<\/p>\n<p>F&uuml;r das Anlegen eines Datensatzes eignet sich eine Abfrage bestens &#8211; die hier verwendete finden Sie in der Entwurfsansicht in Bild 4.<\/p>\n<p><IMG height=\"107\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic003.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 3:  Beispiel f&uuml;r einen Umbuchungsdatensatz<\/span><\/b><\/p>\n<p>Anschlie&szlig;end f&uuml;hrt die Prozedur noch zwei Aktionsabfragen aus: Die erste f&uuml;gt den Inventurdatensatz mit der Artikel-ID, dem Inventurdatum und dem Lagerbestand zur Tabelle tblInventuren hinzu.<\/p>\n<p><IMG height=\"254\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic004.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 4:  Abfrage zum Hinzuf&uuml;gen von Umbuchungsdatens&auml;tzen<\/span><\/b><\/p>\n<p>Die zweite sorgt daf&uuml;r, dass alle Bestands&auml;nderungen, deren Datum kleiner oder gleich dem aktuellen Inventurdatum ist und die noch nicht per Inventur erfasst wurden, als inventarisiert gekennzeichnet werden.<\/p>\n<p>Damit werden auch solche Bestands&auml;nderungen erfasst, die vor dem Datum der letzten Inventur erfolgt sind &#8211; es kann unter Umst&auml;nden vorkommen, dass eine Bestands&auml;nderung zu sp&auml;t im System gebucht und nicht mehr von einer zeitnah stattfindenden Inventur ber&uuml;cksichtigt wird.<\/p>\n<p>Es ist nicht einfach, bei Wareneing&auml;ngen, Warenausg&auml;ngen und Umbuchungen mit verschiedenen Ursachen den &uuml;berblick zu behalten &#8211; schon gar nicht, wenn der Monitor die Sicht dabei einschr&auml;nkt.<\/p>\n<p>Daher finden Sie nachfolgend die Beschreibung eines Berichtes, mit dem Sie alle Bestands&auml;nderungen &uuml;bersichtlich ausgeben k&ouml;nnen.<\/p>\n<p>Dabei sollen zwei Sortierungen beziehungsweise Gruppierungen m&ouml;glich sein: Zun&auml;chst soll der Bericht die Daten nat&uuml;rlich in der chronologischen Reihenfolge ausgeben k&ouml;nnen &#8211; und zwar gemischt und nicht nach Ein- und Ausg&auml;ngen oder Umbuchungen sortiert. Die zweite Variante sieht dann eine Gruppierung nach der Art der Bestands&auml;nderung vor.<\/p>\n<h2>Erstellen der Datenherkunft des Berichts<\/h2>\n<p>Die Anzeige der Wareneing&auml;nge, Warenausg&auml;nge und Umbuchungen in einem Bericht ist nicht trivial, da die Daten aus einer Haupttabelle stammen, deren Datens&auml;tze mit je einer weiteren Tabelle per 1:1-Beziehung verkn&uuml;pft sind.<\/p>\n<p>Um diese Tabellen als Datenherkunft f&uuml;r einen Bericht zu verwenden, ist die Verwendung einer UNION-Abfrage angezeigt (s. Quellcode 8).<\/p>\n<p>Die UNION-Abfrage namens qryBestandsaenderungen fasst die drei Abfragen qryUmbuchungen, qryWareneingang und qryWarenausgang zusammen und f&uuml;gt ein weiteres Feld namens Bestandsaenderungsart hinzu, das einen der drei Werte Umbuchung, Wareneingang oder Warenausgang annehmen kann.<\/p>\n<pre>Private Sub cmdInventurSpeichern_Click()\r\n    Dim db As DAO.Database\r\n    Set db = CurrentDb\r\n    If Not IsDate(Nz(Me.txtDatumAktuelleInventur, \"\")) Then\r\n        MsgBox \"Bitte geben Sie ein g&uuml;ltiges Datum f&uuml;r die Inventur ein.\"\r\n        Exit Sub\r\n        Me.txtDatumAktuelleInventur.SetFocus\r\n    End If\r\n    If Not IsNumeric(Nz(Me.txtBestandAktuelleInventurGezaehlt, \"\")) Then\r\n        MsgBox \"Bitte geben Sie den gez&auml;hlten Bestand f&uuml;r diesen Artikel ein.\"\r\n        Me.txtBestandAktuelleInventurGezaehlt.SetFocus\r\n        Exit Sub\r\n    End If\r\n    If Me.txtDifferenz &lt;&gt; 0 Then\r\n        db.Execute \"INSERT INTO qryUmbuchungen(ArtikelID, Anzahl, Datum, \" _            & \"UmbuchungsartID, Bemerkungen) VALUES(\" & lngArtikelID & \", \" _            & Me.txtDifferenz & \", ''\" & Me.txtDatumAktuelleInventur _            & \"'', 1, ''Anpassung des berechneten an den gez&auml;hlten Bestand'')\"\r\n    End If\r\n    db.Execute \"INSERT INTO tblInventuren(ArtikelID, Inventurdatum, Lagerbestand) \" _        & \" VALUES(\" & lngArtikelID & \", ''\" & Me.txtDatumAktuelleInventur & \"'', \" _        & Me.txtBestandAktuelleInventurGezaehlt & \")\"\r\n    db.Execute \"UPDATE tblBestandsaenderungen SET Inventur = True \" _        & \"WHERE ArtikelID = \" & lngArtikelID & \" AND Datum &gt; \" _        & ISODatum(Me.txtBestandLetzteInventur) & \" AND Datum &lt;= \" _        & ISODatum(Me.txtDatumAktuelleInventur)\r\n    Set db = Nothing\r\n    DoCmd.Close acForm, Me.Name\r\nEnd Sub<\/pre>\n<p><b>Quellcode 7<\/b><\/p>\n<pre>SELECT qryUmbuchungen.BestandsaenderungID, qryUmbuchungen.ArtikelID, qryUmbuchungen.AnzahlMitVorzeichen, qryUmbuchungen.Datum, 0 AS Preis, ''Umbuchung'' AS Bestandsaenderungsart \r\nFROM qryUmbuchungen\r\nUNION\r\nSELECT qryWareneingang.BestandsaenderungID, qryWareneingang.ArtikelID, qryWareneingang.AnzahlMitVorzeichen, qryWareneingang.Datum, qryWareneingang.Einkaufspreis AS Preis,  ''Wareneingang'' AS Bestandsaenderungsart \r\nFROM qryWareneingang\r\nUNION \r\nSELECT qryWarenausgang.BestandsaenderungID, qryWarenausgang.ArtikelID, qryWarenausgang.AnzahlMitVorzeichen, qryWarenausgang.Datum, qryWarenausgang.Verkaufspreis AS Preis, ''Warenausgang'' AS Bestandsaenderungsart \r\nFROM qryWarenausgang\r\nORDER BY Datum;<\/pre>\n<p><b>Quellcode 8<\/b><\/p>\n<p>Damit das Ergebnis der Abfrage nach dem Datum sortiert wird, legen Sie die entsprechende ORDER BY-Klausel nicht f&uuml;r jede Teilabfrage, sondern nur f&uuml;r die letzte Abfrage an. Bild 5 zeigt das Ergebnis der Abfrage mit einigen Beispieldaten an.<\/p>\n<p><IMG height=\"268\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic005.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 5:  Ergebnis der UNION-Abfrage aus Quellcode 8<\/span><\/b><\/p>\n<p><IMG height=\"179\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic006.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 6:  Erster Entwurf der &uuml;bersicht der Bestands&auml;nderungen<\/span><\/b><\/p>\n<p><IMG height=\"285\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic007.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 7:  Anzeige aller Bestands&auml;nderungen<\/span><\/b><\/p>\n<h2>Anzeigen der Lagerbewegungen im Bericht<\/h2>\n<p>Die Anzeige der Lagerbewegungen scheint auf den ersten Blick einfach, aber wenn man sich ein wenig Gedanken &uuml;ber die M&ouml;glichkeiten macht, fallen einem schon eine Menge Varianten ein.<\/p>\n<p>Man k&ouml;nnte beispielsweise<\/p>\n<li>die Lagerbewegungen f&uuml;r einen oder mehrere Artikel in einem Bericht anzeigen,<\/li>\n<li>die Lagerbewegungen zwischen zwei Inventuren anzeigen,<\/li>\n<li>die Inventurergebnisse mit anzeigen,<\/li>\n<li>den Verlauf des Bestands f&uuml;r einen oder mehrere Artikel &uuml;ber der Zeit darstellen.<\/li>\n<p>Berichte sind so flexibel, dass man sich fast alle W&uuml;nsche damit erf&uuml;llen kann. Manche Konstellationen ben&ouml;tigen allerdings unter Umst&auml;nden etwas mehr Zeit f&uuml;r die Zusammenstellung der Daten und die Anzeige des Resultats. Meist passiert dies, wenn die anzuzeigenden Daten nicht mehr allein durch die Datenbindung, sondern per VBA ermittelt oder erzeugt werden m&uuml;ssen.<\/p>\n<h3>Aller Anfang ist schwer &#8230;<\/h3>\n<p>Damit der Anfang in diesem Fall nicht schwer wird, beginnen wir mit einer kleinen Aufw&auml;rm&uuml;bung: Die erste Variante des Berichts soll einfach nur alle Lagerbewegungen anzeigen. Als Datenherkunft stellt man dazu einfach die soeben erstellte Abfrage qryBestandsaenderungen  ein.<\/p>\n<p>Die Entwurfsansicht aus Bild 6 zeigt, wie die einzelnen Felder der Abfrage im Bericht angezeigt werden sollen.<\/p>\n<p><IMG height=\"234\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic008.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 8:  Die um die Artikeltabelle erweiterte Datenherkunft<\/span><\/b><\/p>\n<p>Das Ergebnis ist nat&uuml;rlich nicht das gew&uuml;nschte Endergebnis. Der Bericht zeigt in dieser Version zwar alle Bestands&auml;nderungen an, aber es ist kein Bezug zum jeweiligen Artikel erkennbar (siehe Bild 7).<\/p>\n<p><IMG height=\"330\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic009.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 9:  Gruppieren von Bestandsver&auml;nderungen nach dem Artikel<\/span><\/b><\/p>\n<p>Bringen Sie also ein wenig &uuml;bersicht hinein. Die Datenherkunft in der bisherigen Form beinhaltet leider nicht den Artikelnamen. Um diesen ebenfalls anzeigen zu k&ouml;nnen, m&uuml;ssen Sie die dem Bericht zugrunde liegende Abfrage ein wenig erweitern.<\/p>\n<p>Dazu erstellen Sie eine neue Abfrage, die auf der Abfrage qryBestandsaenderungen und der Tabelle tblArtikel basiert. Sie ben&ouml;tigen alle Felder der Abfrage qryBestandsaenderungen und nur das Feld Bezeichnung der Tabelle tblArtikel (siehe Bild 8).<\/p>\n<p>Damit die Bestands&auml;nderungen im Bericht nach den Artikeln gruppiert werden, m&uuml;ssen Sie eine entsprechende Einstellung im Dialog Sortieren und Gruppieren vornehmen (siehe Bild 9). Stellen Sie dort au&szlig;erdem die Reihenfolge f&uuml;r das Datum ein; die Sortierung in der Abfrage qryBestandsaenderungen ist hier nicht mehr g&uuml;ltig.<\/p>\n<h3>Gruppenkopf zu Beginn der Gruppe und auf neuer Seite<\/h3>\n<p>Der Gruppenkopf soll nicht nur &uuml;ber dem ersten Element der Gruppe stehen, sondern &#8211; wenn die Elemente der Gruppe &uuml;ber zwei oder mehr Seiten verteilt sind &#8211; auch auf den Folgeseiten angezeigt werden. Um dies zu erreichen, stellen Sie die Eigenschaft Bereich wiederholen des Bereichs Gruppenkopf0 auf den Wert Ja ein.<\/p>\n<h3>Gruppenkopf am Seitenende verhindern<\/h3>\n<p>Nun kann es immer noch passieren, dass der Gruppenkopf am Ende einer Seite platziert wird, aber auf dieser Seite keine entsprechenden Gruppenelemente mehr vorhanden sind. Um das zu verhindern, stellen Sie die Eigenschaft Zusammenhalten in den Gruppierungseigenschaften auf den Wert Mit 1. Detaildatensatz ein.<\/p>\n<pre>Option Compare Database\r\nOption Explicit\r\nDim lngArtikelID As Long\r\nPrivate Sub Gruppenkopf0_Print(Cancel As Integer, _    PrintCount As Integer)\r\n    If lngArtikelID = Me!ArtikelID Then\r\n            Me.txtFortsetzung = \"(Fortsetzung)\"\r\n    Else\r\n        Me.txtFortsetzung = \"\"\r\n    End If\r\n    lngArtikelID = Me!ArtikelID\r\nEnd Sub<\/pre>\n<p><b>Quellcode 9<\/b><\/p>\n<p><IMG height=\"326\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic010.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 10:  Hinweis auf eine fortgesetzte Liste<\/span><\/b><\/p>\n<h3>Fortsetzung oder nicht<\/h3>\n<p>Wenn eine Gruppierung sich &uuml;ber mehr als eine Seite erstreckt, w&auml;re es sch&ouml;n, wenn der Gruppenkopf der Folgeseiten anzeigen k&ouml;nnte, dass es sich dabei um die Fortsetzung der Gruppierungselemente von der vorherigen Seite handelt.<\/p>\n<p>Hier ist nun endg&uuml;ltig ein wenig VBA notwendig: Beim Ausgeben des Gruppenkopfes soll &uuml;berpr&uuml;ft werden, ob die vorherige Seite bereits Datens&auml;tze dieser Gruppierung angezeigt hat.<\/p>\n<p>Dazu f&uuml;gen Sie zun&auml;chst dem Detailbereich des Berichts das Feld ArtikelID hinzu, machen es aber direkt unsichtbar. Dieses Feld wird in dem folgenden VBA-Code referenziert. Quellcode 9 enth&auml;lt den kompletten Inhalt des Berichtsmoduls bis zu diesem Zeitpunkt. Die Variable lngArtikelID dient dem Speichern der aktuellen ArtikelID &#8211; also dem Wert, nach dem die in dem Bericht angezeigten Bestands&auml;nderungen gruppiert sind.<\/p>\n<p>Die Prozedur Gruppenkopf0_Print wird jeweils durch die Ereigniseigenschaft Beim Drucken des Bereichs aufgerufen. Beim ersten Aufruf hat die Variable lngArtikelID den Wert 0. Da der Vergleichswert in der If&#8230;Then-Bedingung die aktuelle ArtikelID enth&auml;lt, ist die Bedingung beim ersten Durchlauf garantiert nicht erf&uuml;llt und es wird eine leere Zeichenfolge in das Textfeld txtFortsetzung geschrieben.<\/p>\n<p>Gleichzeitig erh&auml;lt die Variable lngArtikelID die ID des aktuellen Artikels. Der n&auml;chste Aufruf dieser Prozedur erfolgt entweder, wenn der Gruppenkopf auf der folgenden Seite erneut angezeigt wird oder wenn als N&auml;chstes der Gruppenkopf f&uuml;r den folgenden Artikel angezeigt wird. Im ersten Fall stimmt die aktuelle ArtikelID mit dem in der Variablen lngArtikelID gespeicherten Wert &uuml;berein und das Feld txtFortsetzung wird mit dem Text (Fortsetzung) gef&uuml;llt. Im zweiten Fall bleibt das Textfeld wiederum leer. Das Ergebnis dieser Vorgehensweise sehen Sie in Bild 10.<\/p>\n<h2>Inventuren integrieren<\/h2>\n<p>Richtig informativ wird der Bericht aber erst, wenn auch die Inventuren und die zu dem jeweiligen Zeitpunkt vorhandenen Best&auml;nde im Bericht erscheinen. Wie aber bekommt man die Inventuren in den Bericht &#8211; die ben&ouml;tigten Daten befinden sich schlie&szlig;lich in einer ganz anderen Tabelle als die &uuml;brigen angezeigten Daten<\/p>\n<p>Hier wird es nun ein wenig trickreich. Prinzipiell gibt es zwei M&ouml;glichkeiten, die Inventurdaten wie etwa in Bild 11 in den Bericht einzupflechten:<\/p>\n<li>Integrieren der Inventurdaten mit einer weiteren UNION-Klausel in die Abfrage qryBestandsaenderungen<\/li>\n<li>Hinzuf&uuml;gen eines Feldes zu der Abfrage qryBestandsaenderungen mit dem Datum der Inventur, in der die Bestands&auml;nderung ber&uuml;cksichtigt wurde<\/li>\n<p>Die erste L&ouml;sung erreichen Sie leicht durch Hinzuf&uuml;gen des folgenden Ausdrucks zum SQL-Text der Abfrage qryBestandsaenderungen:<\/p>\n<p><IMG height=\"399\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic011.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 11:  Inventurdaten inmitten der Bestandsver&auml;nderungen<\/span><\/b><\/p>\n<pre>UNION SELECT<\/pre>\n<p><IMG height=\"268\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic012.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 12:  Bestands&auml;nderungen und Inventurdaten auf einen Blick<\/span><\/b><\/p>\n<pre>    ''0'' AS BestandsaenderungID,\r\n    tblInventuren.ArtikelID, \r\n    0 AS AnzahlMitVorzeichen, \r\n    Inventurdatum & '' 23:59'' AS Datum, \r\n    0 AS Preis,\r\n    ''Inventur'' AS Bestandsaenderungsart FROM tblInventuren<\/pre>\n<p>Die Datenblattansicht der Abfrage sieht dann wie in Bild 12 aus, die Inventur f&uuml;gt sich beinahe nahtlos in die anderen Daten ein.<\/p>\n<p>Diese Abfrage l&auml;sst sich auch hervorragend als Datenherkunft f&uuml;r einen Bericht verwenden und auch das Hervorheben der Inventurdatens&auml;tze macht mit ein wenig VBA-Einsatz keine Schwierigkeiten. Aber wenn Sie beispielsweise zu jeder Bestands&auml;nderung den aktuellen Stand ausgeben m&ouml;chten, erfordern die Inventurdatens&auml;tze jedes Mal eine Sonderbehandlung.<\/p>\n<p>Betrachten Sie die zweite M&ouml;glichkeit: Die Abfrage qryBestandsaenderungen soll in einer weiteren Abfrage so mit der Tabelle tblInventuren gekoppelt werden, dass zu jeder Bestands&auml;nderung die Inventur ermittelt werden kann, in der diese Bestands&auml;nderung ber&uuml;cksichtigt wurde.<\/p>\n<p>Bild 13 zeigt, wie das Ergebnis einer solchen Abfrage aussehen sollte. Was bringt es nun, wenn zu jeder Bestands&auml;nderung bekannt ist, mit welcher Inventur diese abgedeckt wird Ganz einfach: Sie k&ouml;nnen die Daten wie im weiter oben beschriebenen Bericht anzeigen und diese ganz einfach nach den Inventuren gruppieren. Die Integration der Inventurdaten wie Datum und Lagerbestand erfolgt dann auf herk&ouml;mmliche Weise im Gruppenfu&szlig; der Gruppierung.<\/p>\n<h3>Realisieren der Abfrage aus Bestandsver&auml;nderungen und Inventurdaten<\/h3>\n<p>Das eigentliche Problem ist die Zusammenf&uuml;hrung der Bestands&auml;nderungen und der Inventurdaten. Die Abfrage enth&auml;lt alle Felder der Abfrage qryBestandsaenderungen und der Tabelle tblInventuren, die &uuml;ber das Feld ArtikelID miteinander verkn&uuml;pft sind. Die Verkn&uuml;pfung erfolgt mittels LEFT JOIN, was in diesem Fall bedeutet, dass alle Datens&auml;tze der Abfrage qryBestandsaenderungen angezeigt werden, egal ob die Tabelle tblInventuren einen verkn&uuml;pften Datensatz enth&auml;lt.<\/p>\n<p><IMG height=\"173\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic013.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 13:  Bestands&auml;nderungen mit zugeh&ouml;rigen Inventurdaten<\/span><\/b><\/p>\n<p><IMG height=\"358\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic014.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 14:  Aufbau der Abfrage zur Verkn&uuml;pfung von Bestands&auml;nderungen und Inventurdaten<\/span><\/b><\/p>\n<p>Das ist aber noch nicht alles: Die Abfrage w&uuml;rde in dieser Form alle Kombinationen aus Bestands&auml;nderung und den f&uuml;r diesen Artikel vorgenommenen Inventuren ausgeben. Sie soll aber je Bestands&auml;nderung und Artikel nur die n&auml;chste durchgef&uuml;hrte Inventur anzeigen.<\/p>\n<p>Sie m&uuml;ssen also ein Kriterium festlegen, das daf&uuml;r sorgt, dass jede Bestands&auml;nderung mit dem Inventurdatensatz verkn&uuml;pft wird, der sich auf die gleiche ArtikelID bezieht, dessen Datum gr&ouml;&szlig;er oder gleich dem Datum der Bestands&auml;nderung ist (untere Grenze) und der gleichzeitig von allen passenden Inventurdatens&auml;tzen zuerst stattgefunden hat.<\/p>\n<p>Das alles erledigt die Abfrage aus Bild 14, deren SQL-Code aus Gr&uuml;nden der &uuml;bersichtlichkeit separat abgedruckt wird.<\/p>\n<p>Die vom Datum der Bestands&auml;nderung aus n&auml;chste Inventur wird &uuml;ber eine Unterabfrage ermittelt, die ihrerseits auf die Tabelle tblInventuren der Hauptabfrage zugreift. Die Unterabfrage ermittelt also alle Inventuren, deren Datum hinter dem der Bestands&auml;nderung liegt, sortiert diese nach dem Datum und gibt durch die TOP 1-Klausel das Inventurdatum des ersten der gefundenen Datens&auml;tze zur&uuml;ck.<\/p>\n<p>Wichtig ist, dass das Kriterium auch die Bestands&auml;nderungen ber&uuml;cksichtigt, die noch nicht per Inventur erfasst wurden &#8211; dazu dient der letzte Abschnitt OR t2.Inventurdatum Is Null:<\/p>\n<pre>SELECT t1.BestandsaenderungID,\r\n    t1.ArtikelID, t1.AnzahlMitVorzeichen,\r\n    t1.Datum, t1.Bestandsaenderungsart,\r\n    t1.Preis, t2.InventurID,\r\n    t2.Inventurdatum, t2.Lagerbestand\r\nFROM \r\n    qryBestandsaenderungen_Alternativ \r\n    AS t1 \r\nLEFT JOIN tblInventuren AS t2 \r\nON \r\n    t1.ArtikelID = t2.ArtikelID\r\nWHERE \r\n    t2.Inventurdatum=\r\n    (SELECT TOP 1 t2.Inventurdatum \r\n    FROM tblInventuren AS t2 \r\n    WHERE t2.Inventurdatum &gt;= t1.Datum \r\n    AND t2.ArtikelID = t1.ArtikelID \r\n    ORDER BY t2.Inventurdatum) \r\n    OR t2.Inventurdatum Is Null;<\/pre>\n<h3>Inventuren im Bericht<\/h3>\n<p>Um einen Bericht wie in Bild 11 zu erstellen, k&ouml;nnen Sie auf dem Bericht rptBestandsaenderungen aufbauen.<\/p>\n<p>Erstellen Sie eine Kopie dieses Berichts und speichern Sie diese unter dem Namen rptBestandsaenderungNachInventur.<\/p>\n<p>Passen Sie die Datenherkunft wie in Bild 15 an, indem Sie alle Felder der Abfrage qryBestandsaenderungenMitInventurdaten und das Feld Bezeichnung der Tabelle tblArtikel in das Entwurfsraster ziehen.<\/p>\n<p><IMG height=\"317\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic015.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 15:  Einstellen der Datenherkunft des Berichts zur Anzeige von Bestands&auml;nderungen und Inventurdaten<\/span><\/b><\/p>\n<p><IMG height=\"390\" src=\"..\/fileadmin\/_temp_\/{2B76EF29-7E90-4100-9FFA-555D048C5BA7}\/pic016.png\" width=\"500\" border=\"0\"><\/p>\n<p><b><\/b><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 16:  Bericht mit Bestands&auml;nderungen und Inventuren<\/span><\/b><\/p>\n<p>Nun fehlen nur noch die Anpassungen im Berichts selbst: Stellen Sie zun&auml;chst die Sortierungen und Gruppierungen wie in Bild 16 ein und f&uuml;gen Sie im neuen Fu&szlig;bereich f&uuml;r die Gruppierung nach der InventurID die entsprechenden Steuerelemente hinzu. Neben den Feldern Inventurdatum und Lagerbestand f&uuml;gen Sie auch das Feld InventurID hinzu, stellen die Sichtbarkeit allerdings auf Nein ein.<\/p>\n<p>Das Feld InventurID ben&ouml;tigen Sie, um den Gruppenfu&szlig; auszublenden, wenn die Gruppierung die Bestands&auml;nderungen eines Artikels umfasst, die noch nicht per Inventur erfasst wurden. Dazu f&uuml;gen Sie f&uuml;r die Ereigniseigenschaft Beim Formatieren dieses Bereichs die Prozedur aus Quellcode 10 hinzu.<\/p>\n<pre>Private Sub Gruppenfu&szlig;0_Format(Cancel _    As Integer, FormatCount As Integer)\r\n    If Nz(Me.InventurID, 0) = 0 Then\r\n        Me.Gruppenfu&szlig;0.Visible = False\r\n    Else\r\n        Me.Gruppenfu&szlig;0.Visible = True\r\n    End If\r\nEnd Sub<\/pre>\n<p><b>Quellcode 10<\/b><\/p>\n<h2>Anzeige von Artikeldaten per Bericht<\/h2>\n<p>Die L&ouml;sung enth&auml;lt noch einen weiteren Bericht zur Anzeige eines Artikeldatenblatts. Dieser Bericht beinhaltet keine nennenswerten Besonderheiten mit Ausnahme der bereits im Formular frmArtikel verwendeten Technik zum Anzeigen einer in der Datenbank als Bin&auml;rstrom gespeicherten Datei.<\/p>\n<p>Sie haben in diesem Beitrag erfahren, wie Sie Inventurvorg&auml;nge mit einer Access-Datenbankanwendung abbilden k&ouml;nnen und die Artikelverwaltung aus dem ersten Teil der Beitragsreihe um einige Funktionen erweitern. In Abh&auml;ngigkeit von der jeweiligen Aufgabenstellung funktioniert das nicht immer ohne Tricks und Kniffe, wie sich beim Gruppieren des Berichts nach den Inventurdaten gezeigt hat.<\/p>\n<p>In den folgenden Ausgaben von Access im Unternehmen werden Sie Anwendungen rund um die Artikelverwaltung hinzuf&uuml;gen &#8211; beispielsweise eine Bestellverwaltung oder eine Kundenverwaltung. Dabei wird sicher auch die Artikelverwaltung weiter ausgebaut.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im ersten Teil dieser Beitragsreihe haben Sie das Datenmodell und die wesentlichen Formulare der Artikelverwaltung kennen gelernt. Nun besch&auml;ftigen Sie sich mit den Inventuren: Welche Faktoren sind daf&uuml;r wichtig Wie werden bereits in einer Inventur ber&uuml;cksichtigte Daten bei folgenden Inventuren ausgeschlossen Au&szlig;erdem erfahren Sie in dieser Folge, wie Sie Berichte f&uuml;r die Ausgabe von Artikel- und Inventurdaten erstellen.<\/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":[662005,66032005,44000027],"tags":[],"class_list":["post-55000280","post","type-post","status-publish","format-standard","hentry","category-662005","category-66032005","category-Loesungen"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Artikelverwaltung, Teil 2 - 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\/Artikelverwaltung_Teil_2\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Artikelverwaltung, Teil 2\" \/>\n<meta property=\"og:description\" content=\"Im ersten Teil dieser Beitragsreihe haben Sie das Datenmodell und die wesentlichen Formulare der Artikelverwaltung kennen gelernt. Nun besch&auml;ftigen Sie sich mit den Inventuren: Welche Faktoren sind daf&uuml;r wichtig Wie werden bereits in einer Inventur ber&uuml;cksichtigte Daten bei folgenden Inventuren ausgeschlossen Au&szlig;erdem erfahren Sie in dieser Folge, wie Sie Berichte f&uuml;r die Ausgabe von Artikel- und Inventurdaten erstellen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-06T15:18:01+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg03.met.vgwort.de\/na\/0156e3af372a426e8183da5c9746fd93\" \/>\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\\\/Artikelverwaltung_Teil_2\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Artikelverwaltung, Teil 2\",\"datePublished\":\"2020-05-06T15:18:01+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/\"},\"wordCount\":4076,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg03.met.vgwort.de\\\/na\\\/0156e3af372a426e8183da5c9746fd93\",\"articleSection\":[\"2005\",\"3\\\/2005\",\"L\u00f6sungen\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/\",\"name\":\"Artikelverwaltung, Teil 2 - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg03.met.vgwort.de\\\/na\\\/0156e3af372a426e8183da5c9746fd93\",\"datePublished\":\"2020-05-06T15:18:01+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg03.met.vgwort.de\\\/na\\\/0156e3af372a426e8183da5c9746fd93\",\"contentUrl\":\"http:\\\/\\\/vg03.met.vgwort.de\\\/na\\\/0156e3af372a426e8183da5c9746fd93\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Artikelverwaltung_Teil_2\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Artikelverwaltung, Teil 2\"}]},{\"@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":"Artikelverwaltung, Teil 2 - 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\/Artikelverwaltung_Teil_2\/","og_locale":"de_DE","og_type":"article","og_title":"Artikelverwaltung, Teil 2","og_description":"Im ersten Teil dieser Beitragsreihe haben Sie das Datenmodell und die wesentlichen Formulare der Artikelverwaltung kennen gelernt. Nun besch&auml;ftigen Sie sich mit den Inventuren: Welche Faktoren sind daf&uuml;r wichtig Wie werden bereits in einer Inventur ber&uuml;cksichtigte Daten bei folgenden Inventuren ausgeschlossen Au&szlig;erdem erfahren Sie in dieser Folge, wie Sie Berichte f&uuml;r die Ausgabe von Artikel- und Inventurdaten erstellen.","og_url":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-06T15:18:01+00:00","og_image":[{"url":"http:\/\/vg03.met.vgwort.de\/na\/0156e3af372a426e8183da5c9746fd93","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\/Artikelverwaltung_Teil_2\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Artikelverwaltung, Teil 2","datePublished":"2020-05-06T15:18:01+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/"},"wordCount":4076,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/#primaryimage"},"thumbnailUrl":"http:\/\/vg03.met.vgwort.de\/na\/0156e3af372a426e8183da5c9746fd93","articleSection":["2005","3\/2005","L\u00f6sungen"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/","url":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/","name":"Artikelverwaltung, Teil 2 - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/#primaryimage"},"thumbnailUrl":"http:\/\/vg03.met.vgwort.de\/na\/0156e3af372a426e8183da5c9746fd93","datePublished":"2020-05-06T15:18:01+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/#primaryimage","url":"http:\/\/vg03.met.vgwort.de\/na\/0156e3af372a426e8183da5c9746fd93","contentUrl":"http:\/\/vg03.met.vgwort.de\/na\/0156e3af372a426e8183da5c9746fd93"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Artikelverwaltung_Teil_2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Artikelverwaltung, Teil 2"}]},{"@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\/55000280","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=55000280"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000280\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55000280"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55000280"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55000280"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}