VBA Programmierung für spezielle Aufgabe möglich?

rhodium

Cadet 3rd Year
Dabei seit
Feb. 2013
Beiträge
50
Hey...

Ich habe VBA noch nie benutzt und kenne mich daher nicht aus. Ich benötige es nun aber für ein Makro in Excel. Allerdings weiß ich aufgrund meiner nicht vorhandenen Kenntnisse über VBA nicht, ob es (bzw. was) überhaupt möglich ist.
Bevor ich mich jetzt aufwendig mit VBA beschäftige (Habe eine Zeitbeschränkung), möchte ich fragen, ob mein Vorhaben überhaupt möglich ist.

Grundsätzlich kann ich aber mit Excel umgehen. Auch programmiert habe ich schon (MatLab). Ich besitze also ein paar Kenntnisse.


Nun zu meiner Aufgabe und meinen Fragen dazu:
Geht das mit VBA? Wie viel Aufwand (Zeit, Kenntnisse) ist notwendig?

Ausgangsdaten
Aus einer Applikation (aus dem Internet) exportiere ich manuell eine .csv Datei bzw. speichere sie beim Export direkt als .xlsx.
Darin enthalten ist eine Auflistung mit Spalten A - AJ und einer variablen Anzahl an Zeilen. In der ersten Zeile stehen die Überschriften der Spalten. Die Datei enthält keine Formatierung.

Aus der Datei möchte ich bestimmte Zeilen anhand der Spaltenüberschriften herausfiltern.
Diese Zeilen möchte anhand einer vorhanden Spalte (Datum) mit dem aktuellen Datum abgleichen.
Bei einer bestimmten Differenz (mehrere) sollen E-Mails mit Outlook generiert werden.
In den E-Mails wird vordefinierter Text enthalten sein und Daten aus der dazugehörigen Zeile der exportierten Datei.
Diese E-Mails sollen dann natürlich auch abgeschickt werden. Der Empfänger müsste anhand einer im Makro hinterlegten Liste (oder besser in ein einer Excel, sodass Änderungen an der Liste leichter sind) mit einer Spalte aus der Datei abgeglichen und bestimmt werden.

Ja, das erst mal grob.

Ansonsten:
Ich könnte mir auch vorstellen, dass ich eine separate Excel-Datei aufbaue, in der ich das Makro ausführe. Nur die herausgefilterten Zeilen (nicht alle Spalten) möchte ich dann in diese Excel einlesen und die Spalten sinnvoll anordnen. Dazu müsste ich natürlich die exportierte Datei erst speichern ... ich vermute immer mit dem gleichen Dateinamen, was aber kein Problem darstellt, da die alte Datei dann nicht weiter benötigt wird.
Weiterhin wäre vielleicht eine neue Spalte gut, in der zB ein Eintrag oder ein Haken generiert wird, der dann anzeigt, dass eine E-Mail erzeugt und geschickt wurde.


Schon mal Danke.
 
Zuletzt bearbeitet:
M

miac

Gast
Ja, das geht.

Der Aufwand hängt von deinen Kenntnissen ab. Aber eigentlich brauchst Du lediglich das Objektmodell von Excel und Outlook.

Daten aus dem Internet sind eigentlich immer irgendwie formatiert auslesbar.
 

rhodium

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Feb. 2013
Beiträge
50
Der Aufwand hängt von deinen Kenntnissen ab. Aber eigentlich brauchst Du lediglich das Objektmodell von Excel und Outlook.
Sagen wir mal, dass die Kenntnisse eher gering sind. Was denkst du wie viel Zeit (reiner Programmieraufwand) nötig ist?


Daten aus dem Internet sind eigentlich immer irgendwie formatiert auslesbar.
Die Applikation hat eine Exportfunktion, die eine Datei ohne Formatierung ausgibt. Ich möchte nicht den Internetexplorer auslesen, falls du daran denkst ?!



Gibt es hier im Forum eine simple Einführung in VBA? Habe ein Buch über Excel und auch was im Internet gefunden, aber das ist alles so lang...
Ein paar Kenntnisse habe ich ja...
 
M

miac

Gast
Wie das beim PRogrammieren so ist, kannst Du schnell mal an einem Problem mit Debuggen hängen. Dann kann das Tage dauern.

Ein Tutorial ist z.B. hier: http://www.vba-tutorial.de/index.htm

Mit Formatierung dachte ich, Du meinst den Aufbau der Datei. Es scheint aber schon komplett in Zellen einlesbar zu sein, also entfällt das dann wohl.

Bedenke, daß Du am besten die Import Funktion von Excel verwendest und nicht einfach die Dateiendung umbenennst. Denn damit bekommst Du keine Excel Datei.
 

Piktogramm

Vice Admiral
Dabei seit
Okt. 2008
Beiträge
6.156
Ohne Formatierung wäre die Datei nicht lesbar. Wenn du eine csv ausleiten kannst, dann wird diese klar formatiert sein. Zum Beispiel indem Feldtrenner als , oder ; definiert sind und jede Zeile/datensatz durch ein \r\n am Ende gekennzeichnet ist.

Das was du machen willst ist wie so oft etwas was mit Excel geht, typischerweise wird sowas aber dennoch in Datenbanksystemen abgewickelt. Beispielsweise Microsoft Access. Ein bisschen SQL und etwas Googln sollte schnell zum Ergebnis führen.
 

Alchemist

Lieutenant
Dabei seit
Juni 2009
Beiträge
753
Hallo,

eigentlich ist das ganze nicht besonders schwer und auch ein perfekter Anwendungsfall für ein Makro.
Aus Matlab solltest du ja Grundkenntnisse mitbrigen, in VBA geht es eigentlich genauso.
Ich würde empfehlen eine eigene Excel Datei anzufertigen, in der das Makro liegt. Aus dieser heraus kannst du dann etwa die folgende Struktur verwenden:
Datendatei öffnen (Stichwort fileopen dialog: http://stackoverflow.com/questions/25153342/open-a-workbook-using-filedialog-and-manipulate-it-in-excel-vba) dabei kannst du der Datendatei gleich eine variable zuweisen um später einfacher draufzugreifen zu können.
Daten suchen (for schleife)
Eventuell macht es an dieser Stelle Sinn, die Daten, die später per Mail verschickt werden in ein neues Tabellenblatt zu kopieren, dann kannst du sie beim Testen auch einfacher kontrollieren.
Email Objekte anlegen
Daten einfüllen
Mail verschicken
Status in Tabelle schreiben

Es ist sicher ratsam die einzelnen Abschnitte des Programms in Proceduren auszulagern, macht sich beim Testen einfach besser.

Im VBA Bereich gibt es auch wirklich keine Frage, die noch nicht in einem online Forum gestellt wurde.

Zwei Zeilen noch, die ich sehr praktisch finde, diese kommen einfach am Anfang ins Makro:
Application.Calculation = xlManual
Application.ScreenUpdating = False
Beide machen, wonach es klingt, die erste Anweisung setzt die Autocalculation auf manuell (wenn du keine Formeln im Dokument hast, eher nicht notwendig). Die zweite schaltet die Ansichtsaktualisierung aus. Nach meiner Erfahrung reduziert dies die Rechenzeit teils deutlich. Am Ende einfach wieder auf true setzten und gut ist.
 

Janush

Lt. Junior Grade
Dabei seit
Mai 2008
Beiträge
478
VBA eigenet sich super für deine Aufgabe. Wenn du weißt was du tust, ist das an einem Abend programmiert. Wenn du keine Ahnung von VBA hast dauerts evtl. ne Woche. Je nach dem wieviel zeit du zum googeln hast :-)

Ist das etwas das regelmäßig gebraucht wird?
 

rhodium

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Feb. 2013
Beiträge
50
Danke.


Mit Formatierung dachte ich, Du meinst den Aufbau der Datei. Es scheint aber schon komplett in Zellen einlesbar zu sein, also entfällt das dann wohl.
Ohne Formatierung wäre die Datei nicht lesbar. Wenn du eine csv ausleiten kannst, dann wird diese klar formatiert sein. Zum Beispiel indem Feldtrenner als , oder ; definiert sind und jede Zeile/datensatz durch ein \r\n am Ende gekennzeichnet ist.
Ok, formatiert heißt wohl etwas anderes, als ich dachte.
Ja, die Datei ist so aufgebaut, dass pro Zelle ein Wert (Text oder Zahl) vorhanden ist. Das ganze ist dann entsprechen in Spalten und Zeilen aufgeteilt.

Es ist nicht so, dass alles in einer Zelle steht und durch ; getrennt ist.


Bedenke, daß Du am besten die Import Funktion von Excel verwendest und nicht einfach die Dateiendung umbenennst. Denn damit bekommst Du keine Excel Datei.
Was passiert denn, wenn ich die .csv Datei mit Excel öffne und das ganze dann als .xlsx abspeicher? So habe ich das bisher gemacht. Ich konnte dann mit der .xlsx Datei ganz normal arbeiten. Pivot-Tabellen erstellen, Formel nutzen ... .




Das was du machen willst ist wie so oft etwas was mit Excel geht, typischerweise wird sowas aber dennoch in Datenbanksystemen abgewickelt. Beispielsweise Microsoft Access. Ein bisschen SQL und etwas Googln sollte schnell zum Ergebnis führen.
Von Access habe ich gar keine ahnung und das Programm kommt aber auch nicht in Frage, da es nicht vorhanden ist.
Danke trotzdem.



Hallo,

eigentlich ist das ganze nicht besonders schwer und auch ein perfekter Anwendungsfall für ein Makro.
Aus Matlab solltest du ja Grundkenntnisse mitbrigen, in VBA geht es eigentlich genauso.
Ich würde empfehlen eine eigene Excel Datei anzufertigen, in der das Makro liegt. Aus dieser heraus kannst du dann etwa die folgende Struktur verwenden:
Datendatei öffnen (Stichwort fileopen dialog: http://stackoverflow.com/questions/25153342/open-a-workbook-using-filedialog-and-manipulate-it-in-excel-vba) dabei kannst du der Datendatei gleich eine variable zuweisen um später einfacher draufzugreifen zu können.
Daten suchen (for schleife)
Eventuell macht es an dieser Stelle Sinn, die Daten, die später per Mail verschickt werden in ein neues Tabellenblatt zu kopieren, dann kannst du sie beim Testen auch einfacher kontrollieren.
Email Objekte anlegen
Daten einfüllen
Mail verschicken
Status in Tabelle schreiben

Es ist sicher ratsam die einzelnen Abschnitte des Programms in Proceduren auszulagern, macht sich beim Testen einfach besser.
Das hilft mir auf jeden Fall schon mal weiter, da ich bisher nicht einmal eine Idee hatte, wie man am sinnvollsten da ran geht.
Danke!
Habe auch schon ein bisschen was über VBA gelesen... aber das waren bisher nur Grundlagen/Erklärungen zu irgendwelchen Dingen, unter denen ich mir bisher nichts vorstellen konnte.

Im VBA Bereich gibt es auch wirklich keine Frage, die noch nicht in einem online Forum gestellt wurde.

Zwei Zeilen noch, die ich sehr praktisch finde, diese kommen einfach am Anfang ins Makro:
Application.Calculation = xlManual
Application.ScreenUpdating = False
Beide machen, wonach es klingt, die erste Anweisung setzt die Autocalculation auf manuell (wenn du keine Formeln im Dokument hast, eher nicht notwendig). Die zweite schaltet die Ansichtsaktualisierung aus. Nach meiner Erfahrung reduziert dies die Rechenzeit teils deutlich. Am Ende einfach wieder auf true setzten und gut ist.
Danke.

Ist das etwas das regelmäßig gebraucht wird?
Ja, es soll regelmäßig genutzt werden.


Könnte ihr mir eine Seite nennen, wo diverse Befehle aufgelistet und auch auffindbar sind.
Bsp: Ich suche jetzt den Befehl nach einer Zelle, die etwas bestimmtes enthält. Dann wäre es super, diesen Befehl schnell zu finden.
 
M

miac

Gast
Wenn Du die Import Funktion benutzt, kannst Du z.B. auf Zahlen und Datumsangaben korrekt reagieren.
 

rhodium

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Feb. 2013
Beiträge
50
Hey.

Also ich habe mittlerweile vieles mit Excel und VBA gelöst. Leider aber nicht alles. Ich bräuchte noch eine Idee/einen Vorschlag von euch...

Ich habe jetzt eine Excel-Datei mit einem Sheet, das die gesamte Liste an relevanten Daten enthält - wird per Makro eingelesen, sortiert, ... (Überschriften in Zeile 1, Mehrere Zeilen variabler Anzahl mit Daten, Spalten A-AJ).

Nun möchte ich für alle Einträge (Zeilen), deren Termin (Spalte W) in der Vergangenheit liegt (also "< date" ist), eine E-Mail erstellen
und
zusätzlich Teile (bestimmte Spalten: A,B,C,D,E,G,M,W,AH,AI,AJ) des Eintrages (der Zeile), für den eine E-Mail verschickt wurde, in ein neues Sheet ("Uebersicht") kopieren (ohne leere Spalten dazwischen) und dort noch eine extra Spalte hinten anfügen, in die dann das Datum der Erstellung der E-Mail eingetragen wird (als Bestätigung/Notiz, dass eben eine erstellt wurde, ggf. noch ein Haken oder so).


Ein Makro für die E-Mail Erstellung habe ich schon - funktioniert auch (falls das hilft):
Variablen, die vorkommen, aber nicht definiert sind, sind an anderer Stelle mit Public definiert.

Macht es z.B. Sinn, die Prüfung, ob Datum in Spalte W < date in ein anderes Sub zu schreiben. Dort eine Schleife einzubauen, die jede Zeile durch geht und immer dann, wenn die Bedingung wahr ist, das/der/die (?) Sub EMailErstellungErinnerung auszuführen und dann noch das/der/die (?) Sub zum Kopieren der o.g. Spalten reinzuschreiben?
Gibt's elegantere Lösungen?
Wie kann ich die Prüfung und das Kopieren programmieren?

Danke.


Sub EMailErstellenErinnerung()

Dim MailInhalt As Object
Dim NewMail As Object
Dim AWS As String

Dim TxErinnerung1 As String
[...]
x1 = Worksheets(NeuerTabellenname).Range("A1")
[...]
TxErinnerung1 = Worksheets("Mail-Textvorlagen").Range("A2")
[...]

'Outlook Object erstellen
Set NewMail = CreateObject("Outlook.Application")

'Outlook Nachricht erstellen
Set MailInhalt = NewMail.CreateItem(0)
With MailInhalt
'Empfänger
.To = "Max.Mustermann@xxx" ' Muss noch variabel gemacht werden
'Betreff
.Subject = "Erinnerung - " & x1
' .Attachments.Add AWS
'Text erstellen
.Body = TxErinnerung1 & " " & x1 & " " & TxErinnerung2 & Chr(10) & Chr(10) & _
"Daten:" & Chr(10) & _
"Nr: " & x1 & Chr(10) & "Name: " & x2 & Chr(10) & "Info: " & x3 & Chr(10) & _
"Ort: " & x4 & Chr(10) & "PLZ: " & x5
'Anzeigen der E-Mail
.Display
' Mail senden
' .Send
End With
'Outlook schliessen
'NewMail.Quit
'Variablen leeren
Set NewMail = Nothing
Set MailInhalt = Nothing
End Sub
 

Alchemist

Lieutenant
Dabei seit
Juni 2009
Beiträge
753
Ich würde es in etwa so machen:
Code:
Sub CopyData()
Dim sourcetable As Worksheet
Dim targettable As Worksheet
Dim emailSent As Boolean
Set sourcetable = ActiveSheet   'anpassen'
Set targettable = ActiveSheet   'Anpassen'
For i = 1 To sourcetable.Cells(Rows.Count, "A").End(xlUp).Row 'Iterate rows'
    If sourcetable.Range("W" & i) < Date Then
        targettable.Cells(i, 1) = sourcetable.Range("A" & i) ' Vorne: Spalte anpassen, hinten: Zeile für alle wiederholen: A,B,C,D,E,G,M,W,AH,AI,AJ'
        targettable.Cells(i, 2) = sourcetable.Range("B" & i)
        '...'
        emailSent = EMailErstellenErinnerung()
        If emailSent Then targettable.Cells(i, 10) = "Erfolgreich Email versendet am: " & Date
    End If
Next i
End Sub


Function EMailErstellenErinnerung() As Boolean
'Dein Code HIER'
EMailErstellenErinnerung = True 'wenn erfolgreich'
End Function
Ich würde daher die Email Sub als Function umschreiben, am Code ändert sich nichts, nur der Kopf ist anders und am Ende muss der return Wert erstellt werden.
Frage: wird für jede Zeile eine extra Email versendet? Wenn ja geht es so, wenn nicht muss man das natürlich noch zusammenfassen... das ist dann etwas extra Aufwand.
 
Zuletzt bearbeitet:

rhodium

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Feb. 2013
Beiträge
50
Ich würde es in etwa so machen:

Ich würde daher die Email Sub als Function umschreiben, am Code ändert sich nichts, nur der Kopf ist anders und am Ende muss der return Wert erstellt werden.
Frage: wird für jede Zeile eine extra Email versendet? Wenn ja geht es so, wenn nicht muss man das natürlich noch zusammenfassen... das ist dann etwas extra Aufwand.
Vielen Dank schon mal. Das sieht sehr gut aus und ich kann sogar alles nachvollziehen. Ich teste es mal.

Ja, es soll für jede Zeile eine E-Mail erstellt werden.

Eine Frage habe ich aber noch: Ich werde wohl die Abfrage nach dem Datum noch etwas genauer ausführen. Wie ist der Befehl dafür, wenn ich nicht wissen will ob das Datum W einfach nur kleiner ist, sondern wenn ich wissen will, ob dazwischen mehr als 7 Tage liegen?

Also sowas wie
If Differenz zwischen sourcetable.Range("W" & i) und Date > 0 And [...] <7
 
Zuletzt bearbeitet:

Alchemist

Lieutenant
Dabei seit
Juni 2009
Beiträge
753
Date liefert dir das heutige Datum zurück. Du kannst also auch einfach Date - 7 nehmen, um zu gucken ob der Eintrag länger als 7 Tage in der Vergangenheit liegt.
Nachtrag: Das Äquivalent in einer normalen Formel ist "Heute()", damit kannst du zB gut testen, welchen Wert dir Heute()-365 etc liefert.
 

rhodium

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Feb. 2013
Beiträge
50
Weitere Fragen:

"Sourcetable" ist ja das Ausgangssheet mit den Daten. Ich lege im vorhinein dieses Sheet durch ein Makro automatisch neu an und lasse den Namen des Sheets durch Benutzereingabe bestimmen. Heißt in dem Fall "NeuerTabellenName". Ist irgendwo daher mal definiert als String.

Jetzt definierst du Sourcetable als Worksheet? Wie gehe ich damit um?
 

Alchemist

Lieutenant
Dabei seit
Juni 2009
Beiträge
753
Hier müssen wir mit den Begriffen ein bisschen aufpassen: Worksheets sind deine Tabellenblätter in einem Workbook. Also Worksheets sind diese "Tabelle 1", "Tabelle 2" etc in einer Datei.
Das Workbook ist die ganze Datei zb. "Mappe 1"

Wenn du die Quelldatei sowieso schon benannt hast, kannst du auch gerne damit weiterarbeiten. Vielleicht kannst du mal deine Deklaration hier posten?

Ansonsten zB so:
Set sourcetable = Workbooks("Mappe1").Worksheets(1)

Statt "Mappe 1" also der Name der Datei, wenn es eine andere ist, als die in der das Makro liegt
oder den Index in Worksheets(1) anpassen auf den Namen. Worksheet(1) und Worksheet("Tabelle1") sind äquivalent und bezeichnen dasselbe Tabellenblatt.

EDIT: Lesen hilft... :o Sorry.
Du hast es ja oben schon mal stehen, dann ist das ganz einfach
Set sourcetable = Worksheets(NeuerTabellenname)
 
Zuletzt bearbeitet:

rhodium

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Feb. 2013
Beiträge
50
Die Excel-Datei heißt Erinnerung.
Der Name des Sheets mit den Daten wird durch den Benutzer in die Variable NeuerTabellenName geschrieben
(Public NeuerTabellenName As String)

Also - ?:
Set Sourcetable = Workbooks("Erinnerung.xlsm").Worksheets(NeuerTabellenName)
Set Targettable = Workbooks("Erinnerung.xlsm").Worksheets("Uebersicht")
Ergänzung ()

Ah ok. Also ohne "Workbooks"?

(Ist ein bissl blöd, dass die Seite sich nicht von selbst aktualisiert :-D )
 

Alchemist

Lieutenant
Dabei seit
Juni 2009
Beiträge
753

Alchemist

Lieutenant
Dabei seit
Juni 2009
Beiträge
753
Die Iterationsvariable i hat mit der Funktion EMailErstellenErinnerung nicht viel zu tun.
In Worten passiert folgendes:
Code:
Für i = erste Zeile bis letzte Zeile do
   Wenn Bedingung erfüllt, dann
        Kopiere Daten
        Rufe EMailErstellenErinnerung auf und speichere Rückgabewert in emailSent
        Wenn emailSent= true (also erfolgreich) dann schreibe Eintrag in Tabelle, dass Mail verschickt wurde.
   Ende Wenn
Nächste Zeile
Die Funktion EMailErstellenErinnerung wird also für jede gefundene Zeile aufgerufen, die die Bedingung erfüllt.
In EMailErstellenErinnerung musst du dann keine Schleife mehr haben, die alle Zeilen durchgeht, das wäre ja schon in der CopyData Methode erledigt.

Ich kenne halt den Rest des Programmes nicht, daher kann es natürlich sein, dass es nicht zum Rest bei dir passt.
Wenn du die Zeile übernehmen willst, kannst du sie als Parameter übergeben:
Code:
Aufruf:
emailSent = EMailErstellenErinnerung(i)

Funktion:
Function EMailErstellenErinnerung(Zeile As Integer) As Boolean
 
Zuletzt bearbeitet:
Top