Using concatenated strings as a variable - excel

Evening you fine people!
I am struggling with a particular issue, there are two separate solutions that I have identified but I haven't specifically solved them
I have a list of 37 sheet names in a sheet (A1:A37) and the code I want to run is shown below - I don't know how to set 'z' to the particular cell reference - for example if A1 was Sheet1 I want Z to be Sheet1 and work as a variable. I am using a For loop to loop through the cells.
Workbooks("ED Test.xlsx").Sheets(z).Range("E2:E21").Value = Workbooks("TPT.xlsm").Sheets(z).Range("A2:A21").Value
The second method, more messy was to have the variables set within VBA and using the For loop (i.e. For x = 1 to 37) to concatenate the two values into a variable (e.g. "Sheet" and x) When I do this it gives a different error as it treats the concatenation as a string and not a variable
Please halp :)

You'll need a loop. If you are trying to set E2:E21 in each worksheet to whatever is in that same worksheet's (but in another workbook) range A2:A21 you will loop through those sheets and do pretty much what you have above:
Sub dothething()
Dim cellSheetName As Range
'loop through all the cells holding sheet names in sheet1 (assuming here)
For Each cellSheetName In Sheet1.Range("A1:A37").Cells
'Copy the values in whatever sheet we found
'Noting that the sheetname is held in the cell's value (cellSheetName.value)
Workbooks("ED Test.xlsx").Sheets(cellSheetName.Value).Range("E2:E21").Value = Workbooks("TPT.xlsm").Sheets(cellSheetName.Value).Range("A2:A21").Value
Next cellSheetName
End Sub
This could get more robust, but it's a good starting point.

Related

VBA Loop through named ranges - using Indirect on variants

I'm trying to loop through the multiple named ranges, every range is just one cell, on a column, so it starts with item1, item2...item100.Each of these ranges has a cell reference in it (like "AM100").
I want to be able to set up a for/while loop that just selects(and does something) each of the referenced cells in those named ranges.
I'm stuck at VBA not considering "item"&"1" the same with "item"&"i" when i =1 and from what I deduct this is purely a data type issue. It's able to refer to a pure string range but when it's variant/string type (which any concatenation of string or converted string variable results in).
item1 range has in it $AM$10 reference. That cell, has a value in it. Eventually I want to change the values in multiple similar cells by referring to the name ranges that hold their reference.
Without the "for" loop, I've tested the following:
Sub test()
Dim i as integer
i=1
'These don't work
Range([indirect("item"&CSTR(i))]).Select
Range([indirect("item"&i)]).Select
'What works is, but this is not useful since I want to loop through i:
Range([indirect("item" & "1")]).Select
Range([indirect("item1")]).Select
Sub Test()
Dim oDefName As Name
For Each oDefName In ThisWorkbook.Names
If Left(UCase(oDefName.Name), 4) = "ITEM" Then
Range(oDefName.RefersToRange.Value).Select
End If
Next
End Sub
Note: There is no error checking to ensure that the value within the named range is actually a cell reference.
Edit- Above is how I would solve the problem. Indirect is an in cell function and not usable directly in vba. Below is how you would get the indirect functionality in VBA with a counter.
Range(Range("Item" & oCounter).Value).Select

How to reference cells in other workbooks using a variable in the address

I need to use a variable in the cell addresses on two workbooks. This is how am getting started.
I'm checking the cells in column AE on the active workbook against the cells in column T on the master sheet and if there is a match I want to put a 1 in column T on that same row on the master sheet.
For x = 2 to 1000
If AE("X") = Workbooks(master.xlsx).I("X") Then Workbooks(master.xlsx).T("x"), 1, 0
Next x
When using VBA in Excel you have to remember that code is stupid - you need to explain exactly where everything is each time you want to reference it.
So, AE("X") can be translated by a human based on your descriptive text and looking at the rest of the code. VBA on the other hand will look at AE, realise it's not a codeword but is followed by brackets so will think it's some kind of array that hasn't been declared and start throwing all kinds of errors.
So, AE("X") is a cell in column AE on row X in a named worksheet in a named workbook in the Excel application. VBA knows something! It knows it's in Excel so we don't have to tell it each time - we have to tell it everything else though otherwise it starts making assumptions and generally gets it wrong.
So....
Your workbook is "Master.xlsx". This is a different workbook than the one the code is sitting in - it has an xlsx extension so can't contain any VBA code. The workbook is also open, otherwise you'd need to use the full path of the workbook and tell it to open it.
This code declares a variable called wrkBk and then sets it to reference the Master.xlsx workbook. As the file name is a string of text characters we need to place it within quotation marks. Now, whenever we need to reference the workbook we can just use wrkBk.
Dim wrkBk As Workbook
Set wrkBk = Workbooks("Master.xlsx")
If the workbook is closed you'd use
Set wrkBk = Workbooks.Open("<full path to workbook>\Master.xlsx")
There's a few special keywords you can use in place of Workbooks to reference specific open workbooks: Set wrkBk = ThisWorkbook will reference the workbook that your VBA code is in, Set wrkBk = ActiveWorkbook will reference whichever workbook is currently active.
The next step is to reference the correct worksheet within the workbook. We know the worksheet is going to be in the Master.xlsx workbook so that needs referencing - if we don't then the code will assume we mean whichever workbook is active when the code executes. Now, whenever we use wrkSht the code will know we mean Sheet1 that is in the Master.xlsx workbook (we don't use wrkBk.wrkSht as wrkSht already knows about wrkBk).
Dim wrkSht As Worksheet
Set wrkSht = wrkBk.Worksheets("Sheet1")
Right, now we're ready to reference the cells within the workbook. There's a number of ways to reference a cell - it's a Range of cells, so you could use wrkSht.Range("A1") for instance, it's also a cell on it's own, so you could use wrkSht.Cells(1,1) which means the cell at position row 1 and column 1, you could even use wrksht.Range(wrksht.Cells(1,1), wrksht.Cells(5,1)) which means a range of cells from row 1, column 1 to row 5, column 1. This could also be written as wrksht.Range("A1:A5"). Note - before each reference to a cell I'm telling it which sheet the cell is on.
Now, onto your loop and using X to reference the cell.
For x = 2 To 1000: Next x. That'll work and increase the value held by x.
You want to look at column AE - column 31 in numerical terms.
wrksht.Range("x") won't work as it will look at the literal string "x" and not the number that it stands for - the code also doesn't mention the column.
So wrkSht.Cells(x,31). There's no quotes around the x This will reference cells AE2, AE3, AE4, etc as your loop continues.
Finally, placing values in a cell - in plain English it's basically saying the value of referenced cell equals this value I'm giving it, or in VBA wrkSht.Cells(31,x) = 1
Your final code, with correct references set would like similar to this:
Sub Test()
Dim wrkBk As Workbook
Dim wrkSht As Worksheet
Dim x As Long
'Set reference to external workbook.
Set wrkBk = Workbooks("Master.xlsx")
Set wrkSht = wrkBk.Worksheets("Sheet1")
For x = 2 To 1000
'I haven't used variables here - just referenced the correct cells within the ActiveWorkbook.
'You may find it better to use ThisWorkbook instead.
'This is an IF...END IF block which allows you write multiple lines of code for each condition.
'For one line you could combine the first two lines in the block - but you wouldn't have the ELSE condition.
If ActiveWorkbook.Worksheets("Sheet1").Cells(x, 31) = wrkSht.Cells(x, 9) Then
wrkSht.Cells(x, 20) = 1
Else
wrkSht.Cells(x, 20) = 0
End If
Next x
End Sub
Hope that wasn't too wordy... started losing my way halfway through. :)

Excel VBA Evaluate Function Wrong When Reference is Not Active Sheet for Named Range

EDITED WITH BETTER EXAMPLE
I'm trying to use the Evaluate function to evaluate a formula reference for a named range. However, when using the Evaluate function, if you do not explicitly state the sheet reference along with the cell reference, it will assume the active sheet as the cell reference. This causes the wrong result
In my real project I'm trying to only evaluate a part of the named range's formula, so it makes it even trickier.
Using a basic example of what I'm trying to do, let's say you have the following formula in Sheet 1 cell A1 whose name is MyCell:
="Don't evaluate this part"&"My Result Is " & A2
If the Active Sheet is Sheet 2 and you run the following code it will give you the wrong results (this is a quick and dirty example to illustrate the problem)
Dim s As String
s = Replace(Range("MyCell").Formula, """Don't evaluate this part""&", "")
Debug.Print Evaluate(s)
Instead of giving me the value that is in cell A2 of Sheet 1, it gives me the value that is in cell A2 of Sheet2.
Any ideas around this?
This is closest I found, but it is not my exact problem (despite similar titles) and it doesn't provide a solution:
Excel VBA evaluate formula from another sheet
The problem you are having is that by design Excel will assume all unspecific cell references are referring to the existing worksheet. This is why whenever possible it is recommended to explicitly state the worksheet in all code.
The cleanest way (verified with some MSDN definintion hunting) is to just explicitly state the worksheet without activating it:
Sub test2()
Debug.Print Range("MyCell").Worksheet.Evaluate(Range("MyCell").Formula)
End Sub
Alternatively this code will change the active worksheet to the correct one and then change it back after evaluation. Not recommended to perform sheet activations like the code below without extenuating circumstances. Not even here.
Sub test()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim s As String
s = Replace(Range("MyCell").Formula, """Don't evaluate this part""&", "")
Range("MyCell").Worksheet.Activate ' Don't remember if .Worksheet or .Parent ??
Debug.Print Evaluate(s)
ws.Activate
End Sub
As pointed out in the comments by ThunderFrame, it is important to remember that this code assumes MyCell is a simple cell reference as stated in the question. Otherwise you will need to use other methods to determine the target worksheet name (or hardcode it).
Its nearly always better to use Worksheet.Evaluate rather than the default Application.Evaluate: as Mark Balhoff points out that allows you to control unqualified references.
But Worksheet.Evaluate is also usually twice as fast as Application.Evaluate.
See my blog post here for details
https://fastexcel.wordpress.com/2011/11/02/evaluate-functions-and-formulas-fun-how-to-make-excels-evaluate-method-twice-as-fast/
Your line:
Debug.Print Evaluate(Range("MyCell").Formula)
is equivalent to:
Debug.Print Evaluate("=""My Result Is "" & A2")
which is why you get results according to the value of A2 in the ActiveSheet.
If you want to inspect the contents of the formula, you can use this line:
Debug.Print [MyCell].Formula
If you want the value of MyCell with respect to Sheet1, then you have 2 options:
1 - Use Debug.Print Range("Sheet1!MyCell").Value
2 - Use Debug.Print Sheet1.Range("MyCell").Value

Excel 2007 Using the 'Find' function for a user-defined string, then copying the entire row for each occurrence to another sheet

I'm new to Excel VBA, and this is my first attempt to make a useful macro to speed up my work process.
What I'm trying to do
I have a data file of abut 15 thousand rows by about 15 columns. What I would like my macro to do is once I hit a button on a separate sheet, the code takes a string I have typed into a specific cell on that sheet, goes to the sheet with all of the data on, then uses the find function on one of the columns to find all instances of the string which I have defined.
Once all of the instances of the string have been located, I want to copy the corresponding rows and paste them into the sheet I ran the macro from.
To clarify, the column I want to locate the string in contains descriptions typed by people - there isn't just one word to look at; that is why I have been trying to use the Find function.
My attempt so far:
Sub FindTextBasicData()
'Define variables
Dim sourceSht As Worksheet
Dim outputSht As Worksheet
Dim strSearch As String
Dim searchRange As Range
Dim outputRange As Range
'Set the sheet variables to those present in the workbook
Set sourceSht = Sheets("Basic Data")
Set outputSht = Sheets("Output")
'Set the value of the string variable to the contents of cell C2 in the output sheet
strSearch = outputSht.Range("C2")
'Set the range variable to the range in the data sheet that I want to check
Set searchRange = sourceSht.Range("C6:C15448")
'Use the Find function to look through the range I defined and select all rows where the
'string variable can be found, setting the second range variable to these values
Set outputRange =searchRange.Find(What:=strSearch, After:=.Cells(3, 6), LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False).EntireRow
'Copy the results of the Find function to the clipboard
outputRange.Copy
'Select the 5th row of the output sheet as the location to paste the data, and then paste
outputSht.Select
Rows(5).Select
ActiveSheet.Paste
End Sub
I know that I'm definitely doing something wrong with the find function, but I can't figure the thing out - I think my problem lies with the After parameter in that it doesn't do what I think it does (references cell C6 as the place to start using Find from?). I tried looking at the guide to the Find function on Ozgrid, but I think I just confused myself more.
If I can get this macro to work correctly I will be able to use it a lot to vastly streamline the analysis of data that I have to do for these 15000 records. Any help for this would be greatly appreciated, and I'm of course happy to clarify if I haven't explained something well enough.
The reference .Cells(3, 6) needs to be qualified using a With block or just directly refer to a Worksheet or Range object. Easiest solution here would be sourceSht.Cells...
Also, Cells(3, 6) is cell F3 whereas you want cell C6. Put these together and you should therefore have After:=sourceSht.Cells(6, 3)
As mentioned above. You use dot operator in front of .Cells(3, 6) without With. The best way is to reference it to concrete sheet directly sourceSht in your case. If you want to reference to cell C6 then you can use for example :
sourceSht.Range("C6") or sourceSht.Cells(6,3) or sourceSht.Cells(3,"C") etc..
But I think that shouldnt cause problem (provided the reference is valid) because After parameter is not relevant (and optional) if all you want to do is search in the whole range. In fact only What is required parameter.
set outputRange = searchRange.Find(strSearch).EntireRow should do the trick. Moreover if you specify After parameter, the search doesnt look into that cell.
Anyway, this only gives you the first cell in the row in which the string was found. Not all of them. You might want to put the search code then into a cycle in combination with FindNext method or just using the After parameter of Find method.
Instead of the Range.Find method, use the Range.AutoFilter method to filter the rows on the first sheet based on the value on the second sheet, then copy only the visible rows. IMHO, this is better than the Range.Find method (which is still better than looping).
There are numerous examples on this site about how to copy visible rows to another sheet, here is one example: Excel Macros - Copy and paste filtered rows

How to use one column in excel as a search parameter in another column to output only certain strings

This question stems off another post I had. (see Search through column in excel for specific strings where the string is random in each cell)
Using the above image as reference, I am trying to search through column B (actually over 1000 lines) using column E as the "lookup values." The end goal would be for "just" the names to be displayed in column C. The trick is all the randomly generated characters the encompass the names. Below is what I would want the datasheet to look like. A formula or module should work, but the vlookup and other lookup function I can't get to work.
For a worksheet function approach, you could enter in C3 and fill down this formula:
=LOOKUP(8^5,SEARCH(E$3:E$7,B3),E$3:E$7)
The constant 8^5=32768 is chosen to be larger than the maximum possible string length so that LOOKUP returns the last matching value. The formula returns #N/A if no string is found.
Another possibility, which may be easier to understand then assylias post initially, but also may be a bit more time consumptive (although with 1,000 rows, I don't think it will matter much) is below.
This requires that you name the range in column E as myNames (or whatever name you wish, just update the code - alternatively, you cuold just write Range("E1:E6")). Also, if you move the random values from column B, update that in the code as well.
Sub findString()
Dim celString As Range, rngString As Range, celSearch As Range, rngSearch As Range
Dim wks As Worksheet
Set wks = Sheets("Sheet1") 'change sheet reference to whatever your sheet name is
Set rngString = wks.Range("myNames")
Set rngSearch = Intersect(wks.UsedRange, wks.Range("B1").EntireColumn)
For Each celString In rngString
For Each celSearch In rngSearch
If InStr(1, celSearch.Text, celString.Value) > 0 Then
celSearch.Offset(, 1) = celString.Value
End If
Next
Next
End Sub
Since, I worked on your original question as well, I would suggest getting the counts through Siddharth's answer and then running this, or assylias's code above to get the names next to the columns. You could put a button the sheet, or just use the Macro dialog box to run the macro.

Resources