Replace part of formula - vba

my macro is deleting some spreadsheet (let's call it "Base") and replacing it with similar, same name and format, but with different data. There are formulas in other sheets which are refering to "Base" spreadsheet. This formulas, after execution of the macro, return #ADR! error, and formulas are changed, for example:
=SUM(Base!AA:AA)
becames:
=SUM(#ADR!AA:AA)
I want to replace "#ADR" with "Base" in every formula, to get rid of this error. One of apporaches which I have been trying is:
Selection.Replace What:="#ADR", Replacement:="Base", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
but it doesn't work, even though when I am trying to do it manualy, using Ctrl+h shortcut, everything is perfect.
How can I replace "#ADR!" with "Base" in every selected formula using a macro?

=SUM(INDIRECT("Base!AA:AA"))
INDIRECT takes a string argument, so you will not lose the reference when the sheet is deleted.

When you delete the sheet you delete that entity. Although you then create a new sheet with the same name it is not the same entity.
So when you delete the sheet, formulas in other sheets referencing it lose that reference. Creating a new sheet with same name will never fix the links.
Would it not be simpler to overwrite the data in the Base sheet, therefore preserving all the links and eliminating the issue entirely?

Related

How to define 'Within' match criteria using VBA Find or Replace function?

There are similar questions regarding this, but none address my issue.
I have a tool that is basically a bulk find/replace. I define a set 'template' of data with keyword placeholders in it, then provide a list of template instance definitions that define values for these placeholders, and the tool simply copies the template as many times as I have template instances, and find/replaces the placeholders as it goes.
The find/replace code uses:
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
For iParam = LBound(gsaXMLParams) To UBound(gsaXMLParams)
Selection.Replace What:=gsParamSymbol & gsaXMLParams(iParam) & gsParamSymbol, Replacement:=gsaXMLParamVals(iInstance, iParam), LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Next
I only want to replace the current sheet. The trouble is, there is no 'Within' argument in the Replace function, and instead the replace function uses the currently set 'Within' criteria as set in the Excel Find/Replace tool. If this is set to 'Workbook', then all of my sheets have their cells replaced (if matching replace criteria).
I have tried using Range.Replace as well which produces the same issues.
How do I set the 'Within' criteria programmatically??
Example data:
E.g. Template:
|Area|.|SiteName|.Metering.Value
|Area|.|SiteName|.Enclosure.Door
E.g. Template Instance Definitions
Area SiteName
Area 1 John's Town
Area 2 Peter's Town
E.g. Output
Area 1.John's Town.Metering.Value
Area 2.Peter's Town.Metering.Value
The 'within' you are speaking of is the Range.Replace Method's parent.
When you use Range("A1").Font.Color = vbRed, you are setting the color of the font of A1 so Color is a Property of Font and Font is a Property of Range, specifically, Range("A1").
So if you use the Worksheets("Sheet1").Cells.Replace what:=..., replacememt:=..., method, you are performing it on the cells in Sheet1, and only those cells just as setting the font color in the earlier example only set a red font in A1. Currently you are making the replacement on whatever is selected.
Doing a little more Googling, there doesn't look like there's a 'proper' solution, however using the first line of the following before any Replace calls will reset the Find/Replace tool options, including resetting Within to 'Sheet':
Set r = Worksheets(1).Range("A1").Find(What:="This will reset the Find/Replace tool options, including setting Within=Sheet")
Range("A1:B10").Replace(.....)

Finding function next value in a specific column

I am trying to make a macro button that will automatically select column H and then search and select one by one in an array(one every time I click the macro) every cell in that specific column, that contains the € symbol. I can do that exactly as I want manually using the native excel search function but it is time consuming. Yet I don't know how to do that in VBA. Note that the cells in column H are currency formatted..The code that almost works for me so far is this:
Search = InStr(ActiveCell.NumberFormat, Chr(128))
Selection.Find(What:=Search, After:=ActiveCell, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
BUT the above code doesn't automatically select column H for search. I have to do that manually. When i insert in the above code Columns("H").Select (in order to make the code select the column H automatically) the macro selects the first cell that contains the € symbol in the column H (which is what i want) BUT when clicking again it does not go to the NEXT cell that contains the € symbol in that column. It sticks on the first finding. Could you please help me?
You should always avoid using Selection. or .Select.
Instead of Selection.Find specify the correct range:
Worksheets("MySheetName").Columns("H").Find
Also have a look at the Range.FindNext Method (Excel). With find you will always find the first occurrence only. For further searches you will need to use FindNext.
I am not sure what do you want to achieve, but if you need to find cells formatted as Currency, I would rather use this code:
Sub findCur()
Dim rngCol As Range
Set rngCol = Range("H:H")
With Application.FindFormat
.Clear
.NumberFormat = "$#,##0.00"
End With
rngCol.Find(What:="*", After:=ActiveCell, SearchFormat:=True).Select
End Sub
Add a condition to the selection, something like:
If Selection.Column<>7 then Columns("H").select
This way if you are already in column H, it won't reselect it, but if you are not there, it will go there.

Inserting, searching, copying, pasting across 2 spreadsheets in Excel

I thought I'd be able to figure this out based off an analysis of similar code we had written for something else, but code isn't my forte.
Diving into VBA without guidance has proved to be too daunting for me to proceed.
Forgive my terminology if I use the wrong language, I'm happy to learn and be corrected.
This shouldn't be difficult for someone that knows what they're doing, I just don't at all.
I'm trying to create a macro enabled workbook that does the following:
Open "Data.csv" from a folder called "Data" in the same directory as the macro. We'll call this workbook A - wbA.
Insert a column on wbA after Column C titled "Group Image Name." This Column D is where we want data to end up.
Open "Groups.csv" from a folder called "Groups" in the same directory as the macro. We'll call this workbook B - wkB.
(This next part needs to be a loop that starts at C1 on wbA and proceeds down the column until the end of the spreadsheet)
Copy value from selected cell in Column C on wbA
Search Column C on wbB for copied value. When found, move selection over to corresponding cell in Column A. (If C2, then A2)
Copy contents of the column A value from wbB to column D cell on wbA that corresponds to the original starting point on wbA.
Basically in plain language: Search for Column C contents from wbA on Column C of wbB. When found, move to Column A of same cell # on wbB, copy contents, and paste into cell # of Column D on wbA that corresponds to cell # of starting point from Column C.
I hope that's clear; please feel free to ask for more details if necessary. Thanks for anyone's help in advance!
Here is my terrible code I'm working with at the moment:
Sub OpenDataAddGroupImageTitleColumn()
ChDir "C:\[RealCodeHasCorrectFilepath..]\Desktop\TEST"
Workbooks.Open Filename:="C:\[RealCodeHasCorrectFilepath..]\Desktop\TEST\DATA.csv"
Columns("D:D").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Cells.Select
Cells.EntireColumn.AutoFit
Range("D1").Select
ActiveCell.FormulaR1C1 = "Group Image Title"
Range("C2").Select
'Variables for storing Row, Column Location, and Value here
Dim GROUPNAME As String
Dim RowLocationX As Long
Dim ColumnLocationZ As Integer
GROUPNAME = ActiveCell.Value
RowLocationX = ActiveCell.Row
ColumnLocationZ = ActiveCell.Column
Workbooks.Open Filename:="C:\[RealCodeHasCorrectFilepath..]\Desktop\GROUPS.csv"
Columns("C:C").Select
Selection.Find(What:="GROUPNAME", After:=ActiveCell, LookIn:=xlFormulas, LookAt _
:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False).Activate
End Sub
The current snag I can't figure out after much googling is this: Is it possible to search for my variable GROUPNAME using the Find/Replace feature? Or should I be taking a different approach using something involving copying to clipboard?
The first problems that I see are:
1) You don't put functions in the middle of sub routines. If you want a function, you put it on its own as such:
Sub MySub()
'Do Stuff
x = myFunction()
debug.print x
End Sub
Function MyFunction() As String
'Do Stuff
MyFunction = "Test"
End Function
2) The code you have provided won't compile for reason 1 and also because you have ended the Sub with "End Function" instead of End Sub. Try running the code and you will get error messages. Then you can research the error message and try to fix it. Further, if you don't get error messages, you can step through the code to make sure it is working the way you intend it to.
3) The very first line isn't going to work. You need to use the ENTIRE path of the file, even if it is in the same folder as the file you currently have open. There are ways to get the directory of the file you currently have open (google will surely show you many of them), and you could just append the filename to the directory of the file you have open.
4) You want a loop, but you haven't put in any looping structions. Google "Excel VBA loop through cells" and you can find many examples to use.
5) I think the biggest issue that you are having is that you are overwhelmed because you are trying to do everything all at once. I would suggest solving one problem at a time and then putting the code together. For instance, you want to open two files. Start by writing code just to open one file. Then try to get a value out of the file into the open workbook. Then open another file. Then get data out of that file. Then test looping through cells in the current workbook and checking for desired criteria and pasting the results if they match. Then combine all of these things into coherent code.
Nobody writes efficient code the first time they try, so even if you end up with really long code that isn't efficient, you'll learn a lot and have something. Even experienced programmers can get stuck or write code that doesn't work the first or even tenth time. If you get stuck, ask a specific question about a specific error message or specific issue that you can't resolve.

Excel VBA - Paste into Find Command

I'm trying to create a macro which searches for a string of text that has been entered/selected from another cell. When I record the macro, it sets the "What" part of the find function as the specific text that was copied when recording the macro, rather than a Paste Selection, which is what I want.
Sub GOTOSECTION() ' ' GOTOSECTION Macro '
'
Range("B7").Select
Selection.Copy
Cells.Find(What:="Section 4A", After:= _
ActiveCell, LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False).Activate
Cells.FindNext(After:=ActiveCell).Activate
End Sub
But I want the "What:" to be the value copied from cell B7. When I try to input a paste command in there it gives me a syntax error, so I'm sure it's something really basic I'm missing (I'm pretty green when it comes to vba, and I've been unable to find examples of what I'm looking for online).
Thanks for any input!
Replace What:="Section 4A" with What:=ActiveCell.Value
This will get the current value of the currently selected cell (though it might (though I'm not 100% sure without checking) cause some errors if the cell is blank, so consider error checking).
EDIT:
If you're continuing to use the macro recording in the future, it might be worth looking into relative references. I've never used it for anything like this, so I'm not sure if it will have an effect, but it could, so check it out.

Trying to merge columns together in Excel

I appreciate there are a lot of similar questions out there but I've been searching various forums for three days now and not yet found anything which does what I need - so either I'm doing something very strange or my searching skills aren't up to scratch!
I'd really appreciate it if someone could let me know where I'm going wrong, or even link me to a solution which might help as I haven't managed to find one.
I currently have a spreadsheet with six worksheets. Worksheets 2-6 contain data on items which have been sold from different sources. Worksheet 1 currently contains four columns which populate the item data using a macro I've cobbled together into four separate columns. Worksheet 2 contains an 'itemlist' column into which I want to copy the data from each of the four columns in worksheet 2.
I hope this makes sense. At the moment, the code I have is below:
Sub UpdateList()
'Clear the current ranges
Range("PharmacyItems").Clear
Range("PrelabelItems").Clear
Range("RestockItems").Clear
Range("TakehomeItems").Clear
Range("FullItemList").Clear
'Populate control with unique list
Range("PharmacyFullList").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("PharmacyItems"), Unique:=True
Range("PrelabelFullList").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("PrelabelItems"), Unique:=True
Range("RestockFullList").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("RestockItems"), Unique:=True
Range("TakehomeFullList").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("TakehomeItems"), Unique:=True
'Combine the four ranges into one
Range("UniqueLists!$A:$A, UniqueLists!$B:$B, UniqueLists!$C:$C, UniqueLists!$D:$D").Copy Sheets("Drug totals").Range("A2")
'Sort the data
Range("FullItemList").Sort Key1:=Range("FullItemList").Columns(1), Order1:=xlAscending, Orientation:=xlSortColumns, Header:=xlYes, SortMethod:=xlPinYin, DataOption1:=xlSortNormal, DataOption2:=xlSortNormal, DataOption2:=xlSortNormal
End Sub
In order to clarify the above, here is a definition of which range is which:
PharmacyItems, PrelabelItems, RestockItems and TakehomeItems: these are the individual lists which contain the unique items copied from each data worksheet.
FullList: the fulllist of the above four are the source data lists which are not unique lists
FullItemList: the column into which I want all the data from the unique lists to end up
The reason I have a range which specifies each column rather than using a named range is that I was trying to see if this would make it any better as originally it was just giving me a vague and fluffy range issue error. With the columns defined in the range it tells me the size/shape of the destination doesn't match the source.
The exact error is:
Run-time error '1004':
The information cannot be pasted because the Copy area and the paste area are not the same size and shape. Try one of the following:
- click a single cell, and then paste
- select a rectangle that's the same size and shape, and then paste
Can anyone help me? Sadly I'm a SQL Server girl, I'd far rather be pulling data from a database but I'm not allowed on this one!
Thank you in advance
Summer
You can't paste an entire column to a range starting on row 2 (or any other row than 1) because then the last row(s) of the column won't fit on the sheet. That's why Excel says "the Copy area and the paste area are not the same size".
Instead of
Range("UniqueLists!$A:$A, UniqueLists!$B:$B, UniqueLists!$C:$C, UniqueLists!$D:$D").Copy Sheets("Drug totals").Range("A2")
try pasting it starting on the first row.
Range("UniqueLists!A:D").Copy Sheets("Drug totals").Range("A1")
But I'm guessing you don't have data all the way down to the very bottom of your "UniqueLists" sheet? If so, then why are you copying the entire column? Just copy the part you need. Then you'll be able to paste starting on cell "A2". Example:
Range("UniqueLists!A1:D1234").Copy Sheets("Drug totals").Range("A2")
If you don't need the individual unique lists but just want to create a single column of all the unique values then this should work for you (untested though...)
Sub UpdateList()
Range("FullItemList").Clear 'Clear the full item list range
'Populate control with unique list
UniquesToFullItemList Range("PharmacyFullList")
UniquesToFullItemList Range("PrelabelFullList")
UniquesToFullItemList Range("RestockFullList")
UniquesToFullItemList Range("TakehomeFullList")
'Sort the data
Range("FullItemList").Sort Key1:=Range("FullItemList").Columns(1), _
Order1:=xlAscending, Orientation:=xlSortColumns, Header:=xlYes, _
SortMethod:=xlPinYin, DataOption1:=xlSortNormal, DataOption2:=xlSortNormal, _
DataOption2:=xlSortNormal
End Sub
Sub UniquesToFullItemList(rngFrom As Range)
rngFrom.AdvancedFilter Action:=xlFilterCopy, _
CopyToRange:=Sheets("Drug totals").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0), _
Unique:=True
End Sub