Indirect and Concatenate #ref error on *open* workbook - concatenation

I've been trying to find the answer to this, and the only results I'm getting are #ref errors on closed workbooks. I'm getting this error when the workbook I am referencing is open.
So here's what I'm doing - I'm trying to blend numbers daily from different banks from multiple worksheets with multiple tabs each. Since those worksheets have a date followed by a random ID number, we're going to just rename them to a set name (eg, "pmac") and dump each into a folder. Then, we'd open each one we want to blend, and I'll use "ISERROR" to turn any reference errors to blank so only the open workbooks are included in the blend (which I'll try to add as soon as I can get this indirect reference to work).
The team that would be using this is on a shared drive, so I decided to make some dynamic fields "RatesheetFolder" and "PennyMacFileName", so if we ever needed to move or rename stuff, we'd change it in one place instead of updating every formula.
So currently, my formula looks like this:
=INDIRECT(CONCATENATE("='"&RatesheetFolder&"["&PennyMacFileName&"]Conventional'!B"&ROW(B17)))
but it returns a #REF error. Everything I'm reading is saying that it's because the workbook is closed... but it isn't. It's open. If I copy and paste the value from the formula above into a cell, then THAT reference works... so the concatenation wasn't done incorrectly either, but for some reason it won't reference the open workbook.
I also tried doing the same thing, but on a local directory, in case the shared drive was an issue... same problem though. (for reference, here is the pasted value of the above formula)
='C:\Users\username\Documents\Reports\In Progress\[pmac.xlsx]Conventional'!B17
I also tried leaving out the folder path entirely, since I'd be dealing with open workbooks, and that also didn't work (copy/pasting values of the concatenated string still works, so again, it's not that it's written incorrectly). Also tried having both files in the same folder, no luck.
Any idea what's going on? Is it some kind of security thing that my company might be blocking the indirect reference or something? Maybe the way I'm using the row function?
I am using Office 2016.
Additional:
So, boiling things down to their absolute minimum....
=$B$2 returns the value in B2
=CONCATENATE("="&ADDRESS(2,2)) returns the text "=$B$2"
=INDIRECT("=$B$2") returns a #ref error
=INDIRECT("$B$2") returns the value in B2 (so only without the "=")
=INDIRECT(CONCATENATE("="&ADDRESS(2,2))) returns a ref error
=INDIRECT(CONCATENATE(ADDRESS(2,2))) returns the value in B2
Thinking it was the equals sign causing the trouble, I tried this:
=[pmac.xlsx]Conventional!B17 which returned the value from the other workbook
=INDIRECT([pmac.xlsx]Conventional!B17) still returns a ref error...
so I'm lost again.
I tried the last two things again, but with the full directory path (not just filename) and same thing - actually writing the direct reference out worked
='C:\Users\username\Documents\Reports\In Progress\[pmac.xlsx]Conventional'!B17
but the indirect reference didn't
=INDIRECT('C:\Users\username\Documents\Reports\In Progress\[pmac.xlsx]Conventional'!B17
Oddly - when I did the Indirect formula with the full path and hit enter it removed the full path and changed it back to just the filename (since the workbook was open):
=INDIRECT([pmac.xlsx]Conventional!B17)
but it still threw up a reference error. So it recognizes the workbook and that it's open... but it still gives an error trying to reference it. The indirect-concatenate does seem to work when I'm not referencing another workbook, so it does seem that's where the issue is... but I don't know why.

So I guess I found the answer after messing around with quotation marks and stuff in both the indirect formula and the concatenate formula.
To start, I realized that INDIRECT(B2) gave a ref error, while INDIRECT("B2") worked. So I went back through and tested a few things out making sure concatenate returned the exact right thing, and then surrounded that with an indirect formula.
So when I did =INDIRECT([pmac.xlsx]Conventional!B17) this didn't work because it wasn't a string. If I did =INDIRECT("[pmac.xlsx]Conventional!B17"), THEN it worked. Indirect requires it to be a string.
Looks like the problem was that Concatenate returned [pmac.xlsx]Conventional!B17 as text - but when I copy/pasted the VALUE that the concatenate formula returned, that then reverted the string back to a value, and stopped working inside the indirect formula.
What ended up working (and I swear I tried this already....) was:
=INDIRECT(CONCATENATE("'"&RatesheetFolder&"["&PennyMacFileName&"]Conventional'!B"&ROW($A17)))
I must have accidentally removed the single quote mark before RatesheetFolder when I removed the equal sign causing it to fail, and then every attempt after that was me trying to break it down into the individual parts, and unknowingly undoing the "string" property that concatenate applied whenever I pasted the result it into the indirect formula.
TL;DR of what I figured out
The Indirect formula requires it's contents to all be text/string
The results of Concatenate are returned as text/string, making additional quotation marks around those results redundant and cause an error
If you're referencing a cell directly, you need the equal sign
=B2, but if you're doing an indirect reference, you want to leave
the equals sign out of the indirect formula =INDIRECT("B2")
So putting that all together (in this example DynamicVar's value is simply the letter B) :
=INDIRECT("B2") works
=INDIRECT(B2) doesn't work
=CONCATENATE(DynamicVar & 2) returns B2 without quotations, but it's a string, so..
=INDIRECT(CONCATENATE(DynamicVar & 2)) works

Related

How to make Vlookup ignore blank cells while still checking to see if the ones with a value inside are correct

I am currently making a tardy counter system for my principal as of right now I am having issues with trying to make it so that whenever a new entry is put into the Datasheet it references to the ID sheet and checks to see if it's correct and if it is the cell next to it is blank if it is incorrect it should say error but every time when I try =IF(A2:A="","",ARRAYFORMULA(if(VLOOKUP(A2:A, ID!A1:A,1,FALSE)=A2:A, "", "error")))
it correctly checks but if any are wrong it outputs N/A I'm fine with that on the ones with a value in it but I need to get rid of the "N/A" corresponding to the blank cells
in summary, I need it to count the values that don't match the ID sheet as wrong rather than the blank cells as wrong
I tried multiple if functions but had no good results
also here is a copy
try:
=ARRAYFORMULA(IF(A2:A="","",IFNA(IF(VLOOKUP(A2:A,ID!A:A,1,)=A2:A,),"error")))
Have you tried the ISBLANK() function. Ex. IF(ISBLANK($A2),...
I got this working in google sheets, try it out:
=IF(isblank($A2),"", IF(IFERROR(VLOOKUP($A2, ID!A:A,1,FALSE)=$A2), "", "error"))

Array constant in a formula with non-adjacent cell references

I need to add an array of non-adjacent cells to my array formula. I have tried all of the following array constant-like ways and they all give me a "There is a problem with this formula error".
'Chart Data'!{A12:A14,D3:D11}
{'Chart Data'!A12:A14,'Chart Data'!D3:D11}
'Chart Data'!{A12,A13,A14,D3:D11}
{'Chart Data'!A12,'Chart Data'!A13,'Chart Data'!A14,'Chart Data'!D3:D11}
'Chart Data'!{A12,A13,A14,D3,D4,D5,D6,D7,D8,D9,D10,D11}
{'Chart Data'!A12,'Chart Data'!A13,'Chart Data'!A14,'Chart Data'!D3,'Chart Data'!D4,'Chart Data'!D5,'Chart Data'!D6,'Chart Data'!D7,'Chart Data'!D8,'Chart Data'!D9,'Chart Data'!D10,'Chart Data'!D11}
Entire formula (the array constant goes where the {#####} is):
{=SUM(((1-References!M1:M12)*({#####}*(G3:G14+F3:F14-0.11)))+((References!M1:M12)*('Chart Data'!A12:A23*(G3:G14+F3:F14-0.11)))+((H2:H13*X3:X14)+(H3:H14*Y3:Y14)+(I2:I13*(V3:V14-X3:X14))+(I3:I14*(W3:W14-Y3:Y14))))}
I am 100% positive that it is this particular array constant that is causing the problem. I can't move the cells I'm referencing to put them in line. Is it even possible to reference a non-adjacent range in an array formula? If it's possible, what am I doing wrong?
There are several ways to do this. The following is very simple and pretty direct so my favorite.
EITHER choose a cell to build your string for your non-contiguous array in OR create a Named Range to do it. I'll show the first as it seems nicest for being able to use the mouse freely, but in both of them you can actually be creative using about how you build the string that will become your array. The main advantage of creating it in a Named Range is no helper cell lying about anywhere.
So, you create that string and then make it an array. Say you have a non-contiguous array needed using cells A12:A14 and C3:C11. You use joining and TEXTJOIN() like so:
="{"&TEXTJOIN(",",FALSE,B12:B14,C3:C11)&"}"
to create a text string of the values in those cells wrapped with the curly braces ({}) just as if you'd typed it in ("hardcoded it"). It will look like this with the right values in those cells:
{1,2,3,1,2,3,4,5,6,7,8,9}
but is ain't an array yet.
Now the magic in THIS method. Create a Named Range, perhaps called String2Array, and give it a formula of:
=EVALUATE(A1)
(or whatever cell you used for the above formula creating the text string that you want to be an array). Make the reference absolute. ($A$1... which it will do for you, just don't edit it to be relative. If you use this for similar work, but need it relative, that will work fine, but it just isn't what is needed here.)
Now replace your placeholder in the formula with the Named Range's name (perhaps you DID use String2Array). And you're done.
A couple other methods use INDEX() or CHOOSE() and you can force things to be arrays using the functions DOLLARDE() and IMREAL() (I found on a helpsite in a 2014 post) and some others do the same kind of thing. In those days, one had to use {CSE} too, but SPILL takes care of that now (with those two weird-seeming friendlies and at least two others). The poster was someone I've seen on this site, EXCELXOR was the name for the site, XOR LX was the name of the member here though the functions were mentioned in a comment by a Lori. Since he covers, it seems, aspects not usually covered in helpsites, looking up some of his work here, or elsewhere too, might be worthwhile to some folks.
But this method is very direct and therefore easy to maintain. And personally, I love the idea that EVALUATE() (must be used IN the Named Range functionality, not cell-side) is the gift that keeps on giving, one wonderfully helpful thing after another.
So many ways. You could even literally build the array in a helper column/row somewhere and reference THAT instead of the non-contiguous addresses. I like the joining+TEXTJOIN() approach best because I can use the mouse to easily get all the blocks into the formula since it is a LIVE formula. But you can type out a string fairly easily too and add the {}'s. Or perhaps a user would type a string of addresses and you'd add them like the formula does above. And you can insert actual values (constants) into the string you are building as well if that is appropriate. And you could build it formulaicly... I wouldn't pick that workload first thing off the pile of choices, but if you were going to do it anyway already, then... or if it's a small build.

Variant array passed from UserForm to Module in VBA is null/empty

I have a UserForm with a ListBox for the user to select values. Those values are populated in UserForm_Initialize() via a function call to the base module, which returns an array as variant. This works without problems.
If the user selects some values and presses a button, the buttons Click event calls another function in the base module to pass on the user-entered array and compute things. This does not work at all. The value received in the base module is always nonexistent (not even null, but I don't know the correct VBA term, nothing is there at all).
Things I have tried so far:
Passing all arguments ByVal: Did not make a difference
Using global shared variables: This did work, but I don't want to rely on them if all I do is pass a single array to a single function. This also introduces state into the code which has to be managed, especially when reusing the function
Accessing the functions by full qualifiers: Did not make a difference. The functions are found and executed correctly, but the argument variables are empty, therefore the functions fail later on when doing the calculations.
My question is: How can I pass arrays from UserForms to Modules (not vice versa) without relying on global variables and without losing the array content?
This question may be related to this question about passing a String from Form to Module, but the accepted answer does not help in my case (using global variables).
When adding the code as requested in the comments, I stumbled upon that fact that I could print the content of the array, but it would not show anything in the debugger and the size would be 0.
The size issue was because I used Len(array) instead of Application.CountA(array) and I had a leftover On error resume next from earlier still in the code, which meant that no error was raised and size was always set to zero... This was the reason for the strange behaviour.

Error in google spreadsheet with arrays

In google spreadsheet I receive an error and it says, "Array result was not expanded because it would overwrite data in M261". I looked in M261 and it is a blank cell, but the weird thing is if I hit the delete button on the empty cell, then the error goes away. Sadly it keeps coming back. Is there a fix for this?
Here is my formula:
=ARRAYFORMULA(IF(E2:E>0,IF(D2:D=0,"Need Due Date",""),""))
I did not see "Array result was not expanded because it would overwrite data in M261" but at one point did see "...Add more rows".
One approach that should I think work is to restrict the output range of your formula. So for example if you wish it to apply to 100 rows, use:
=array_constrain(ARRAYFORMULA(IF(E2:E>0,IF(D2:D=0,"Need Due Date",""),"")),100,1)
However the problem you mention and the error message I saw are both because it is an array formula. There seems little need for it to be such and something like:
=if(and(D2=0,E2>0),"Need Due Date",)
is much faster, specially for a large number of rows, though unlike the array version does require copying down.

VBA Array - addressing to it by its name

this is a general VBA Array issue, it is not for MS Office apps (no tables involved).
I'm looking to find out how to create multiple one-dimension arrays at runtime (maybe even public ones), using data from a .csv file.
I can explain. This is an example of how the csv file would look:
------- CSV FILE ----------------------------
Colors,white,red,blue,green (... and so on)
Animals,cat,dog,wolf,bear (...and so on)
Food,cake,bread,garlic (...and so on)
...and so on, more rows
The opening part is solved,
even the part where each row is assigned to a temporary variable,
and more - the row is split into values and assigned to a temporary array.
So, I have:
tempArray1, containing ("Colors", "white", "red" ...etc)
tempArray2, containing ("Animals", "cat", "dog" ...etc)
...
The goal is to create (or to address to) an (existing) array
NAMED after the first value of each row and then assign the rest of the values from row to that array.
Please do not ask me why am I not using a multi-dimensional array.
I have my reasons.
A similar question related to this case is:
if I already have a one-dimension public array, defined, named and populated - let's say it is Colors() - how can I address to it using the value "Colors"?
Not only to address, but also to erase, redim or change values in it?
When I say "Colors" I mean a string value, not 'hard-coded' Colors() into the sub or function.
With respect to your "a similar question related to this case", you can do the following:
Create a public class module containing your array Colors()
Then, add a "Microsoft Script Control" ActiveX control (possibly to your form), and keep it hidden
Add code (as string) dynamically to your ScriptControl, and execute it. Now, if this code contains (as a string), say " Colors(1)="red" " , then it will actually modify the Colors array in your class-module.
Note: However, there's a catch. Since it is a class module, and not a
normal module, it will only modify the object created inside the
script-control. So, you might have to do all the rest of the coding
too in that script-control (by dynamically adding code to it and
executing it), otherwise, all changes would be lost as the scope of
that object would be limited to that code contained inside the
script-control

Resources