The true problem I'm trying to solve:
I've pasted text including formulas from one Excel workbook to another, but I don't want to reference the old workbook in the formulas
The question I'm asking:
How can I find and replace (or similar results) references to an old workbook, where I want formula to instead reference (identically named) internal data table? I want to replace the values within a formula, but my best guess is that Excel is having a problem with some kind of special character
Sample:
The following is formatted as a data table named "Data" in "MyOldWorkbook.xlsx" and "MyCurrentWorkbook.xlsx"
ColRowNum
ColAmt
1
5
2
10
3
5
The original/desired formula: =COUNTIFS(Data[ColAmt],"<=10")
The unwanted formula when pasted: =COUNTIFS('MyOldWorkbook.xlsx'!Data[ColAmt],"<=10")
Notes:
The sample is overly simplistic. The easiest thing to do is manually just deleted out the unwanted text, but I'm looking for the systematic solution.
I feel like I'm missing some "escape" character command/grep thing/something in the find & replace dialogue.
Fails
If I try to put into the Find and Replace dialogue box(es) Find: 'MyOldWorkbook.xlsx'! and replace with "" (actually blank), I get an error.
If I try to shorten it (remove the !) I get an error about how excel has broken formulas (true) and refuses to find/replace for me
Can't break the external links, since that converts my formulas (formula, in this simple example) to numbers
UPDATE I've encountered this issue before and didn't have a solution other than manually fixing the text. When I was replicating the problem to a colleague, the above find-and-replace method actually worked. I don't think this has ever worked for me before. Does anyone have any ideas????
Sort of not-a-terrible-Solution: Use a Formula
As I'm posting this, stackoverflow tried to see if my question was answered before and it got me thinking which got to a solution that isn't horrendous, though I was hoping to use the GUI find/replace feature:
A1 (formula): =COUNTIFS(Data[ColAmt],"<=10")
B1 (text): 'MyOldWorkbook.xlsx'!
Use this formula in C1 =SUBSTITUTE(FORMULATEXT(A1),B1,"")
Copy and paste-vales from C1 into D1
Done
Terrible (but relatively functional) solution: Paste As Text etc.
Format formula cell as TEXT (or paste formula in a cell formatted as text)
Find/Replace "=" with "" to remove Excel thinking it's a formula (or otherwise remove "=")
Find/Replace "'MyOldWorkbook.xlsx'!" with ""
stitch back formula in some way and copy text back to original formula cell
You can programmatically remove references to different workbooks in Excel formulas using either a macro or VBA script.
You can loop through all of the cells in a worksheet and modify the formulas to remove any references to external workbooks. I have created an example below:
Sub remove_external_references()
Dim cell As Range
Dim ws As Worksheet
Set ws = ActiveSheet 'Change to the desired worksheet
For Each cell In ws.UsedRange
If cell.HasFormula Then
cell.Formula = Replace(cell.Formula, "[", "")
cell.Formula = Replace(cell.Formula, "]", "")
End If
Next cell
End Sub
This script uses the Replace function to remove any square bracket characters "[" and "]" from the formula, which are typically used to indicate a reference to an external workbook.
You could of course change it anyway you want to, for example: cell.Formula = Replace(cell.Formula, "'MyOldWorkbook.xlsx'!", "")
Additionally, you can use the Workbook.LinkSources property to get the list of external links for a workbook, and use the Workbook.ChangeLink method to update the references.
Related
I've had a scroll through most of the SUMIFS questions here and they all seem to be variations of double quote problems, as opposed to what I'm getting.
I'm trying to insert sumifs into a table which is triggering runtime error 1004. The sum range, and the three criteria ranges are all in a different table (on a different tab, though that shouldn't make a difference), and the three criteria are all in the table where the formula is being entered. The first critera is the row header, the other two are other cells in the same row. Within the code, the table where the criteria are, and the formula is being entered is in a ListObject variable (summary_table) and the sum and criteria ranges are in a different ListObject variable (data_table)
Code is as follows:
For i = 5 To summary_table.ListColumns.Count - 1
summary_table.ListColumns(i).DataBodyRange.Formula = _
"=SUMIFS(data_table[Amount],data_table[FOCUS GLs],summary_table[[#Headers],[" & _
summary_table.HeaderRowRange(i).Value & "]],data_table[Employee Number]," & _
"[#[Position Number]],data_table[Posting Date],[#[Posting Date]]"
Next i
Basically, just looping through the fifth column through to second last and inserting this sumifs formula in. This is then within a larger loop that goes through 40 or so entities. The summary_table is a listObject variable pass to this particular sub.
If I put a debug.print statement in to look at the actual formula string that is being produced, and copy that into the table, the formula works fine.
If I built a sub-routine that puts the sum range and the three criteria ranges into range variables, and the three criteria into three long variables, then loop through each range in each listColumn.DataBodyRange and enter in the result of calling Application.WorksheetFunction.SumIfs(sum_range, crit_range1, crit1 etc...), that will populate the cells with the correct value.
However, this takes 10-20 second per entity for which this is being done, adding 7-15 minutes to the running time. If the formula in the code block worked, it should only be a few milliseconds. Additionally, if someone updates the data table (which is unlikely, but possible), the lack of a formula means the summary table will no longer hold the correct value.
I cannot for the life of me work out why it is not working and would appreciate any comments, observations, thoughts or general abuse.
I suggest you apply a few basics. That will make your formula easier to read. Once it's easier to read I would attempt to do so. But if it were easier to read you probably wouldn't need my help. So, let's apply basics.
A ListObject as a Range, ListRows and ListColumns. It also has Header and Total rows which are included in the Range.
A ListObject's DataBodyRange excludes the headers and totals. It's nothing but a named range. In fact, the name for it is set up by Excel to be the same as the table's. Since it's a range it has rows and columns which you can address by their range (DataBodyRange) or sheet coordinates.
Therefore one wouldn't use ListRows or ListColumns to address DataBodyRange rows and columns. Your code would become a lot simpler if you were to use With summary_table.DataBodyRange to start the show off.
A SUMIFS function has these arguments:-
= SUMIFS(SumRng, Crit1_Rng, Crit1, Crit2_Rng, Crit2, etc)
Therefore, once you hit a problem - and a problem you did hit - you should resolve all arguments. Then your code would look somewhat like this:-
Dim Formla As String
Dim SumRng As Range
Dim Crit1_Rng As Range
Dim Crit1 As Variant
Dim Crit2_Rng As Range
Dim Crit2 As Variant
Formla = "=SUMIFS(" & SumRng.Address & _
"," & Crit1_Rng.Address & "," & Crit1 & _
"," & Crit2_Rng.Address & "," & Crit2 & ")"
True, your code looks a lot more compact and uses fewer characters but it also brought you to this forum. Set SumRng = data_table[Amount] allows you to check Debug.Print SumRng.Address, a luxury you have denied yourself by design. And please don't believe that your code would run faster because it doesn't need to assign the range to a variable. It will have to do that whether you instruct or not.
Now all that remains is to assign the formula. You suggest summary_table.ListColumns(i).DataBodyRange.Formla. But wouldn't that assign the same formula to every cell in the DataBodyRange? If you want to assign the formula to all cells in one column your syntax should look somewhat like this:-
summary_table.DataBodyRange.Columns(i).Formula = Formla
Of course, this doesn't address the question of absolute and relative referencing. But in the logically structured approach that I have recommended above you would solve that when you assign the ranges, perhaps using Address(0, 0) in place of the naked Address I showed above, setting the formula for a single cell and then copying that cell to the rest of the column. But you can also use structural referencing, perhaps by using string variables in place of the ranges I showed above. Once the toys are all laid out you can start playing with them.
For those of you playing along at home (and I suspect it's only me, but there's a useful lesson in this anyway), I finally found the answer to the problem, and it's as stupid a minor detail as is always the case. I decided that VBA didn't like SUMIFS formulas split across two tables on two different sheets, so decided to change it to cell references. (For the record, VBA is fine with formulae across multiple tables on multiple sheets, but it at least led me down the right path).
Now, the default A1 reference style is a thing of beauty when working directly in the Excel spreadsheet, but it's disgusting to code with (getting the .address variable and splitting on $ is just unnecessary code - great if you're being paid by line of code, but just nasty to work with and worse to maintain). So I used R1C1 reference style. Still wouldn't work in the VBA code, but if I debug.printed the formula out and copied and pasted, it was fine. But, R1C1 formulae tend to be much shorter, so I could compare the debug.print text, copy and paste it just under where I had the formula I'd built in Excel as a comment straight under each other on a single line, and lo and behold:
'=SUMIFS(Data!R2C17:R777C17,Data!R2C1:R777C1,R1C,Data!R2C13:R777C13,RC1,Data!R2C16:R777C16,RC4)' '=SUMIFS(Data!R2C17:R777C17,Data!R2C1:R777C1,R1C,Data!R2C13:R777C13,RC1,Data!R2C16:R777C16,RC4
"Close your (expletive deleted) brackets, Yianni!!!"
And of course, Excel somewhere around the 07 release decided that if a simple, non nested, single bracket formula was missing the last bracket, it would just add it when you hit enter, so pasting the incorrect formula in Excel worked because it corrected it for me...
So, the takeout from this is something I should have known all along - R1C1 reference style is always the answer in VBA if at all possible, it's just this particular case needs table reference formulae instead.
Two questions 1) Can I autofill logical formulas to a cell using VBA and how (there is something wrong with my code) and 2)Can I autofill it only when data is entered and how?
The formula I want to put works when I put into a a cell but not VBA:
=IF(ISNUMBER(SEARCH("$",$A2)),"Scanner 2",IF(ISNUMBER(SEARCH("#",$A2)),"Scanner 1","Error"))
For the VBA I also used Relative Coordinates, did not work:
Range("C2").Value="=IF(ISNUMBER(SEARCH('$',RC[-2])),'Scanner 2', IF(ISNUMBER(SEARCH('#',RC[-2])),'Scanner 1','Error'))"
Pictures that may help:
The problem is a combination of the use of single quotes + you didn't add as . Formula:
So:
Range("C2").Formula = "=IF(ISNUMBER(SEARCH(""$"",$A2)),""Scanner 2"",IF(ISNUMBER(SEARCH(""#"",$A2)),""Scanner 1"",""Error""))"
Should work
Also, I see in your code you are using .Select, there are many ways to avoid using this. Check this link.
The below example will do the same thing:
With ThisWorkbook.Sheets("Sheet1")
.Range("C2:C100").Formula = "=IF(ISNUMBER(SEARCH(""$"",$A2)),""Scanner 2"",IF(ISNUMBER(SEARCH(""#"",$A2)),""Scanner 1"",""Error""))"
End With
You'll notice Excel will auto-adapt the formula to the correct cell references.
I'm trying to get rid of #NAs in excel, I've tried using the VLOOKUP formula but it doesn't seems to be working in my case. I just have one cell from A1:A18, and two of the cells contains NAs, I was wondering what the VLOOKUP formula would be like to get rid of those cells.
Use the formula =IFNA(A1,"") in an adjacent column and copy downwards. The second argument of this function is the value that you want to replace a cell containing #N/A with. I've chosen a blank string, but you could use 0, &c.
On older versions of Excel (prior to the 2013) release, use =IF(ISNA(A1), "", A1)
Then perform the rest of your analysis on that newly created column.
I dislike removing the #N/A cells as that can destroy the structure of your workbook, and using VBA to remove them is inherently buggy since #N/A propagates through built-in Excel functions.
In general:
Select A1:A18
Run the following:
Sub InsertIFERROR()
Dim R As Range
For Each R In Selection.SpecialCells(xlCellTypeFormulas)
R.Formula = "=IFNA(" & Mid(R.Formula, 2) & ","""")"
Next R
End Sub
It is a bit dangerous, because you will not see #NA errors and you cannot revert the formulas with Ctrl+Z.
How does one cell obtain the formula of another cell as text without using VBA? I can see this question has already been asked many times and the answer is always to write a custom function in VBA.
However, I found a post made in 2006 which claimed to have found the non-VBA solution but the link provided in that post is already broken.
=FormulaText(Reference) will do the trick Documentation
There is nice way of doing this without VBA. It uses XL4 macros (these are macros, but it is not VBA, as asked).
With reference to the figure 1, cells A2:A4 contain usual formulas.
Going to Formulas -> Define Name, I defined two named ranges (see fig. 2), with the information shown in cells A6:B8.
Enter in cell B2 =FormulaAsText. This will retrieve the formula in cell A2 as text.
Explanation:
The named range FormulaAsText uses =GET.CELL(info_type,reference). In this case, ìnfo_type = 6 retrieves the formula, and reference = OFFSET(INDIRECT("RC",FALSE),0,-1) uses the cell with 0 rows and -1 columns offset from the one the formula is used in.
Copy B2 and paste into B3:B4. This will show formulas in A3:A4. Cell A4 shows that the worksheet function CELL only retrieves values, not formulas (as opposed to GET.CELL).
Since FormulaAsText gets the formula from a cell at fixed offset (0,-1) from the current, I defined another range FormulaAsText2, which uses an offset (rows,cols) read from the worksheet itself. Cells D2:D4 contain =FormulaAsText2. Thus, cell D2 shows the contents of cell B3 (=OffSET(D2,1,-2)), which is FormulaAsText. cells D3:D4 show the contents of themselves. This adds some flexibility. YMMV.
PS1: The essence was taken from
http://www.mrexcel.com/forum/excel-questions/20611-info-only-get-cell-arguments.html
PS2: Tim Williams mentioned in a comment "the old XLM GET.FORMULA()". This answer is possibly related (not the same, since this one uses GET.CELL()).
PS3: A simple VBA solution is given, e.g., in
http://dmcritchie.mvps.org/excel/formula.htm
EDIT: Complementing this nice answer, the worksheet function FormulaText is available for Excel 2013 and later.
This suggestion may be helpful for those who after retrieving a block of formulas and transporting them to a new spreadsheet want to put them to work again. Excels FORMULATEXT function is great for picking up formulas but it leaves them as unusable text strings. If you want to get them back as fully functioning formulas you have to edit each one individually to remove the string character, but here is a shortcut for larger blocks.
Get to the position where you have the required formulas as text (in other words after using FORMULATEXT - you have done a copy and (value only) paste). The next step involves highlighting all the cells you want to convert and then navigating to the [Text-To-Columns] menu option ({Data} bar on Excel 2016). You can select 'Delimited' but on the next screen just make sure you de-select any marks that do appear in your formulas. Then 'Finish'. Excel should automatically analyse the cells as containing formulas and you should now have them working again.
There is a way to do this. In my example I had a table that showed a date. The date comes from Sheet!G91. In my table I also had a column that showed the sheet name. I added two more columns to my table. The first column had column(Sheet!g91), which returns the number 7, because G is the seventh letter in the alphabet. I then converted the number to a letter (G) using another table in my workbook. In the second column that I added, I made a formula row(Sheet!G91), which returns the number 91. Note: Row and Column may appear as volatile formulas, which recalculate with every calculation of the workbook.
I wanted another column to show the formula contents of the date cell mentioned at the beginning of this post. I included the following string function (you can also use CONCATENATE).
"=" & AJ9 & "!" & AM9 & AN9
The items separated by ampersands get strung together (that is, concatenated). AJ9 in my example contains the sheet name, AM9 contains the column letter, and AN9 contains the row number.
I now have a column that dynamically updates its contents to reflect the sheet name and cell reference. The results in my workbook cell are
=Sheet!G91.
You can't. This is most likely a design choice to eliminate an average Excel user from accidentally getting something they did not want.
What you are reading is correct - writing a UDF is the solution you want.
How do I replace the formula in a cell with the output of the formula?
I simply need "=RIGHT(E86,LEN(E86)+1-FIND("(",E86,1))" to become "(e)"
Is there a way to do this to the whole sheet? Replace all the cells with formulas with the text they are displaying? I am using version 2003.
Select the cells you want to replace and copy them. Then go to "Edit->Paste Special" and select values instead of all.
Since this doesn't change non-formula cells, you could select the entire sheet and copy->paste special to remove all formulas.
To do it programatically, look at Steve's answer. He's got the code you'll need.
Alternatively something like the following will work if you want to avoid using the clipboard
Dim r as range
For each r in Worksheets("Sheet1").UsedRange.Cells
r.Value = r.Value
Next
I haven't excel to hand I'm afraid so you'll need to check the syntax.
Another way to do it: double-click the cell in question and press F9.