Windows Script to open Excel file and run macro - vba

Sorry I am very new to VBA so am learning as I go along. I have tried to search for an answer to this but everything I find seems to think that the macro will be in the file I want to open.
Once a month I get a file that contains some data. Up to now I had to look at the data then do a VLOOKUP to add some additional data before saving it.
I have now written a VBA macro to add the additional information I want and it works as intended. However what I would like to do is have a Windows script that will open the file I receive, run the macro I have written, then save the file as a csv.
Can anyone point me in the right direction? If needed my macro is below
Sub AddBandInfo()
Dim i As Long
For i = 2 To 50000
Dim band As String, result As Double
band = Range("B" & i).Value
If band = "A" Then result = 1144.02
If band = "B" Then result = 1334.7
If band = "C" Then result = 1525.36
If band = "D" Then result = 1716.04
If band = "E" Then result = 2097.38
If band = "F" Then result = 2478.72
If band = "G" Then result = 2860.08
If band = "H" Then result = 3432.08
If band = "" Then result = 0.01
Range("C" & i).Value = result
Next i
Dim r As Long
For r = Sheet1.UsedRange.Rows.Count To 1 Step -1
If Cells(r, "C") = "0.01" Then
Sheet1.Rows(r).EntireRow.Delete
End If
Next
End Sub
Thanks

Create a .txt-file and rename it to .vbs.
Start your code with:
Set objXLS = CreateObject("Excel.Application")
Set myWkbk = objXLS.Application.Workbooks.Open("C:\mypath\myfile.xlsx")
Set myWksh = myWkbk.Worksheets("yoursheet")
With myWksh
'your
'code
'here
End With
Set objXLS = Nothing
All done. :)

We can improve AddBandInfo speed and performance by
Toggling Application.ScreenUpdating
Looping from the last row to the first row (doing this allows use to delete the rows as we go)
If 50000 isn't the actual last row use
For i = Range("B" & Rows.Count).End(xlUp).Row To 2 Step -1
Public Sub AddBandInfo()
Dim i As Long
Application.ScreenUpdating = False
For i = 50000 To 2 Step -1
Dim band As String, result As Double
band = Range("B" & i).Value
Select Case Cells(i, 2).Value
Case "A"
Range("C" & i).Value = 1144.02
Case "B"
Range("C" & i).Value = 1334.7
Case "C"
Range("C" & i).Value = 1525.36
Case "D"
Range("C" & i).Value = 1716.04
Case "E"
Range("C" & i).Value = 2097.38
Case "F"
Range("C" & i).Value = 2478.72
Case "G"
Range("C" & i).Value = 2860.08
Case "H"
Range("C" & i).Value = 3432.08
Case Else
Rows(i).EntireRow.Delete
End Select
Next
Application.ScreenUpdating = True
End Sub
Assuming AddBandInfo is saved in C:\somedirectory\somefile.xlsx and that you want a vbscript to open the Workbook and then run AddBandInfo:
Const WorkBookPath = "C:\somedirectory\somefile.xlsx"
Dim xlApplication, xlWorkbook
Set xlApplication = CreateObject("Excel.Application")
Set xlWorkbook = xlApplication.Workbooks.Open(WorkBookPath)
xlApplication.Run "'" & xlWorkbook.Name & "'!AddBandInfo()"
xlWorkbook.Save , False
xlApplication.Quit
Set xlApplication = Nothing

Related

How to make multiple "for" statements run efficiently in VBA

In my code there is a searching order and it does as folloing:
It takes each value (about 2000 ranges) in ws.sheet range A and looks it up in another sheet named wp.sheet range A (about 90 ranges). If a particular value x in ws.sheet range e.g A3 is not found in wp.sheet range A the next search order in sheet ws.sheet is the value y in the next range B3 (same row as value x) to be searched in sheet wp.sheet in the entire range B, and so on.
This is what my "for" loop does and the issue with my code is that it takes very long as it compares each value in ws.sheet range A1-2000 to the values in wp.sheet range A1-90. Is there an alternative which does it more quickly or more efficiently?
Dim wb As Workbook, wq As Object
Dim ws, wi As Worksheet, datDatum
Dim w As Long, I As Long, t As Long
Dim DefaultMsgBox()
Dim r, i As Integer
For r = 2 To 2000
Check = True:
For i = 1 To 90
If ws.Range("A" & r).Value = wp.Sheets("ABC").Range("A" & i).Value Then
wp.Sheets("ABC").Rows(i).Columns("E:AB").Copy
ws.Range("G" & r).PasteSpecial
GoTo NextR
End If
Next i
For i = 1 To 90
If ws.Range("B" & r).Value = wp.Sheets("ABC").Range("B" & i).Value Then
wp.Sheets("ABC").Rows(i).Columns("E:AB").Copy
ws.Range("G" & r).PasteSpecial
GoTo NextR
End If
Next i
For i = 1 To 90
If ws.Range("C" & r).Value = wp.Sheets("ABC").Range("C" & i).Value And ws.Range("D" & r).Value = wp.Sheets("ABC").Range("D" & i).Value Then
wp.Sheets("ABC").Rows(i).Columns("E:AB").Copy
ws.Range("G" & r).PasteSpecial
GoTo NextR
End If
Next i
NextR:
If Not Check = ws.Range("A" & r).Value = wp.Sheets("ABC").Range("A" & i).Value Or Not Check = ws.Range("B" & r).Value = wp.Sheets("ABC").Range("A" & i).Value Or Not Check = ws.Range("C" & r).Value = wp.Sheets("ABC").Range("C" & i).Value And ws.Range("D" & r).Value = wp.Sheets("ABC").Range("D" & i).Value Then
MsgBox "......"
End If
Next r
End sub
I would suggest turning off ScreenUpdating and using the Find function instead:
Dim cell, foundValue, lookupRange As Range
Set wp = ThisWorkbook.Sheets("ABC")
Set ws = ThisWorkbook.Sheets("WS")
r = 2
number_r = 2000
ru = 1
number_ru = 90
Application.ScreenUpdating = False
'Loop through each cell in WS, offsetting through columns A to C
For Each cell In ws.Range("A" & r & ":A" & number_r)
For i = 0 To 2
'Define range to look up in ABC
Set lookupRange = wp.Range(wp.Cells(ru, i + 1), wp.Cells(number_ru, i + 1))
'Look for current WS cell on corresponding column in ABC
Set foundValue = lookupRange.Find(cell.Offset(0, i).Value)
'If cell is found in ABC...
If Not foundValue Is Nothing Then
Select Case i
Case 2 'If found cell is in column C
Do 'Lookup loop start
'If same values on columns D...
If foundValue.Offset(0, 1).Value = cell.Offset(0, 3).Value Then
'Copy data to WS and switch to the next cell
wp.Rows(foundValue.Row).Columns("E:AB").Copy
ws.Range("G" & cell.Row).PasteSpecial
GoTo nextCell
'If not same values on columns D...
Else
'Try to find next match, if any
Set foundValue = lookupRange.FindNext(foundValue)
If foundValue Is Nothing Then GoTo noMatchFound
End If
Loop 'Repeat until WS values in column C and D match ABC values in columns C and D
Case Else 'If found cell is in column A or B
'Copy data to WS and switch to the next cell
wp.Rows(foundValue.Row).Columns("E:AB").Copy
ws.Range("G" & cell.Row).PasteSpecial
GoTo nextCell
End Select
End If
Next i
noMatchFound:
MsgBox "......" 'Message appears only when no match was found in column A, column B and column C + D
nextCell:
Next cell
Application.ScreenUpdating = True
I hope you don't mind my saying so, but your code is hard to follow, including your choice of variable names. I can recommend that if you do not make use of your .copy statements, then comment them out and your code will run much faster.

Attempting to store unique strings from text file in Excel using VBA

I am having an issue with one of my loops entering a string into excel. I am extracting data from a text file that can be any length, but everything I've used so far is anywhere between 100 lines of data and 50000 lines of data. The string I am attempting to extract is 4 characters long, most often numbers, but can be alphanumeric. By default the characters are 0001, 0002, 0003, and 0004 but this is completely up to our customers if they choose to use any other 4 characters. When entering the data in Excel, I am wanting only the unique values entered.
The whole code can be given, but everything else works fine so I don't think it's necessary. If you think so, request and I'll edit it in. Keep in mind that I've tried many different attempts at this and the logic never seems to work out.
The result is a long list of rows with every value from the text file.
If I had to guess, this is due to the string being a number and then excel storing it as just "2" instead of "0002" so I have formatted the entire column to show 4 characters. Even then I think Excel sees it as just "2" so the string never matches the data.
Any help is appreciated.
FileName = Application.GetOpenFilename()
Open FileName For Input As #1
strSearch = "MTRDT"
Do Until EOF(1)
Line Input #1, ReadData
If Left(ReadData, Len(strSearch)) = strSearch Then
MtrdtCount = MtrdtCount + 1
MeterType = Mid(ReadData, 78, 4)
lastrow = Cells(Rows.Count, "G").End(xlUp).Row + 1
MeterTypeTest = True
For Each cell In Range("G3:G" & lastrow)
If MeterType = cell.Value Then
MeterTypeTest = False
Exit For
End If
Next cell
If MeterTypeTest = True Then
Range("G" & MeterTypeCnt) = MeterType
MeterTypeCnt = MeterTypeCnt + 1
End If
Else
End If
Loop
If all your data has been entered using the method shown, Excel won't be seeing the data entered as 0002 as the number 2 - it will be seeing it as the string "0002".
But you are testing those values against "'" & Mid(ReadData, 78, 4), which means you will be comparing "0002" against "'0002".
You need to add that ' character as you enter the data to the cell, not before doing the comparison. So the following should work:
FileName = Application.GetOpenFilename()
Open FileName For Input As #1
strSearch = "MTRDT"
Do Until EOF(1)
Line Input #1, ReadData
If Left(ReadData, Len(strSearch)) = strSearch Then
MtrdtCount = MtrdtCount + 1
MeterType = Mid(ReadData, 78, 4)
lastrow = Cells(Rows.Count, "G").End(xlUp).Row + 1
MeterTypeTest = True
For Each cell In Range("G3:G" & lastrow)
If MeterType = cell.Value Then
MeterTypeTest = False
Exit For
End If
Next cell
If MeterTypeTest Then
Range("G" & MeterTypeCnt) = "'" & MeterType
MeterTypeCnt = MeterTypeCnt + 1
End If
End If
Loop
I think set column "G"'s numberformatLocal as bellow
Columns("g").NumberFormatLocal = "#"
Filename = Application.GetOpenFilename()
Open Filename For Input As #1
strSearch = "MTRDT"
Do Until EOF(1)
Line Input #1, ReadData
If Left(ReadData, Len(strSearch)) = strSearch Then
MtrdtCount = MtrdtCount + 1
MeterType = Mid(ReadData, 78, 4)
lastrow = Cells(Rows.Count, "G").End(xlUp).Row + 1
MeterTypeTest = True
For Each cell In Range("G3:G" & lastrow)
If MeterType = cell.Value Then
MeterTypeTest = False
Exit For
End If
Next cell
If MeterTypeTest = True Then
Range("G" & MeterTypeCnt) = MeterType
MeterTypeCnt = MeterTypeCnt + 1
End If
Else
End If
Loop

Vba Lookup value on sheet x if value like or similar to?

I have a workbook with 2 sheets.
Sheet1:
Column B Column C Column D Column E
Dairy Crest Ltd
Milk Farm
Tuna Family
Guiness
Sheet 2:
Column A Column B Column C Column d
Dairy Crest James james#email.com 07874565656
Milk Farm Limited Kelly kely#email.com 07874565656
Tuna's Families Dave dave#email.com 07874565656
Guiness Prep Limited Tom tom#email.com 07874565656
I want to match the similar named companies. This can't be a case of saying if value = value because the company name is usually spelt different.
Instead i want to use like or wildcard. Would this work?
If i use Value Like Value this doesn't seem to work.
Where found, i want to copy the contact name, email and contact number over to sheet 1 in the relevant columns.
For some reason this is not working. Please can someone show me where i am going wrong?
Relevant code:
'Start second loop sequence
With ThisWorkbook.Worksheets(3)
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
j2 = 2
For i2 = 1 To LastRow
' === For DEBUG ONLY ===
Debug.Print ThisWorkbook.Worksheets(2).Range("B" & j2).Value
If ThisWorkbook.Worksheets(2).Range("B" & j2).Value = .Range("A" & i2).Value Then ' check if Week No equals the value in "A1"
ThisWorkbook.Worksheets(2).Range("C" & j2).Value = .Range("B" & i2).Value
ThisWorkbook.Worksheets(2).Range("D" & j2).Value = .Range("D" & i2).Value
ThisWorkbook.Worksheets(2).Range("E" & j2).Value = .Range("C" & i2).Value
j2 = j2 + 1
End If
Next i2
End With
'End Second Loop
Full COde:
Option Explicit
Sub LoadWeekAnnouncementsFromPlanner()
Dim WB As Workbook
Dim WB2 As Workbook
Dim i As Long
Dim i2 As Long
Dim j As Long
Dim j2 As Long
Dim LastRow As Long
Dim ws As Worksheet
'Open Planner
'On Error Resume Next
Set WB = Workbooks("2017 Planner.xlsx")
On Error GoTo 0
If WB Is Nothing Then 'open workbook if not open
Set WB = Workbooks.Open("G:\BUYING\Food Specials\2. Planning\1. Planning\1. Planner\8. 2017\2017 Planner.xlsx", xlUpdateLinksNever, True, Password:="samples")
End If
'Open PhoneBook
'On Error Resume Next
'On Error GoTo 0
' ======= Edit #2 , also for DEBUG ======
With WB.Worksheets(1)
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
j = 2
For i = 1 To LastRow
' === For DEBUG ONLY ===
Debug.Print CInt(ThisWorkbook.Worksheets(1).Range("I8").Value)
If CInt(ThisWorkbook.Worksheets(1).Range("I8").Value) = .Range("A" & i).Value Then ' check if Week No equals the value in "A1"
ThisWorkbook.Worksheets(2).Range("A" & j).Value = .Range("A" & i).Value
ThisWorkbook.Worksheets(2).Range("B" & j).Value = .Range("N" & i).Value
ThisWorkbook.Worksheets(2).Range("H" & j).Value = .Range("K" & i).Value
ThisWorkbook.Worksheets(2).Range("I" & j).Value = .Range("L" & i).Value
ThisWorkbook.Worksheets(2).Range("J" & j).Value = .Range("M" & i).Value
ThisWorkbook.Worksheets(2).Range("K" & j).Value = .Range("G" & i).Value
ThisWorkbook.Worksheets(2).Range("L" & j).Value = .Range("O" & i).Value
ThisWorkbook.Worksheets(2).Range("M" & j).Value = .Range("P" & i).Value
ThisWorkbook.Worksheets(2).Range("N" & j).Value = .Range("W" & i).Value
ThisWorkbook.Worksheets(2).Range("O" & j).Value = .Range("Z" & i).Value
'Start second loop sequence
With ThisWorkbook.Worksheets(3)
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
j2 = 2
For i2 = 1 To LastRow
' === For DEBUG ONLY ===
Debug.Print ThisWorkbook.Worksheets(2).Range("B" & j2).Value
If ThisWorkbook.Worksheets(2).Range("B" & j2).Value = .Range("A" & i2).Value Then ' check if Week No equals the value in "A1"
ThisWorkbook.Worksheets(2).Range("C" & j2).Value = .Range("B" & i2).Value
ThisWorkbook.Worksheets(2).Range("D" & j2).Value = .Range("D" & i2).Value
ThisWorkbook.Worksheets(2).Range("E" & j2).Value = .Range("C" & i2).Value
j2 = j2 + 1
End If
Next i2
End With
'End Second Loop
j = j + 1
End If
Next i
End With
End Sub
Please can someone show me where i am going wrong?
This is a good example how to use Like in VBA. Try it in the console window, to get the answers.
?"Vito6" Like "V?to6"
True
?"Vito6" Like "Vito#"
True
?"Vito6" Like "V*6"
True
?"Vito6" Like "Vit[a-z]6"
True
?"Vito6" Like "Vit[A-Z]6"
False
?"Vito6" Like "Vit[!A-Z]6"
True
?"12 34" Like "## ##"
True
?"12 34" Like "1[0-9] [0-9]4"
True
If there's not a specific reason you need VBA, you could apply the solution that #Cyril gave in his comment to an Excel cell formula on Sheet1.
For example, in Sheet1, Cell F1, you can input:
=LEFT(B1, 4)
'This would return "Dair"
Then, in column A, you could use a nested IF statement:
=IF(F1 = "dair", "Dairy Crest", IF(F1 = "milk", "Milk Farm Limited, IF(F1 = "tuna", "Tuna's Families", IF(F1 = "Guiness", "Guiness Prep Limited", "No match))))
Will try to elaborate on my thought from the comment I left you:
Dim asdf as String
Dim i as Variant
Dim LR as Long
LR = Sheets("Sheet2").Cells(.Rows.Count, "A").End(xlUp).Row
For i = 2 to LR 'Sheet1 looks to start on row 3, while Sheet2 looks to start on row2
asdf = Sheets("Sheet1").Cells(i+1,2).Value
If Sheets("Sheet2").Cells(i,1).Value Like "*asdf*" Then 'you left out the asterisks
'true: copy data
Else:
'false: can just be nothing here
End If
Next i
Something similar to that is what I was suggesting. Utilized like operator, as suggested by #DougCoats.
While you can use wildcards to compare strings using the like operator , the explicit parts need to be exact. So
"*Dairy Crest*" like "Dairy Crest Ltd" will work nicely
but "*Tuna Family*" like "Tuna's Families" will not work.
You can try fuzzy lookup for matching for the 2nd scenario. It employs probability into the lookup.
Here is the link to the source code.
https://www.mrexcel.com/forum/excel-questions/195635-fuzzy-matching-new-version-plus-explanation.html
Just one note for fuzzy matching with probability, the matching may not be 100% correct if you set the accuracy % too low. If accuracy is important, then set the accuracy % higher.

Need VBA code to search for data in a sheet and print the selected data in one page

I need to find various data in a sheet and select those data and print the selected data to printout and all data to be printed in one page. I tried with this code but something is wrong:
Sub Selection()
Dim varRow As String
For i = 1 To Range("A" & Rows.Count).End(xlUp).Row
If Range("A" & i).Value = "M655" Or Range("A" & i).Value = "Equity Fund" Then
If Trim(varRow) <> "" Then
varRow = varRow & "," & i & ":" & i
Else
varRow = varRow & i & ":" & i
End If
End If
Next i
Range(varRow).Select
Selection.PrintOut
With ActiveSheet.PageSetup
.PrintTitleRows = "$3:$3"
.PrintTitleColumns = "$B:$B"
.Orientation = xlLandscape
.Zoom = False
.FitToPagesWide = 1
.FitToPagesTall = 1
End with
End Sub
One issue is that after you loop through the cells, varRow is a string of "M655" and "Equity Fund" separated by commas. You then try to use that string as an argument for a range which is invalid. If you are trying to build a a string of range addresses ("a1", "a2", etc) try using the .AddressLocal property. Also, you use .PrintOut prior to setting the print settings. Try putting that line after you set the page setup settings to have them take effect.

Compare sheet 1 col 1 to sheet 2 col 1 place value in sheet 1 col 6

First time posting a question, so please correct me if I do anything I'm not supposed to!
I have a macro written on a button press to compare 2 columns on 2 sheets and output either the value from sheet 2 col 1 in sheet 1 col 6 OR output "None" in sheet1 col 6 if there isn't a match.
My code is buggy and takes a long time to run (around 5000 entry's on sheet 1 and 2000 on sheet 2).
My code works partly; it only matches around 2/3rd's of the col 1's on either sheet.
Sub Find_Sup()
Dim count As Integer
Dim loopend As Integer
Dim PartNo1 As String
Dim PartNo2 As String
Dim partRow As String
Dim SupRow As String
Dim supplier As String
Let partRow = 2
Let SupRow = 2
'Find total parts to check
Sheets("Linnworks Supplier Update").Select
Range("A1").End(xlDown).Select
loopend = Selection.row
Application.ScreenUpdating = False
'main loop
For count = 1 To loopend
jump1:
'progress bar
Application.StatusBar = "Progress: " & count & " of " & loopend & ": " & Format(count / loopend, "0%")
Let PartNo2 = Worksheets("Linnworks Supplier Update").Cells(SupRow, 1).Value
Let supplier = Worksheets("Linnworks Supplier Update").Cells(SupRow, 2).Value
If PartNo2 = "" Then
SupRow = 2
Else
jump2:
Let PartNo1 = Worksheets("Linnworks Stock").Cells(partRow, 1).Value
'add part numbers than do match
If PartNo2 = PartNo1 Then
Let Worksheets("Linnworks Stock").Cells(partRow, 5).Value = supplier
Let partRow = partRow + 1
Let count = count + 1
GoTo jump2
Else
Let SupRow = SupRow + 1
GoTo jump1
End If
End If
Next
Application.StatusBar = True
End Sub
I have done some coding in C and C++ and a little VB.NET. Any help streamlining this code or pointing me in the right direction would be very gratefully received!
I realise there are similar questions but all other options I've tried (nested for each loops) don't seem to work correctly.
This is the closest I've managed to get so far.
Many Thanks for reading
try something like this instead and leave feedback so I can edit the answer to match perfectly
Sub Main()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = Sheets("Linnworks Supplier Update")
Set ws2 = Sheets("Linnworks Stock")
Dim partNo2 As Range
Dim partNo1 As Range
For Each partNo2 In ws1.Range("A1:A" & ws1.Range("A" & Rows.Count).End(xlUp).Row)
For Each partNo1 In ws2.Range("A1:A" & ws2.Range("A" & Rows.Count).End(xlUp).Row)
If StrComp(Trim(partNo2), Trim(partNo1), vbTextCompare) = 0 Then
ws2.Range("E" & partNo1.Row) = partNo2.Offset(0, 1)
ws2.Range("F" & partNo1.Row) = partNo2
End If
Next
Next
'now if no match was found then put NO MATCH in cell
for each partno1 in ws2.Range("E1:F" & ws2.Range("A" & Rows.Count).End(xlUp).Row)
if isempty(partno1) then partno1 = "no match"
next
End Sub