UPDATE TO THE BELOW
The update has now rolled out to lots of machines, and broken maybe 90% of the work we have done in the past. Just to clarify exactly what I mean:
Using VBA (or C# or anything else for that matter) - we dynamically insert formulas at runtime using named ranges. For example:
=(MIN(Bid_S1,Bid_S2, Bid_S3, Bid_S4, Bid_S5)/Bid_S3)*PriceWeighting
This now longer works and gives a SPILL error. When I try to put the # in front as suggested, I see a message telling me # is not supported for some versions of Excel, do I still want to use it.
Option 1 - yes, I put #'s in front of every named range, spill error.
Option 2 - the formula they suggest is identical to the one I already had. Same Spill error.
This is going to be a huge problem for a lot of companies, surely.
Hard not to agree with this question:
https://answers.microsoft.com/en-us/msoffice/forum/all/the-new-dynamic-arrays-spill-functionality-should/92f9847f-deca-4ec9-ada3-9e005a5b68da?rtAction=1579696000111&page=1
A very bizarre situation. 4 different computers. Each running identical versions of Excel, Windows.
A simple named range with 4 cells say, called PlanID
PlanID
1
2
3
4
Type "=PlanID" next to the first, on 3 of the machines it returns 1, as I would expect. On the 4th machine it returns the formula array of the whole range. Just spent about 2 hours researching Spill errors etc but nothing seems to directly relate to the 2 issues I have:
How can something that has worked reliably for years suddenly not work
Why only on one machine?
Literally identical versions of Excel (16.0.12325.20280 32 bit)
Sound to me like your exisiting worksheets rely on Implicit Intersection (whether you realised it or not).
If that's the case, you can continue to use that, by preceeding your formula with # (See here )
If you create a workbook in a version of Excel that supports Dynamic Arrays, you will need to be explicit with your Implicit Inersections.
If you create a workbook in a version of Excel that does not support DA's, then later open it in a version that does, Excel will insert the #'s for you.
To illustrate, here's a book created in a version that does not support DA's
Here's the same workbook opened (without modification) in a version that does support DA's
Note the addition of #'s in the selected formula
Related
nothing stuck or broken, just I am inspired after a discussion with another Excel author.
His situation:
Read from an existing Excel monster file (column FG), and hard-coded the following
Range("FF:FG").Copy
Potential issue:
data in FF:FG will be pushed to GF:GG every couple of months because newer columns will be inserted in between. (It's a pivot-like design... sorry, but end-users need this appearance, but categories are increasing, summary need to be at right end side)
He has 2 other choices (if he don't want to maintain VBA code every few months):
A: Store "FF","FG" in a Cell (fixed location!), then read the location parameter using VBA
B: Read a second dedicated CSV file (copy/paste from the monster file, consumed by another user so available readily), it only has the 2 columns required..
To me, none is obviously better than the other, just a matter of preference.
Similar but simpler Scene of mine
I produce the monstrous file by lots of Vlookup from manual data sources (inherited the design... and I refactored the design using another automation tool but there is license consideration atm).
In a column there is a formula doing something like
=if(A1="SALES PERSON SICK","void result",(if(A1="MACHINE BROKEN",C2*0.8),"")..
say 5000 rows with this formula
To reduce hard-coding I moved
"SALES PERSON SICK","MACHINE BROKEN" to a reference sheet cell A1,A2, and changed formula to:
=if(A1=Ref!$A$1,"void result",(if(A1=Ref!$A$2,C2*0.8),"")
I feel it's a good practice.
Question: Is method A or B better? Considering column position will move every ~3-6 months, still worth choosing 1 from A/B?
data in FF:FG will be pushed to GF:GG every couple of months because newer columns will be inserted in between
Then you should use named ranges in what you call "monster file" (see Define and use names in formulas) and use them in your VBA.
Eg define a name for Columns FF:FG like CopySource (use a name that describes the data in that columns) and finally you can use that in your VBA code.
Range("CopySource").Copy
Whenever the range moves because new columns are inseted before, the named range moves too, so it still points to the same data.
There is a file that contains mathematical operations that are a bit complicated.
When the file is opened on my laptop the value of 500,000,000 changes to 500,000,001, an excess of 1 number.
What exactly should I do?
I use Excel 2013, using an Asus X441U
This is commonly a formatting problem.
Please make sure that you are obtaining the real value of the result, not the displayed value.
This is best done by changing the cell number formatting. I would recommend adding a helper cell or two to and use =CELL("contents",yourcellwithchangingvalue) as one test.
Another method is to make a second result cell and wrap it in =TEXT(yourcellwithchangingvalue, "#.###") to see if that causes it to change.
Lastly, be sure all of your formulas are using functions or addins that are available on both machines.
I'm trying to read an Excel sheet from an XLS or XLSX file in memory using Delphi 7. When possible I use automation to read the cells one by one, but when Excel is not installed, I revert to using the ADO/ODBC Jet driver.
I connect using either
Provider=Microsoft.Jet.OLEDB.4.0; Data Source=file.xls;Extended Properties="Excel 8.0;Persist Security Info=False;IMEX=1;HDR=No";
Provider=Microsoft.ACE.OLEDB.12.0; Data Source=file.xlsx;Extended Properties="Excel 12.0;Persist Security Info=False;IMEX=1;HDR=No";
My problem then is that when I use the following query:
SELECT * FROM [SheetName$]
the returned results do not contain the empty rows or empty columns, so if the sheet contains such rows or columns, the following cells are shifted and do not end up in their correct position. I need the sheet to be loaded "as is", ie know exactly from what cell position each value comes from.
I tried to read the cells one by one by issuing one query of the form
SELECT F1 FROM `SheetName$A1:A1`
but now the driver returns an error saying "There is data outside the selected region". btw I had to use backticks to enclose the name because using brackets like this [SheetName$A1:A1] gave out a syntax error message.
Is there a way to tell the driver to select the sheet as-is, whithout skipping blanks? Or maybe a way to know from which cell position each value is returned?
For internal policy reasons (I know they are bad but I do not decide these), it is not possible to use a third party library, I really need this to work from standard Delphi 7 components.
I assume that if your data is say in the range B2:D10 for example, you want to include the column A as an empty column? Maybe? Is that correct? If that's the case, then your data set, when you read the sheet (SELECT * FROM [SheetName$]) would also return 1 million rows by 16K columns!
Can you not execute a query like: SELECT * FROM [SheetName$B2:D10] and use the ADO GetRows function to get an array - which will give you the size of the data. Then you can index into the array to get what data you want?
OK, the correct answer is
Use a third party library no matter what your boss says. Do not even
try ODBC/ADO to load arbitrary Excel files, you will hit a wall sooner or later.
It may work for excel files that contain a single data table, but not when you want to cherry pick data in a sheet primarily made for human consumption (ie where a single column contains some cells with introductory text, some with numerical data, some with comments, etc...)
Using IMEX=1 ignores empty lines and empty columns
Using IMEX=0 sometimes no longer ignores empty lines, but now some of the first non empty cells are considered field names instead of data, although HDR=No. Would not work anyway since valules in a column are of mixed types.
Explicitly looping across cells and making a SELECT * FROM [SheetName$A1:A1] works until you reach an empty cell, then you get access violations (see below)
Access violation at address 1B30B3E3 in module 'msexcl40.dll'. Read of address 00000000
I'm too old to want to try and guess the appropriate value to use so it works until someone comes with yet another mix of data in a column. Sorry for having wasted everybody's time.
One of the reports that wastes a bunch of my time at work is the Roster. It's a multi-site, multi-contract listing of every employee currently assigned to a specific client. Currently, it has a little over 6,000 lines by 20-something columns, indexed against 3 different datasets. Not the largest mess in the world, but still a pain. And it's almost all in excel, because I somehow don't have a business case for Access.
But one part of this monster stands apart. One tab per site Site Totals, listing off every time any agent has gone through training. A second tab (again, one per site) Site Data displaying only the most recent training class, and the credentials they had during that class.
That second tab is driven by variations of this array formula - Last_Row is a named range on another tab, and column A is a pivot of the UID column on Site Totals. I've broken it apart for readability:
=IF(INDEX('Site Totals'!B:B,LARGE(($A2=INDIRECT("'Site Totals'!$A$1:$A$"&Last_Row))*
(INDIRECT("'Site Totals'!B1:B"&Last_Row)<>"")*
ROW(INDIRECT("'Site Totals'!$A$1:$A$"&Last_Row)),1))="Trainer",
"",
INDEX('Site Totals'!B:B,LARGE(($A2=INDIRECT("'Site Totals'!$A$1:$A$"&Last_Row))*
(INDIRECT("'Site Totals'!B1:B"&Last_Row)<>"")*
ROW(INDIRECT("'Site Totals'!$A$1:$A$"&Last_Row)),1)))
I know what this formula does, but I don't know how to improve it. This formula needs to be changed, because it currently is on the order of 500 Million calculations (I'm not allowed to delete historical data), and it takes me 3 hours to calculate the workbook ... if it doesn't crash Excel first.
I'm open to VBA and / or custom functions, but would prefer to have native Excel functions. I'm not able to install anything, so any solution must be native Excel, and Must be compatible to Excel 2007.
If your source is a pivot table, try is the GETPIVOTDATA function. You might be able to accomplish what you want without INDIRECT and INDEX.
What i have understood is that every person has/has not attended a training and you want to retrive the name of that training, in case he has not, you want a blank space in the cell. If this description is correct you can try this formua, press ctrl+shift+enter to execute.
=IFERROR(INDEX('Site Totals'!B$1:B$12,MATCH(A2&"Trainer",'Site Totals'!A$1:A$12&'Site Totals'!B$1:B$12)),"")
Here A2 contians the name of the person. I can be more precise with this formula if you can provide some sample data butI would recommend to not to use entire B & Columns in Site Total workssheete as this will definately slow down computing process, instead you can use B1:B8000 or smaller range, to speed up process. Hope that helps.
Is there anyway to rewrite this formula to speed up Excel processing?
My spreadsheet has become terribly slow!
=SUMPRODUCT((Sheet1!J:J=Sheet2!A2)*(Sheet1!G:G="Windows XP")*(Sheet1!B:B="Desktop")*(Sheet1!M:M<>"Refresh >=Q2 2014")*(Sheet1!M:M<>"Release 2013")*(Sheet1!M:M<>"Release 2014")*(Sheet1!M:M<>"N/A NVM")*(Sheet1!M:M="No")*(Sheet1!M:M="N/A"))
As written your formula will always return zero because the last two conditions are mutually exclusive - did you mean those last two to be <> rather than = (or did you refer to the wrong columns)?
In any case I can see from the use of whole columns that you must be using Excel 2007 or later (your current formula would give an error otherwise) in which case COUNTIFS will be much faster, i.e. assuming the last two conditions should be adjusted as I suggested try this version:
=COUNTIFS(Sheet1!J:J,Sheet2!A2,Sheet1!G:G,"Windows XP",Sheet1!B:B,"Desktop",Sheet1!M:M,"<>Refresh >=Q2 2014",Sheet1!M:M,"<>Release 2013",Sheet1!M:M,"<>Release 2014",Sheet1!M:M,"<>N/A NVM",Sheet1!M:M,"<>No",Sheet1!M:M,"<>N/A")
If you do need to use SUMPRODUCT then restrict the ranges rather than using whole columns
I don't think that there is really a chance to speed up Excel Formula. But you could save your File in binary code (.xlsb). Losing some compatibility but improving performance.
You also could stop auto (re-)calculations of ther Formula, then you have to manualy refresh. This will let you edit the file much smoother.