In VBA replace hard coded cell reference with dynamic in a link - vba

I have two workbooks one "database" and another "source". What I'm trying to achieve is to set up a loop that would iterate thru a known range in "source" wb and create links in "database". Data in the "source" wb = C7:C38.
Any ideas?
Code below is the one i'm using to pull single values for the links - how can I make it loop thru range C7:C38?
Option Explicit
'**********Using ip address to link/locate folders in the the directory.
Public Sub PullData()
Dim repDate As Date
Dim tmpFileStr As String
Dim tmpPathStr As String
Dim rowCtrLng As Long
Dim startRowCtrLng As Long
Dim stoptRowCtrLng As Long
Dim msgStr As String
Dim currentDate As Date
Dim stopDate
Dim fldName As String
Dim fName As String
Dim fDay As String
'On Error GoTo errHandler
'Initialize row counter
startRowCtrLng = 2
'Get starting row for new data
Do While ThisWorkbook.ActiveSheet.Range("B" & startRowCtrLng).Value <> ""
startRowCtrLng = startRowCtrLng + 1
Loop
rowCtrLng = startRowCtrLng
'Assign current date to variable
'Pause automatic calculation
Application.Calculation = xlCalculationManual
'Disable alerts
Application.DisplayAlerts = False
repDate = Format(ThisWorkbook.Worksheets("Database").Range("A" & rowCtrLng).Value, "mm/dd/yyyy")
currentDate = Date
fldName = Format(Year(Now), "0000")
fName = Format(Month(Now), "00")
fDay = Format(Day(Now), "0")
'Begin looping through date range
Do While repDate < currentDate
tmpFileStr = ""
tmpPathStr = ""
'Determine if report exists
tmpPathStr = "\\0.0.0.0\dept\Folder\Subfolder\" & fldName & "\"
If Dir("\\0.0.0.0\dept\Folder\Subfolder\" & fldName & "\" & fName & "-" & fldName & ".xls") <> "" Then
tmpFileStr = fName & "-" & fldName & ".xls"
Else
tmpFileStr = ""
End If
If tmpFileStr <> "" Then
'build Links
'Production Date
ThisWorkbook.ActiveSheet.Range("A" & rowCtrLng).Value = repDate
'Crush
ThisWorkbook.ActiveSheet.Range("B" & rowCtrLng).Value = "='" & tmpPathStr & "[" & tmpFileStr & "]C vol'!$C$7"
End If
rowCtrLng = rowCtrLng + 1
repDate = ThisWorkbook.Worksheets("Database").Range("A" & rowCtrLng).Value
Loop
End Sub
'

Related

Create folders using 2 column values from Excel

So I need to make a whole bunch of folders from a spreadsheet.
I have in column A the Surname and in Column B the name of a person, I need to generate folders based on this.
I have found a bit of code that someone else posted, that works, but I need to add a space between the name and surname in the created folder.
The original poster said that they did manage to add a space, but never indicated how.
Sub MakeFoldersForEachRow()
Dim Rng As Range
Dim maxRows, maxCols, r, c As Integer
Dim s As String
Set Rng = Selection
maxRows = Rng.Rows.Count
maxCols = Rng.Columns.Count
For r = 1 To maxRows
s = ""
For c = 1 To maxCols
s = s & Rng(r, c)
Next c
If Len(Dir(ActiveWorkbook.Path & "\" & s, vbDirectory)) = 0 Then
MkDir (ActiveWorkbook.Path & "\" & s)
On Error Resume Next
End If
Next r
End Sub
Please, try the next code:
Sub createFoldNamesFromTwoColumns()
Dim sh As Worksheet, lastR As Long, fldName As String, i As Long
Set sh = ActiveSheet 'use here your necessary sheet
lastR = sh.Range("A" & sh.Rows.count).End(xlUp).row
For i = 1 To lastR
fldName = sh.Range("A" & i) & " " & sh.Range("B" & i)
If Dir(ActiveWorkbook.Path & "\" & fldName, vbDirectory) = "" Then
MkDir ActiveWorkbook.Path & "\" & fldName
End If
Next i
End Sub
Edited:
I could see now your last request, meaning to process the selected columns:
Sub createFoldNamesFromTwoSelectedColumns()
Dim sh As Worksheet, rngSel As Range, C1 As Long, lastR As Long, fldName As String, i As Long
Set sh = ActiveSheet
Set rngSel = Selection
If rngSel.Columns.count <> 2 Then MsgBox "You must select two columns!": Exit Sub
C1 = rngSel.cells(1).Column: Stop
lastR = sh.cells(sh.Rows.count, C1).End(xlUp).row
For i = 1 To lastR
fldName = sh.cells(i, C1) & " " & sh.cells(i, C1 + 1)
If Dir(ActiveWorkbook.Path & "\" & fldName, vbDirectory) = "" Then
MkDir ActiveWorkbook.Path & "\" & fldName
End If
Next i
End Sub

Save copy of workbook as new xlsm, runtime error 1004

I'm trying to save a copy of the workbook as a new .xlsm file via the following code:
SaveAs FileName:=StrPadHoofdDocument & "\Docs\" & "\n\" & ".xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
I get the following error: "runtime error 1004: method of object SaveAs of object_Workbook failed"
I've read a lot of other topics with the same kind of problem but I just can't quite solve it. Hope you guys can help!
full code:
Sub motivatieFormOpmaken()
Const StBestand = "Stambestand.xlsm"
Const motivatie = "Template motivatieformulier opstapregeling.xlsx"
Dim wbMotivTemp As Workbook
Dim wsMotiv As Worksheet
Dim PathOnly, mot, FileOnly As String
Dim StrPadSourcenaam As String
Set wbMotivTemp = ThisWorkbook
Set wsMotiv = ActiveSheet
StrHoofdDocument = ActiveWorkbook.Name
StrPadHoofdDocument = ActiveWorkbook.Path
StrPadSourcenaam = StrPadHoofdDocument & "\" & c_SourceDump
If Not FileThere(StrPadSourcenaam) Then
MsgBox "Document " & StrPadSourcenaam & " is niet gevonden."
Exit Sub
End If
Application.ScreenUpdating = False
Workbooks.Open FileName:=StrPadSourcenaam
Application.Run "Stambestand.xlsm!unhiderowsandcolumns"
Worksheets("stambestand").Activate
iLaatsteKolom = Worksheets("stambestand").Cells.SpecialCells(xlLastCell).Column
iLaatsteRij = Worksheets("stambestand").Cells.SpecialCells(xlLastCell).row
VulKolomNr
If KolomControle = False Then Exit Sub
Aantalregels = AantalZichtbareRows
Dim rng As Range
Dim row As Range
Dim StrFileName As String
'If Aantalregels > 1 Then
Set rng = Selection.SpecialCells(xlCellTypeVisible)
For Each row In rng.Rows
iRijnummer = row.row
If iRijnummer > 1 Then
'Windows(c_SourceDump).Activate
wsMotiv.Range("motiv_cid") = Cells(iRijnummer, iKolomnrCorpID).Text
wsMotiv.Range("motiv_naam") = Cells(iRijnummer, iKolomnrNaam).Text
wsMotiv.Range("motiv_ldg") = Cells(iRijnummer, iKolomnrHuidigeLeidingGevende).Text
n = naamOpmaken
wbMotivTemp.Activate
ActiveWorkbook.SaveAs FileName:=StrPadHoofdDocument & "\Docs\" & "\n\" & ".xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
End If
Next row
End Sub
Function naamOpmaken() As String
Dim rng As Range
Dim row As Range
Set rng = Selection.SpecialCells(xlCellTypeVisible)
iRijnummer = rng.row
If iRijnummer > 1 Then
s = Cells(iRijnummer, iKolomnrNaam).Text
Dim Position As Long, Length As Long
Dim n As String
Position = InStrRev(s, " ")
Length = Len(s)
n = Right(s, Length - Position)
End If
naamOpmaken = n
End Function
Change this part:
FileName:=StrPadHoofdDocument & "\Docs\" & "\n\" & ".xlsm",
With this:
FileName:=StrPadHoofdDocument & "\Docs\" & n & ".xlsm",
As you see, the problem is that you are using twice \\. Furthermore, n is a variable and it is passed as string. In future similar cases, print the problematic string and examine it closely, with code like this:
Debug.Print StrPadHoofdDocument & "\Docs\" & "\n\" & ".xlsm"
Debug.Print StrPadHoofdDocument & "\Docs\" & n & ".xlsm"
The errors would be visible then.

Excel VBA UDF Executes in Immediate Window, Fails on Worksheet

UDF "NAV()" is designed to find the correct report on a network drive based on the first argument (always a date), then loop through all worksheets to find a piece of data with the same row as second argument and same column as third argument (second and third can be text or numbers).
Works reliably in the immediate window. Always returns #VALUE! when used on worksheet, e.g. =NAV(D7,D8,D9) or =NAV(2/19/2016,"Net Asset Value","221-I").
In general it looks like one could get this behaviour if trying to alter other cells in a UDF, but my functions don't do that. Also, I believe all range references specify which workbook and worksheet, so I don't think that is the problem either. I'm not sure where to look next.
Function also attempts to email me a report through Outlook when it fails to find what the user is looking for. I don't know if that is relevant.
Again, what is perplexing is that this code seems to work fine in the immediate window, but only gives #VALUE! when used on a worksheet.
Where else can I look in my code below to determine what would cause NAV() to function correctly in the immediate window, but always yield #VALUE! when used on a worksheet?
Option Explicit
Function NAV(ByVal NAVDate As Date, ByVal matchRow As Variant, ByVal matchColumn As Variant) As Variant
'Application.ScreenUpdating = False
Application.Volatile True
NAV = FindItemOnWorksheet(NAVDate, matchRow, matchColumn)
'Application.ScreenUpdating = True
End Function
Function FindItemOnWorksheet(ByVal NAVDate As Date, ByVal ItemSpecies As Variant, ByVal ItemGenus As Variant) As Variant
' Finds Item by opening NAV workbook with correct date, activating correct worksheet, and searching for correct row and column
Dim startingRange As Range
Dim ws As Worksheet
Dim wb As Workbook
Dim theDate As Date
Dim theItemSpecies As String
Dim theItemGenus As String
theDate = NAVDate
theItemSpecies = ItemSpecies
theItemGenus = ItemGenus
Set wb = GetWB(NAVDate)
'Loop through ws
Dim WS_Count As Integer
Dim i As Integer
WS_Count = wb.Worksheets.Count
For i = 1 To WS_Count
Set ws = wb.Worksheets(i)
Set startingRange = ws.Range("A1:Z100")
Dim theRow As Range
Dim theColumn As Range
Set theRow = startingRange.Cells.Find(theItemSpecies, SearchDirection:=xlPrevious, lookat:=xlWhole)
If Not (theRow Is Nothing) Then
Set theColumn = startingRange.Cells.Find(theItemGenus, SearchDirection:=xlPrevious, lookat:=xlWhole)
If Not (theColumn Is Nothing) Then
FindItemOnWorksheet = ws.Cells(theRow.Row, theColumn.Column).Value
wb.Close
Exit Function
End If
End If
Next i
'Loop if no hit on either row or column Find()
'following executes only if no match found
MsgBox "No Match Found. Make sure you are entering arguments--" & vbNewLine & _
" The Date of NAV, " & vbNewLine & _
" the entry found in the right row of NAV workbooks (e.g. 'Net Asset Value'), " & vbNewLine & _
" the right column (e.g. 'Fund')." & vbNewLine & _
" This function will only find exact matches." & vbNewLine & vbNewLine & _
"Now emailing developer to ask for a fix."
Dim OutApp As Object
Dim OutMail As Object
Dim strbody As String
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
strbody = "User attempted" & _
"=FindItemOnWorksheet( " & theDate & ", " & theItemSpecies & ", " & theItemGenus & " )" & vbNewLine & _
"theDate type " & TypeName(theDate) & vbNewLine & _
"theItemSpecies type " & TypeName(theItemSpecies) & vbNewLine & _
"theItemGenus type " & TypeName(theItemGenus)
On Error Resume Next
With OutMail
.To = <Address Removed>
.CC = ""
.BCC = ""
.Subject = "FindItemOnWorksheet Error"
.Body = strbody
'.Attachments.Add ("C:\file.xlsx")
.Send
End With
On Error GoTo 0
Set OutMail = Nothing
Set OutApp = Nothing
FindItemOnWorksheet = "Error"
'wb.Close
Exit Function
End Function
Function GetWB(ByVal NAVDate As Date) As Workbook
'Open requested workbook, return to parent procedure
Dim wbPath As String
Dim wbYear As String
Dim wbMonth As String
Dim wbWeek As String
Dim wbFile As String
Dim wbString As String
Dim wb As Workbook
Dim BackADay As Boolean
Dim OriginalNAVDateRequested As Date
OriginalNAVDateRequested = NAVDate
BackADay = True
'Loop through possible file tree structures and dates to find the closest NAV in the past to the date requested.
Do While BackADay = True
'Don't go back to a previous week if cannot find current NAV
If OriginalNAVDateRequested - NAVDate > 4 Then
BackADay = False
End If
wbPath = <Network Path Removed>
wbYear = CStr(Year(NAVDate)) & "\"
wbMonth = MonthName(Month(NAVDate)) & " " & wbYear
wbWeek = DateFormat(NAVDate) & "\"
wbFile = Dir(wbPath & wbYear & wbMonth & wbWeek & "*Valuation Package*.xlsx")
'Pricings with distributions have differing tree structure
If wbFile = "" Then
wbWeek = wbWeek & "POST Distribution " & wbWeek
wbFile = Dir(wbPath & wbYear & wbMonth & wbWeek & "*Valuation Package*.xlsx")
If wbFile = "" Then
NAVDate = NAVDate - 1
Else: BackADay = False
End If
Else: BackADay = False
End If
Loop
wbString = wbPath & wbYear & wbMonth & wbWeek & wbFile
Set wb = Workbooks.Open(wbString, UpdateLinks:=False, ReadOnly:=True)
Set GetWB = wb
End Function
Function DateFormat(ByVal X As Date) As String
'Appends leading zeroes if needed to achieve form "00" for any two digit integer, and converts to string
Dim MM As String
Dim DD As String
Dim YYYY As String
If Month(X) < 10 Then
MM = "0" & CStr(Month(X))
Else
MM = CStr(Month(X))
End If
If Day(X) < 10 Then
DD = "0" & CStr(Day(X))
Else
DD = CStr(Day(X))
End If
YYYY = CStr(Year(X))
DateFormat = MM & "." & DD & "." & YYYY
End Function
You can Open Workbooks within a Worksheet_Change Event.
For demonstration, if a change in Sheet1!A2, Excel will try open the workbook name with that cell value, then Output the status to Sheet1!A4.
Put below in a Module:
Option Explicit
Function TryOpenWB(ByVal oItem As Variant) As Variant
Dim sOut As String
Dim oWB As Workbook
On Error Resume Next
Set oWB = Workbooks.Open(CStr(oItem))
If oWB Is Nothing Then
sOut = "Cannot open """ & CStr(oItem) & """"
Else
sOut = "Opened """ & CStr(oItem) & """ successfully."
'oWB.Close
End If
TryOpenWB = sOut
End Function
Then below in Worksheet Module (I used Sheet1 for demonstration):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = Range("A2").Address Then
Application.EnableEvents = False
Range("A4").Value = TryOpenWB(Target)
Application.EnableEvents = True
End If
End Sub
So this idea is to open the Workbook only if some cell address is matched.

VBA Save As Current Filename +01

I'm looking to write a macro to save my current version filename +1 instance of the version. For each new day the version would reset to v01. Ex. Current = DailySheet_20150221v01; Save As = DailySheet_20150221v02; Next Day = DailySheet_20150222v01
While increasing the version number, I am hoping the version won't have to contain the v0 once v10+ has been reached.
I was able to workout how to save the file with today's date:
Sub CopyDailySheet()
Dim datestr As String
datestr = Format(Now, "yyyymmdd")
ActiveWorkbook.SaveAs "D:\Projects\Daily Sheet\DailySheet_" & datestr & ".xlsx"
End Sub
but need additional help in finding the version addition. Could I set the SaveAs to a string, then run it through a For/If - Then set?
Put this out to a couple of my friends and below is their solution:
Sub Copy_DailySheet()
Dim datestr As String, f As String, CurrentFileDate As String, _
CurrentVersion As String, SaveAsDate As String, SaveAsVersion As String
f = ThisWorkbook.FullName
SaveAsDate = Format(Now, "yyyymmdd")
ary = Split(f, "_")
bry = Split(ary(UBound(ary)), "v")
cry = Split(bry(UBound(bry)), ".")
CurrentFileDate = bry(0)
CurrentVersion = cry(0)
SaveAsDate = Format(Now, "yyyymmdd")
If SaveAsDate = CurrentFileDate Then
SaveAsVersion = CurrentVersion + 1
Else
SaveAsVersion = 1
End If
If SaveAsVersion < 10 Then
ThisWorkbook.SaveAs "D:\Projects\Daily Sheet\DailySheet_" & SaveAsDate & "v0" & SaveAsVersion & ".xlsm"
Else
ThisWorkbook.SaveAs "D:\Projects\Daily Sheet\Daily Sheet_" & SaveAsDate & "v" & SaveAsVersion & ".xlsm"
End If
End Sub
Thanks to all those who contributed.
Try this one:
Sub CopyDailySheet()
'Variables declaration
Dim path As String
Dim sht_nm As String
Dim datestr As String
Dim rev As Integer
Dim chk_fil As Boolean
Dim ws As Object
'Variables initialization
path = "D:\Projects\Daily_Sheet"
sht_nm = "DailySheet"
datestr = Format(Now, "yyyymmdd")
rev = 0
'Create new Windows Shell object
Set ws = CreateObject("Wscript.Shell")
'Check the latest existing revision number
Do
rev = rev + 1
chk_fil = ws.Exec("powershell test-path " & path & "\" & sht_nm & "_" & datestr & "v" & Format(rev, "00") & ".*").StdOut.ReadLine
Loop While chk_fil = True
'Save File with new revision number
ActiveWorkbook.SaveAs path & "\" & sht_nm & "_" & datestr & "v" & Format(rev, "00") & ".xlsm"
End Sub
If you have the current filename I would use something like:
Public Function GetNewFileName(s As String) As String
ary = Split(s, "v")
n = "0" & CStr(CLng(ary(1)) + 1)
GetNewFileName = ary(0) & "v" & ary(1)
End Function
Tested with:
Sub MAIN()
strng = GetNewFileName("DailySheet_20150221v02")
MsgBox strng
End Sub

How to make Looping and Calculate formula from another workbook without open file

I want to ask how to do this from vba code
Workbook 1 contain cell A, cell B, cell C
Workbook 2 contain Cell D
each cell contains number value
Cell D = (Cell A - Cell B) * Cell C
i want to calculate and just return value to cell D in workbook 2, Here my code snippet
Dim path As String
Dim workbookName As String
Dim worksheetName As String
Dim cella As String, cellb As String, cellc As String
Dim returnedValue1 As String, returnedValue2 As String, returnedValue3 As String
Dim Hasil1 As Long
path = "D:\"
workbookName = "Workbook1"
worksheetName = "Daily"
cella = "F7"
cellb = "E7"
cellc = "D7"
returnedValue1 = "'" & path & "[" & workbookName & "]" & _
worksheetName & "'!" & Range(cella).Address(True, True, -4150)
returnedValue2 = "'" & path & "[" & workbookName & "]" & _
worksheetName & "'!" & Range(cellb).Address(True, True, -4150)
returnedValue3 = "'" & path & "[" & workbookName & "]" & _
worksheetName & "'!" & Range(cellc).Address(True, True, -4150)
Worksheets("Workbook2").Cells(D).Value = CLng(ExecuteExcel4Macro(returnedValue1) - ExecuteExcel4Macro(returnedValue2)) * ExecuteExcel4Macro(returnedValue3)
as far my code was good, but how to do it in one column, i have many cell beside just cell A. I want to calculate like this
Column D = (Column A - Column B ) * COlumn C
thanks for your answer..
Something like that (while row in column A is not empty, it populates your expression in column D):
Sub mmacro()
Dim path As String
Dim workbookName As String
Dim worksheetName As String
Dim cella As String, cellb As String, cellc As String, celld As String
Dim returnedValue1 As String, returnedValue2 As String, returnedValue3 As String
Dim Hasil1 As Long
Dim rownum As Integer
Dim A As Integer, B As Integer, C As Integer, D As Integer
path = "D:\tmp\"
workbookName = "Book2"
worksheetName = "Sheet1"
cella = "F"
cellb = "E"
cellc = "D"
celld = "A"
rownum = 3'Data starts in row 3 in my example
Do
returnedValue1 = "'" & path & "[" & workbookName & "]" & _
worksheetName & "'!" & Range(cella & rownum).Address(True, True, -4150)
returnedValue2 = "'" & path & "[" & workbookName & "]" & _
worksheetName & "'!" & Range(cellb & rownum).Address(True, True, -4150)
returnedValue3 = "'" & path & "[" & workbookName & "]" & _
worksheetName & "'!" & Range(cellc & rownum).Address(True, True, -4150)
A = CInt(ExecuteExcel4Macro(returnedValue1))
B = CInt(ExecuteExcel4Macro(returnedValue2))
C = CInt(ExecuteExcel4Macro(returnedValue3))
D = (A - B) * C
Worksheets("Sheet1").Range(celld & rownum).Value = D
rownum = rownum + 1
Loop While Not D = 0
End Sub
This is just example. It is needed to be refined
Further to my comment here is a faster method which DOESN'T use looping. Use ACE.OLEDB to read the 3 columns into a temp sheet and then perform the calculation. Yes, ACE.OLEDB will open the other excel file but it doesn't open it like Excel does.
Note: The below code uses Early binding and please set a reference to the ActiveX Object Data XX.XX Library.
Option Explicit
Sub Sample()
Dim sConn As String
Dim rs As ADODB.Recordset
Dim mySQL As String, sPath As String
Dim wsI As Worksheet, wsO As Worksheet
Dim wsILRow As Long, i As Long
'~~> Change this to the relevant Excel File
sPath = "C:\MyFile.xlsx"
'~~> Change connection string if the above is not xlsx
sConn = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & sPath & ";" & _
"Extended Properties=Excel 12.0"
'~~> Assuming that workbook 2 has sheet1 from where you want data
mySQL = "SELECT * FROM [Sheet1$A:C]"
Set rs = New ADODB.Recordset
rs.Open mySQL, sConn, adOpenUnspecified, adLockUnspecified
'~~> Create a temp sheeet to get the data from closed file
Set wsI = ThisWorkbook.Sheets.Add
'~~> Dump the data in the temp sheet
wsI.Range("A1").CopyFromRecordset rs
'~~> Close the recordset
rs.Close
sConn.Close
Set rs = Nothing
Set sConn = Nothing
'~~> Get last row from temp sheet
wsILRow = wsI.Range("A" & wsI.Rows.Count).End(xlUp).Row
'~~> This is where you want the output
Set wsO = ThisWorkbook.Sheets("Sheet1")
With wsO
'~~> Insert values in one go
.Range("D1:D" & wsILRow).Formula = "=(" & wsI.Name & "!A1 - " & _
wsI.Name & "!B1) * " & _
wsI.Name & "!C1"
'~~> Change formulas to values
.Range("D1:D" & wsILRow).Value = .Range("D1:D" & wsILRow).Value
End With
'~~> Delete tmep sheet
On Error Resume Next
Application.DisplayAlerts = False
wsI.Delete
Application.DisplayAlerts = False
On Error GoTo 0
End Sub