2017-01-24 10 views
1

Ich versuche, bestimmte Funktionen in einer Excel-Datei zu automatisieren.Füllen Zellen basierend auf anderen Tabelle

Hier ist mein Problem:

simplified example

Tabelle 1 eine Zeichenfolge enthält, ist Spalte "Info", gefolgt von zwei leeren Zellen. Für jede der Zeilen in Tabelle 1 möchte ich prüfen, ob ein Wert von Tabelle 2, Spalte "Frucht" in Spalte "Info" von Tabelle 1 vorhanden ist. Wenn ja, möchte ich die "Farbe" und "Preis" ausfüllen Tabelle 2 in den leeren Zellen in Tabelle 1.

Zum Beispiel enthält die zweite Zeile das Wort "Bananen", was bedeutet, dass "Farbe" "Gelb" und "Preis" "15" in demselben gefüllt sein sollte Spalten in Tabelle 1, Zeile 2.

Irgendwie erscheint mir dieses Problem so einfach, aber wenn ich darüber nachdenke, wie ich das umsetzen kann, bleibe ich stecken. Leider habe ich keinen verfügbaren Code zur Verfügung. Ich hoffe nur, dass dieses Thema nicht zu vage ist.

Ich habe auch versucht, dieses Problem mit Formeln, mit MATCH und INDEX zu lösen, aber ich konnte das auch nicht funktionieren.

+0

Nur ein kleiner Hinweis -> warum versuchst du es nicht ein bisschen einfacher zu machen und es dann komplizierter zu machen? Z.B. für "Äpfel" statt "Dies ist eine Zeile über Äpfel". Dort können Sie leicht einen Index (Match; Match) verwenden. – Vityata

+0

Danke für Ihren Kommentar. Ich stimme deinem Standpunkt zu. Aber dieses Beispiel war nur eine vereinfachte Version eines komplizierteren Blattes. Das Originalblatt enthält viel mehr Zeilen und der Wert in der Spalte "info" ist viel komplizierter. Eine Substitution dieser Werte ist also keine Option. EDIT: Nebenbei, diese Werte mit VBA ersetzen würde erfordern ein ähnliches Skript. ;) –

Antwort

0

Hier ist eine Funktion, die die Zeile im ListObject (Tabelle) zurückgibt, wo das erste passende Wort gefunden wird.

Public Function MatchFruit(ByVal sInfo As String, ByRef rFruit As Range) As Long 

    Dim vaSplit As Variant 
    Dim i As Long, j As Long 
    Dim rFound As Range 
    Dim sWhat As String 

    vaSplit = Split(sInfo, Space(1)) 

    For i = LBound(vaSplit) To UBound(vaSplit) 
     'strip out non-alpha characters 
     sWhat = vbNullString 
     For j = 1 To Len(vaSplit(i)) 
      If Asc(Mid(LCase(vaSplit(i)), j, 1)) >= 97 And Asc(Mid(LCase(vaSplit(i)), j, 1)) <= 122 Then 
       sWhat = sWhat & Mid(vaSplit(i), j, 1) 
      End If 
     Next j 

     'find the word in the range 
     Set rFound = Nothing 
     Set rFound = rFruit.Find(sWhat, , xlValues, xlWhole, , , False) 
     If Not rFound Is Nothing Then 'if it's found 
      'return the row in the ListObject 
      MatchFruit = rFound.Row - rFruit.ListObject.HeaderRowRange.Row 
      'stop looking 
      Exit For 
     End If 
    Next i 

End Function 

Angenommen, Ihre erste Tabelle ist tblData und Ihre zweite Tabelle tblFruit genannt, würden Sie die Farbe erhalten mit

=INDEX(tblFruit[Color],MatchFruit([@Info],tblFruit[Fruit])) 

und der Preis ähnlich

=INDEX(tblFruit[Price],MatchFruit([@Info],tblFruit[Fruit])) 

lange Erklärung

DieDie-Zuweisungszeile verwendet die Split-Funktion, um eine Zeichenfolge basierend auf einem Begrenzer in ein Array zu konvertieren. Da Ihre Beispieldaten Sätze waren, ist das normale Trennzeichen ein Leerzeichen, um es in Wörter zu teilen. Eine Zeichenfolge wie

This is some line about apples. 

in ein Array umgewandelt wird

vaSplit(1) This 
vaSplit(2) is  
vaSplit(3) some 
vaSplit(4) line 
vaSplit(5) about 
vaSplit(6) apples. 

Als nächstes wird die For Schleife geht in der Anordnung jedes Element durch, um zu sehen, ob es in der anderen Liste nicht finden kann. Die Funktionen LBound und Ubound (untere und obere Grenze) werden verwendet, da wir nicht sicher sein können, wie viele Elemente das Array haben wird.

Die erste Operation in der Schleife besteht darin, alle überflüssigen Zeichen zu entfernen. Dazu erstellen wir die Variable sWhat und setzen sie auf nichts. Dann durchlaufen wir alle Zeichen im Element, um zu sehen, ob sie außerhalb des Bereichs a...z liegen. Im Grunde wird alles, was ein Buchstabe ist, an sWhat angehängt und alles was nicht ist (eine Zahl, ein Leerzeichen, ein Punkt) tut es nicht. Am Ende sWhat ist das gleiche wie das aktuelle Element mit allen Nicht-Alpha-Zeichen entfernt. In diesem Beispiel würden wir wegen des Zeitraums nie übereinstimmen, also ist es abgestreift.

Sobald wir eine gute sWhat haben, verwenden wir jetzt die Find Methode, um zu sehen, ob dieses Wort im rFruit Bereich existiert. Wenn dies der Fall ist, wird rFound nicht Nothing sein und wir gehen voran.

Beachten Sie, dass rFound ist und die Funktion null zurückgibt, wenn es das Wort in dem Bereich nicht findet.

Wenn das Wort gefunden wird, gibt die Funktion die Zeile zurück, in der sie gefunden wurde, in der Zeile, in der ListObject beginnt. Auf diese Weise gibt die Funktion die Zeile mit den Daten des ListObject nicht auf dem Arbeitsblatt zurück. Dies ist nützlich, wenn Sie in eine INDEX Formel einbeziehen. Um einer Formel etwas zurückzugeben, weisen Sie dem Namen der Formel etwas zu.

Schließlich hört die Exit For Zeile einfach auf, durch das Array zu suchen, sobald eine Übereinstimmung gefunden wurde. Wenn Ihre Daten mehr als eine Übereinstimmung aufweisen, wird nur die erste zurückgegeben.

Fehlerbehebung

Der wahrscheinlichste Fehler, die Sie finden, ist, dass die Funktion Null zurück, wenn Sie es erwarten eine Zeilennummer zurück. Das bedeutet höchstwahrscheinlich, dass es keine Wörter in der Liste gefunden hat.

Wenn Sie sicher sind, dass beide Listen ein passendes Wort enthalten, gehen Sie folgendermaßen vor: Geben Sie nach der Set rFound = Zeile eine Debug.Print Anweisung ein.

 Set rFound = rFruit.Find(sWhat, , xlValues, xlWhole, , , False) 
     Debug.Print "." & sWhat & "." 
     If Not rFound Is Nothing Then 'if it's found 

Die sWhat zu dem Direkt-Fenstern (Strg + G im VBE die Direkt-Fenster zu sehen) gedruckt wird. Die Perioden um das Wort sind so, dass Sie nicht druckbare Zeichen (wie Leerzeichen) sehen können. Wenn Sie versuchen, .pears . mit pears in Übereinstimmung zu bringen, wird es nicht passen, weil das erste ein Leerzeichen am Ende hat - und Sie können das sehen, weil wir Perioden vorher und nachher feststeckten. Wenn Leerzeichen ein Problem darstellen, können Sie die Trim$() Funktion auf sWhat zuerst loswerden.

Mit dieser Debug.Print Aussage, könnten Sie Ergebnisse sehen wie

.paers. 

in diesem Fall würde erkennen, dass Sie einen Tippfehler haben.

+0

Danke Dick. Das hat definitiv funktioniert. Obwohl ich noch nicht sicher bin, wie und warum es funktioniert. Aber ich werde meine Zähne darin versenken und versuchen, es herauszufinden. Wenn ich richtig bin, muss ich auf diese Weise die Formeln noch manuell in die leeren Zellen eingeben, was bei der Aktualisierung der Datei sicherlich für mich funktioniert. Aber ist es möglich, dies noch weiter zu automatisieren? –

+0

Entschuldigung dafür, ein n00b zu sein. Obwohl es für meine Beispieltabellen gut funktioniert, verstehe ich nicht wirklich, was die Funktion macht und wenn ich versuche, die Funktion an mein tatsächliches Blatt anzupassen, funktioniert es nicht. Könntest du mich vielleicht etwas durch die Funktion sprechen? –

+0

OK. Ich komme ein bisschen weiter. Ich habe mir gedacht, warum die Funktion fehlgeschlagen ist. 'vaSplit = Split (sInfo, Space (1))' zerlegte die Zeichenkette an jedem _space_. In meinem Blatt sollte die Zeichenfolge tatsächlich durch "/" getrennt werden, so dass nach der Änderung in "vaSplit = Split (sInfo,"/") die INDEX Formel funktioniert hat. Aber jetzt gibt es "0" zurück, obwohl die Zeichenfolge eine Übereinstimmung haben sollte. Fortsetzung der Untersuchung. –

0

Zu Dick und andere Leute, die interessiert sein könnten. Wie ich in meinem letzten Kommentar zu der Antwort von @ Dick-Kusleika erwähnt habe, hat seine Antwort meine anfängliche Frage nicht vollständig abgedeckt. Obwohl es mir große Einsicht verschaffte und es mir die Aufgabe machte, die leeren Zellen mit den entsprechenden Daten zu füllen, suchte ich wirklich nach etwas, das es automatisch tun würde, ohne dass ich irgendwelche Formeln kopieren oder einfügen musste. Also verbrachte ich etwas mehr Zeit damit, es herauszufinden, Informationen aus dem Internet zu bekommen und mit einem Kollegen zu trainieren, der mein Interesse daran teilt. Und schließlich habe ich es geschafft zu arbeiten! (hurra !!)

Unten ist meine Lösung. Da ich noch ein Anfänger bin, habe ich wahrscheinlich ein paar Dinge gemacht, die besser oder sauberer hätten gemacht werden können. Ich bin also sehr interessiert an Ihrer Meinung und würde gerne irgendwelche Bemerkungen oder Tipps hören.

Sub check_fruit() 

Dim ws As Excel.Worksheet 
Dim lo_Data As Excel.ListObject 
Dim lo_Fruit As Excel.ListObject 
Dim lr_Data As Excel.ListRow 
Dim lr_Fruit As Excel.ListRow 
Dim d_Info As Variant 
Dim f_Fruit As Variant 

Set ws = ThisWorkbook.Worksheets("Exercise") 
Set lo_Data = ws.ListObjects("tblData") 
Set lo_Fruit = ws.ListObjects("tblFruit") 

For Each lr_Data In lo_Data.ListRows 

    'check if field "Color" is empty in tblData' 
    If IsEmpty(Intersect(lr_Data.Range, lo_Data.ListColumns("Color").Range).Value) Then 
     d_Info = Intersect(lr_Data.Range, lo_Data.ListColumns("Info").Range).Value 

     For Each lr_Fruit In lo_Fruit.ListRows 
      f_Fruit = Intersect(lr_Fruit.Range, lo_Fruit.ListColumns("Fruit").Range).Value 

      'check for each row in tblFruit if value for field "Fruit" exists in field "Info" of tblData' 
      If InStr(1, d_Info, f_Fruit, vbTextCompare) <> 0 Then 
       Intersect(lr_Data.Range, lo_Data.ListColumns("Color").Range).Value = Intersect(lr_Fruit.Range, lo_Fruit.ListColumns("Color").Range).Value 
       Intersect(lr_Data.Range, lo_Data.ListColumns("Price").Range).Value = Intersect(lr_Fruit.Range, lo_Fruit.ListColumns("Price").Range).Value 
      End If 

     Next lr_Fruit 

    End If 

Next lr_Data 

End Sub 
Verwandte Themen