Concatenating Variables Into String to be Set to a Range in VBA - variables

I am having a problem with a particular line of code:
ActiveSheet.Range("A" & rowCount & ":" & Mid(alphabet, totHdrLngth, 1) & belowRowCount)
Where alphabet is a string containing uppercase letters A to Z.
I keep getting the following error:
Run-time error '5':
Invalid Procedure call or argument
I tried creating a String "inRange" and changing the code to this:
inRange = "A" & rowCount & ":" & Mid(alphabet, totHdrLngth, 1) & belowRowCount
curRange = ActiveSheet.Range(inRange)
But that did not help (as I thought it wouldn't). Any suggestions?

Although creating ranges like this is frowned upon in general, the way to do it is with the word SET (like #Gary McGill stated in the comments). Here is an example of how to do this:
Sub test()
Dim alphabet As String
Dim totHrdrLngth As Long
Dim belowRowCount As Long
Dim rowCount As Long
Dim inRange As Range
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
totHrdrLngth = 5
belowRowCount = 10
rowCount = 5
' Gives us A5:E10
Set inRange = Range("A" & rowCount & ":" & range2 & _
Mid$(alphabet, totHrdrLngth, 1) & belowRowCount)
End Sub
You are running this macro in the current range, so there should be no need to specify ActiveSheet.Range. I hope this helps get you toward what you are trying to achieve.

As far as I can tell, you're getting an error because your types don't match up. I imagine rowCount is an integer, as is belowRowCount. If you convert them to strings before concatenating them, you can fix it. str() will convert an integer to a string with a space before it, and LTrim() will remove the space. Try code as below:
Dim sRowCount As String
Dim sBelowRowCount As String
and later
sRowCount = LTrim(Str(RowCount))
sBelowRowCount = LTrim(Str(belowRowCount))
inRange = "A" & sRowCount & ":" & Mid(alphabet, totHdrLngth, 1) & sBelowRowCount
curRange = ActiveSheet.Range(inRange)
Hope this helps.

Related

Inserting date as integer (Excel)

I have a vba code to concatenate a values from different columns. One of the columns; column M - is date, in format dd/mm/yyyy. I would like to concatenate the integer value of date of this with other values in cells.
I am trying to use Int(CDbl("date")) to convert the date value to int, then use that to concatenate with other cells.
My current vba code is:
Dim datevar As Integer
For i = 1 to LastRow
datevar = Int(CDbl(Sheets("Project_Name").Cells(i, 13).value))
target.location.formula = "=Project_Name!B" & i & "&UPPER(Project_Name!D" & i & ")&Project_Name!E" & i & "&Project_Name!F" & i & "&Project_Name!G" & i & "&Project_Name!H" & i & "&Project_Name!I" & i & datevar & ""
Next i
When I run this, I get a "Type Mismatch" error on the datevar = Int(CDb1(...)) line:
Can someone please advise why I am getting an error, and if there is a more efficient way of working?
EDIT
OKay - I get the error as CDbl cannot convert String to Double... However, the value in that cell is definitely a date and not string. What is the best way to counter this issue?
Working with dates, you better store their value to Double and not Integer.
Just use:
datevar = Sheets("Project_Name").Cells(i, 13).Value
You can add the following line to protect against none-integer values:
If IsNumeric(Sheets("Project_Name").Cells(i, 13).Value) And Sheets("Project_Name").Cells(i, 13).Value > 0 Then
Note: you can use Double or Long to store date values.
Integer is limited to values up to 32,767, read HERE.
If we look at today's date, Aug-17-2018 value is 43,329, which is over the Integer upper limit, that's why you are getting your error.
To follow up on our conversation in the comments, heres a quick little example of that idea:
Sub test()
Dim cellValue As String
Dim spaceSpot As Integer
cellValue = CStr(ThisWorkbook.Worksheets(1).Range("A1").Value) ' which is 12/22/2018
spaceSpot = InStr(cellValue, " ")
' Checking if date is in format 12/22/2018 00:00:00
If spaceSpot > 0 Then
cellValue = Left(cellValue, spaceSpot - 1)
End If
cellValue = Replace(cellValue, "/", "")
MsgBox cellValue ' shows 1222018
End Sub

Using Named Range and Variable to Define a Range

I have been trying to use a named range and variable to define a range that I want to autofill and I can only get one of the named ranges to work and not the variable in my code. The ColLetter variable is what is giving me trouble. If the I omit that variable and just put "AR" in the range the code works it is just not dynamic.
Sub test()
Dim lastRow As Long
Dim ColLetter As Range
lastRow = Range("D" & Rows.Count).End(xlUp).row 'Counts rows in specific column which controls how far to autofill.
ColLetter = Mid(ActiveCell.Address, 2, 2)
'Range("Notes_Start").AutoFill Destination:=Range("Notes_Start:AR" & lastRow) 'This works just is not dynamic. The AR for column is static.
Range("Notes_Start").AutoFill Destination:=Range("Notes_Start:ColLetter" & lastRow)
End Sub
A couple of problems, Dim ColLetter As Range should really be Dim ColLetter As String, your string concatenation is wrong, change Range("Notes_Start:ColLetter" & lastRow) to Range("Notes_Start:" & ColLetter & lastRow)
Be very careful using letters to define columns in your code.
If your active cell is A1, Mid(ActiveCell.Address, 2, 2)
yields A$, which is what you want.
If your active cell is AA1, Mid(ActiveCell.Address, 2, 2)
yields AA. You lose the $ and your reference is broken.
You would probably be better off using numerical references to columns:
Dim Col as integer
Col = ActiveCell.column
I'm not familiar with the Range("Notes_Start:..." syntax, but I believe that you could use Range("Notes_Start").Offset(lastrow,Col) to get what you're after. The Offset() may need a tweak of +1 or -1 to adjust to exactly where you need to be. Some quick trial & error will show exactly what you need to do.
You could use:
Dim adr() as string
Dim ColLetter as string
adr = split(ActiveCell.Address, "$")
ColLetter = adr(0)
But I'd still recommend using column numbers...

convert numeric to alphanumeric excel cell reference

How can I convert from numeric to alphanumeric cell references? For example, I have the numeric row,col(0,1) and I want to convert to a standard MS Excel alphanumeric col,row(B,1)? I'm sorry, but I don't know the proper terminology to describe different cell references.
I want to write VB.NET code with numeric cell references so my code can iterate but convert to alphanumeric so I can insert formulas into my spreadsheet.
To convert from a numerical column designator to a alphabetic designator, consider:
Sub qwerty()
n = 134
s = Cells(1, n).Address(0, 0)
MsgBox Left(s, Len(s) - 1)
End Sub
EDIT#1:
For a function to perform the conversion:
Public Function ColumnId(N As Long) As String
s = Cells(1, N).Address(0, 0)
ColumnId = Left(s, Len(s) - 1)
End Function
If you want to get the full address. Then you can just use the .Address property of a range.
If you want to separate the row and column then you can split the address into the individual parts using Split on the $.
Sub RangeAddressTest()
Dim cell As Range
Dim fullAddress As String
Dim rowAddress As String, columnAddress As String
Dim detailsArray As Variant
'select your cell
Set cell = ActiveSheet.Cells(30, 25)
fullAddress = cell.Address
detailsArray = Split(fullAddress, "$")
columnAddress = detailsArray(1)
rowAddress = detailsArray(2)
MsgBox "Full Address: " & fullAddress _
& vbCrLf & vbCrLf & _
"Column Address: " & columnAddress _
& vbCrLf & vbCrLf & _
"Row Address: " & rowAddress
End Sub
Thanks for your answers to my question, both seem like they should work but while looking around I found a very simple answer from the Aspose forum that gets the job done with two lines of code. Thanks for your ideas - I learn more by seeing different ways of getting to the same solution.
Aspose Forum:
As per my understanding, you wish to get the cells reference in the syntax of "A1" (Cell Name). You may consider using the following code snippet that returns the alphanumeric cell reference for cell[0,0].
VB
Dim r As Integer = 0, c As Integer = 0
Dim Cell As String = CellsHelper.ColumnIndexToName(c) + (r + 1)

VBA: Limiting cell range with functions

How do you write a function in VBA that lets the user enter a range as a parameter, and set the upper/lower bounds for that range (in case they enter a whole column)?
I have a function that looks at a cell and sees if it contains any words listed in a glossary (I just allow the user to select a column (range) that is the list of glossary terms. I currently use a for each cell in range loop to go through the range, but I don't want to waste steps going through ALL the cells in column A, even if I am checking first if Len(cell.value) <> 0.
I am guessing it's done with a select statement, but I'm now sure how to do that to a range that was passed as a parameter (I call it cell_range right now).
Any help would be greatly appreciated!
Added Info:
The data type of the range is of type string. It's a list of English words (glossary terms) and I am writing a function that will look at a cell and see if it includes any of the terms from the glossary. If it does, the code returns the glossary term plus the offset cell to the right (the translated term).
EDIT (06.20.11)
Finalized code thanks to experimentation and suggestions below. It takes a cell and looks for any glossary terms in it. It returns the list of terms, plus the translated terms (second column in glossary).
Function FindTerm(ByVal text As String, ByVal term_list As range) As String
Static glossary As Variant
Dim result As String
Dim i As Long
glossary = range(term_list.Cells(1, 1), term_list.Cells(1, 2).End(xlDown))
For i = 1 To UBound(glossary)
If InStr(text, glossary(i, 1)) <> 0 Then
result = (glossary(i, 1) & " = ") & (glossary(i, 2) & vbLf) & result
End If
Next
If result <> vbNullString Then
result = Left$(result, (Len(result) - 1))
End If
FindTerm = result
End Function
Why not limit your loop to the filled cells efficiently?
For Each c In Range("a:a").SpecialCells(xlCellTypeConstants)
....
Next c
To answer the direct question, you can't restrict what is passed as a parameter, but you can derive a new range from a passed range.
That said, looping through a range is very slow. There are may alternative methods:
Query based methods, as suggested by Remou
Copy the range to a variant array and loop through that
Dim vDat as variant
vDat = cell_range
vDat is now a two dimensional array
Use the built in search function Find
cell_range.Find ...
Use Application.WorksheetFunction.Match (and/or .Index .VLookup)
Which one best suits depend on the specifics of your case
Edit
Demo of the variant array approach
Function Demo(Glossary As Range, search_cell As Range) As String
Dim aGlossary As Variant
Dim aSearch() As String
Dim i As Long, j As Long
Dim FoundList As New Collection
Dim result As String
Dim r As Range
' put data into array
aGlossary = Range(Glossary.Cells(1, 1), Glossary.Cells(1, 1).End(xlDown))
' assuming words in search cell are space delimited
aSearch = Split(search_cell.Value, " ")
'search for each word from search_cell in Glossary
For i = LBound(aSearch) To UBound(aSearch)
For j = LBound(aGlossary, 1) To UBound(aGlossary, 1)
If aSearch(i) = aGlossary(j, 1) Then
' Add to found list
FoundList.Add aSearch(i), aSearch(i)
Exit For
End If
Next
Next
'return list as comma seperated list
result = ""
For i = 1 To FoundList.Count
result = result & "," & FoundList.Item(i)
Next
Demo = Mid(result, 2)
End Function
If you are confident there are no gaps:
''Last cell in column A, or first gap
oSheet.Range("a1").End(xlDown).Select
''Or last used cell in sheet - this is not very reliable, but
''may suit if the sheet is not much edited
Set r1 = .Cells.SpecialCells(xlCellTypeLastCell)
Otherwise, you may need http://support.microsoft.com/kb/142526 to determine the last cell.
EDIT Some notes on selecting the column
Dim r As Range
Dim r1 As Range
Dim r2 As Range
Set r = Application.Selection
Set r1 = r.Cells(1, 1)
r1.Select
Set r2 = r1.End(xlDown)
If r2.Row > Sheet1.Cells.SpecialCells(xlCellTypeLastCell).Row Then
MsgBox "Problem"
Else
Debug.Print r1.Address
Debug.Print r2.Address
End If
Set r = Range(r1, r2)
Debug.Print r.Address
However, you can also use ADO with Excel, but whether it will work for you depends on what you want to do:
Dim cn As Object
Dim rs As Object
Dim strFile As String
Dim strCon As String
Dim strSQL As String
Dim s As String
Dim i As Integer, j As Integer
Dim a As String
''It does not matter if the user has selected a whole column,
''only the data range will be picked up, nor does it matter if the
''user has selected several cells, except when it comes to the HDR
''I guess you could set HDR = Yes or No accordingly.
''One cell is slightly more difficult, but for one cell you would
''not need anything like this palaver.
a = Replace(Application.Selection.Address, "$", "")
''This is not the best way to refer to the workbook
''you want, but it is very convenient for notes
''It is probably best to use the name of the workbook.
strFile = ActiveWorkbook.FullName
''Note that if HDR=No, F1,F2 etc are used for column names,
''if HDR=Yes, the names in the first row of the range
''can be used.
''This is the Jet 4 connection string, you can get more
''here : http://www.connectionstrings.com/excel
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile _
& ";Extended Properties=""Excel 8.0;HDR=Yes;"";"
''Late binding, so no reference is needed
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon
''So this is not very interesting:
strSQL = "SELECT * " _
& "FROM [Sheet1$" & a & "]"
''But with a little work, you could end up with:
strSQL = "SELECT Gloss " _
& "FROM [Sheet1$A:A] " _
& "WHERE Gloss Like '%" & WordToFind & "%'"
''It is case sensitive, so you might prefer:
strSQL = "SELECT Gloss " _
& "FROM [Sheet1$A:A] " _
& "WHERE UCase(Gloss) Like '%" & UCase(WordToFind) & "%'"
rs.Open strSQL, cn, 3, 3
''Pick a suitable empty worksheet for the results
''if you want to write out the recordset
Worksheets("Sheet3").Cells(2, 1).CopyFromRecordset rs
''Tidy up
rs.Close
Set rs=Nothing
cn.Close
Set cn=Nothing

How do I get a range's address including the worksheet name, but not the workbook name, in Excel VBA?

If I have a Range object--for example, let's say it refers to cell A1 on a worksheet called Book1. So I know that calling Address() will get me a simple local reference: $A$1. I know it can also be called as Address(External:=True) to get a reference including the workbook name and worksheet name: [Book1]Sheet1!$A$1.
What I want is to get an address including the sheet name, but not the book name. I really don't want to call Address(External:=True) and try to strip out the workbook name myself with string functions. Is there any call I can make on the range to get Sheet1!$A$1?
Only way I can think of is to concatenate the worksheet name with the cell reference, as follows:
Dim cell As Range
Dim cellAddress As String
Set cell = ThisWorkbook.Worksheets(1).Cells(1, 1)
cellAddress = cell.Parent.Name & "!" & cell.Address(External:=False)
EDIT:
Modify last line to :
cellAddress = "'" & cell.Parent.Name & "'!" & cell.Address(External:=False)
if you want it to work even if there are spaces or other funny characters in the sheet name.
Split(cell.address(External:=True), "]")(1)
Ben is right. I also can't think of any way to do this. I'd suggest either the method Ben recommends, or the following to strip the Workbook name off.
Dim cell As Range
Dim address As String
Set cell = Worksheets(1).Cells.Range("A1")
address = cell.address(External:=True)
address = Right(address, Len(address) - InStr(1, address, "]"))
The Address() worksheet function does exactly that. As it's not available through Application.WorksheetFunction, I came up with a solution using the Evaluate() method.
This solution let Excel deals with spaces and other funny characters in the sheet name, which is a nice advantage over the previous answers.
Example:
Evaluate("ADDRESS(" & rng.Row & "," & rng.Column & ",1,1,""" & _
rng.Worksheet.Name & """)")
returns exactly "Sheet1!$A$1", with a Range object named rng referring the A1 cell in the Sheet1 worksheet.
This solution returns only the address of the first cell of a range, not the address of the whole range ("Sheet1!$A$1" vs "Sheet1!$A$1:$B$2"). So I use it in a custom function:
Public Function AddressEx(rng As Range) As String
Dim strTmp As String
strTmp = Evaluate("ADDRESS(" & rng.Row & "," & _
rng.Column & ",1,1,""" & rng.Worksheet.Name & """)")
If (rng.Count > 1) Then
strTmp = strTmp & ":" & rng.Cells(rng.Count) _
.Address(RowAbsolute:=True, ColumnAbsolute:=True)
End If
AddressEx = strTmp
End Function
The full documentation of the Address() worksheet function is available on the Office website: https://support.office.com/en-us/article/ADDRESS-function-D0C26C0D-3991-446B-8DE4-AB46431D4F89
I found the following worked for me in a user defined function I created. I concatenated the cell range reference and worksheet name as a string and then used in an Evaluate statement (I was using Evaluate on Sumproduct).
For example:
Function SumRange(RangeName as range)
Dim strCellRef, strSheetName, strRngName As String
strCellRef = RangeName.Address
strSheetName = RangeName.Worksheet.Name & "!"
strRngName = strSheetName & strCellRef
Then refer to strRngName in the rest of your code.
You may need to write code that handles a range with multiple areas, which this does:
Public Function GetAddressWithSheetname(Range As Range, Optional blnBuildAddressForNamedRangeValue As Boolean = False) As String
Const Seperator As String = ","
Dim WorksheetName As String
Dim TheAddress As String
Dim Areas As Areas
Dim Area As Range
WorksheetName = "'" & Range.Worksheet.Name & "'"
For Each Area In Range.Areas
' ='Sheet 1'!$H$8:$H$15,'Sheet 1'!$C$12:$J$12
TheAddress = TheAddress & WorksheetName & "!" & Area.Address(External:=False) & Seperator
Next Area
GetAddressWithSheetname = Left(TheAddress, Len(TheAddress) - Len(Seperator))
If blnBuildAddressForNamedRangeValue Then
GetAddressWithSheetname = "=" & GetAddressWithSheetname
End If
End Function
rngYourRange.Address(,,,TRUE)
Shows External Address, Full Address
The best way I found to do this is to use the following code:
Dim SelectedCell As String
'This message Box allows you to select any cell on any sheet and it will return it in the format of =worksheetname!$A$X" where X is any number.
SelectedCell = Application.InputBox("Select a Cell on ANY sheet in your workbook", "Bookmark", Type:=8).Address(External:=True)
SelectedCell = "=" & "'" & Right(SelectedCell, Len(SelectedCell) - Len("[" & ActiveWorkbook.Name & "]") - 1)
'Be sure to modify Sheet1.Cells(1,1) with the Sheet and cell you want to use as the destination. I'd recommend using the Sheets VBA name.
Sheet1.Cells(1, 1).Value = SelectedCell
How it works;
By Clicking on the desired cell when the message box appears. The string from "Address(External:=True)" (i.e ['[Code Sheet.xlsb]Settings'!$A$1) is then modified to remove the full name of the worksheet([Code Sheet.xlsb]).
Using the previous example it does this by taking the "Len" of the full length of;
[Code Sheet.xlsb]Settings'!$A$1 and subtracts it with the Len of ([Code Sheet.xlsb] -1). leaving you with Settings'!$A$1.
SelectedCell = "=" & "'" & Right(SelectedCell, Len(SelectedCell) - Len("[" & ActiveWorkbook.Name & "]") - 1)
The Code then its and "='" to insure that it will be seen as a Formula (='Settings'!$A$1).
Im not sure if it is only on Excel on IOS but for some reason you will get an Error Code if you add the "='" in any other way than "=" & "'" as seen bellow.
SelectedCell = "=" & "'" & Right....
From here all you need is to make the program in the Sheet and cell you want your new formula in.
Sheet1.Cells(1, 1).Value = SelectedCell
By Opening a new Workbook the full Code above will work as is.
This Code is Especially useful as changing the name of the workbook or the name of the sheet that you are selecting from in the message box will not result in bugs later on.
Thanks Everyone in the Forum before today I was not aware that External=True was a thing, it will make my coding a lot easier. Hope this can also help someone some day.
Why not just return the worksheet name with
address = cell.Worksheet.Name
then you can concatenate the address back on like this
address = cell.Worksheet.Name & "!" & cell.Address
Dim rg As Range
Set rg = Range("A1:E10")
Dim i As Integer
For i = 1 To rg.Rows.Count
For j = 1 To rg.Columns.Count
rg.Cells(i, j).Value = rg.Cells(i, j).Address(False, False)
Next
Next
For confused old me a range
.Address(False, False, , True)
seems to give in format TheSheet!B4:K9
If it does not why the criteria .. avoid Str functons
will probably only take less a millisecond and use 153 already used electrons
about 0.3 Microsec
RaAdd=mid(RaAdd,instr(raadd,"]") +1)
or
'about 1.7 microsec
RaAdd= split(radd,"]")(1)
[edit on 2009-04-21]
As Micah pointed out, this only works when you have named that
particular range (hence .Name anyone?) Yeah, oops!
[/edit]
A little late to the party, I know, but in case anyone else catches this in a google search (as I just did), you could also try the following:
Dim cell as Range
Dim address as String
Set cell = Sheet1.Range("A1")
address = cell.Name
This should return the full address, something like "=Sheet1!$A$1".
Assuming you don't want the equal sign, you can strip it off with a Replace function:
address = Replace(address, "=", "")