Alternative formula in Excel 2003 for DSUM - formula

I am working with Excel 2003 and trying to find the total of individual criteria. I am currently using this formula and it is working successfully.
Data A1:G1776 is the the database ---
Data C1 - is the column that has what I want total --- and
F4:F5 is a column where I set up a the criteria for the line to match.
=DSUM(DATA!$A$1:$G$17996,DATA!$C$1,$F$4:F5)
The problem I am running into is that the file size is over 5MB, which is huge when you are trying to email it to other people.
Any suggestions how I can replicate that formula, while decrease the file size and also improving the speed of the document? I am not wishing to use a Pivot Table

A replacement for DSUM, you could use a sumproduct formula:
=SUMPRODUCT((DATA!$C$2:$C$17996)*(DATA!$A$2:$A$17996="Boys")*(DATA!$B$2:$B17996>18))
The above example creates a total of column C only including rows where: Column A are "boys and column B is greater than 18.
The example assumes that row 1 is a header row.
For speeding up calculations you could use VBA to enable calculation of indvidual sheets.
VBA for enabling calculation:
Public Sub enableCalc(ParamArray sheetsInUse())
Dim i As Integer
For i = 0 To UBound(sheetsInUse) Step 1
sheetsInUse(i).EnableCalculation = True
Next i
End Sub
Called using: enableCalc activeworkbook.Worksheets("Sheet1")
Which would enable calculation Sheet1 in the activeworkbook
VBA for disabling calculation for all sheets in workbook:
Public Sub finishedUse(wrkbook As Workbook)
Dim i As Integer
Dim wrkSheet As Worksheet
For Each wrkSheet In wrkbook.Worksheets
wrkSheet.EnableCalculation = False
Next wrkSheet
End Sub
Called using: finishedUse activeworkbook
Which would disable calculation of all the sheets in the activeworkbook.
The above method isnt effected by changing Automatic/Manual Calculation in Tools --> Options

Related

Getting Column Index from SSDBGrid in VB6

I'm producing a report in Crystal Reports where the column order must match the order that they're displayed in in the SSDBGrid in VB6.
To do this, I decided it was best to loop over each column in the grid, and call a function to set the parameter field values to the correct heading (so, column 0's caption would be the value for parameter field #Col1, etc)
Anyway, the code I have for this is
Dim c As Column
Dim cName As String
For Each c In FShow_All_Accounts.grd_accounts.Columns
cName = "#Col" & c.ListIndex
Call setColumnHeaders(c.Index)
crxReport.ParameterFields.GetItemByName(cName).AddCurrentValue ("f")
Next
The problem is that first of all, setting the type of c to Column and looping over each c in grd_accounts seems to be incorrect - grd_accounts is an SSDBGrid, and secondly, it errors when trying to return the index.
So, my question(s):
What is the correct way to loop over each column in an SSDBGrid?
Secondly, how would I then get the column index for the correct column, to pass into the function?
The answer is actually more simple than you're imagining it to be. Your code is very nearly there.
Dim c As Column
Dim i As String
Dim cname As String
i = 0
For Each c in grd_accounts.Columns
i = i + 1
cName = "#Col" & i
crxReport.ParameterFields.GetItemByName(cName).AddCurrentValue (c.Caption)
Next
No need for the helper function. This will iterate over each column, set cName to be "#Col" and the value of i (Also the column number), and therefore that parameter field in the report will be captioned with that columns caption.

New cell with range between two cells

I have a cell with vehicle model years (starting A:2 and ending B:2) for example A:2 is 1997 and B:2 is 2001 How can I make the single cell C:2 show the range of years for example 1997 1998 1999 2000 2001 I need this for a shopping cart that will query specific years. My files have about 15,000 rows so I need to do this with a formula.
I need the end result to go into either the single cell c:2 or to populate in single cells to the right example c;2 d;2 e;2 etc. It is preferred to have them in a single cell separated by a space not a comma as this will be uploaded as a .csv file.
In C2 enter:
=A2
In C3 enter:
=IF( MAX($C$1:C2)=$B$2,"",C2+1)
and copy down
EDIT#1:
In order to place the result into a single cell run the following macro rather than using formulas:
Sub SpanOfYears()
Dim FirstCell As Range, SecondCell As Range, Result As Range
Dim I As Long
Set FirstCell = Range("A2")
Set SecondCell = Range("B2")
Set Result = Range("C2")
For I = FirstCell.Value To SecondCell.Value
Result.Value = Result.Value & " " & I
Next I
End Sub
with this result:
EDIT#2
Macros are very easy to install and use:
ALT-F11 brings up the VBE window
ALT-I
ALT-M opens a fresh module
paste the stuff in and close the VBE window
If you save the workbook, the macro will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the macro:
bring up the VBE window as above
clear the code out
close the VBE window
To use the macro from Excel:
ALT-F8
Select the macro
Touch RUN
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
Macros must be enabled for this to work!

PHPExcel writer too slow

I am generating a .xls file, in which there is a column containing formulas like these:
IF(A1=1; 'xxx'; IF(A1=2; 'yyy'; IF(A1=3; 'zzz' ...
You know, it would be a SWITCH if it wouldn't be excel formula.
The problem is, depending on how many IF's I use, the time it takes to generate the .xls file grows exponentially.
The filesize is not much different.
I have 18 cases, which means 18 IF's and that takes just unacceptable amount of time.
Why is that so? Is there anything I might be doing wrong?
Here is a sample code:
for ($k = 1; $k<16; $k++){
$cellID = "A".($row+$k);
$codes_if = '=IF('.$cellID.'="1",4579,'
.'IF('.$cellID.'="2",7978,'
... // some more IF's
.'""))))))))))))))))';
$actSheet->SetCellValue("B".($row+$k),$codes_if);
}
A formula like this with multiple nested IFs will be inefficient anyway
Consider replacing your multiple nested IFs with VLOOKUP instead
e.g.
=VLOOKUP(A1,E1:F3,2,TRUE)
where column E contains the lookup values 1, 2, 3, ... and column F contains the return values aaa, yyy, zzz, etc)
That is the equivalent of a switch statement in MS Excel
You will find that using VLOOKUP is a lot more efficient than your nested IFs
To reduce the time it takes to save the file further, be aware that PHPExcel calculates all formulae before saving by default. You can change that behaviour by calling
$objWriter->setPreCalculateFormulas(false);
before calling the save

Chart doesn't update when adding new rows to an existing Excel table (not without having to use named ranges)

I'm really new to the use of closedXMl and Excel too(at least for this purpose) so sorry if I'm asking silly questions.
I know that closedXML doesn't support charts yet so the only thing that came to mind to get around this was to create my chart using an excel table . That way I thought ClosedXML would update the ranges when I inserted new rows and the chart would pick up on it. Well , it didn't. At least not when I add the rows from code using the closedXML library.
What is curious is that adding new rows from inside excel automatically updates the chart but if I want to get that same result from code, I have to use OFFSET formula along with named ranges and then set the chart source data to these named ranges.
That's why I'd like to know if if there is anything wrong with the code I use to insert new rows:
Dim ruta As String = Server.MapPath("~/Templates/MyTemplate.xlsx")
Dim wb As New XLWorkbook(ruta)
Dim ws = wb.Worksheet(1)
Dim tblData = ws.Table("Table1")
Dim year As Integer = 2000
For i As Integer = 1 To 13
With tblData.DataRange.LastRow()
.Field("Year").SetValue(year)
.Field("Sales").SetValue(CInt(Math.Floor((2000 - 500 + 1) * Rnd())) + 500)
End With
tblData.DataRange.InsertRowsBelow(1)
year = year + 1
Next
tblData.LastRow.Delete()
As you can see the code is very simple and so is the template , that consists of only two columns : "Year"(table1[Year]) and "Sales"(Table1[Sales]
I don't think this has anything to do with my template because as I told you, adding new rows directly from excel works as expected and it is only when I generate the table from code that the chart series doesn't include the new row that were added
Being necessary to manually add the new ranges(Sheet1!Table1[Sales] and Sheet1!Table1[Year]) as it only includes the first row(the one added by default when you insert a table)
Any help would be much appreciated
P.S. Here is a link to a rar containing the full code as well as the excel template(\Templates\MyTemplate.xlsx)
If the problem is that your table doesn't recognise the additional rows, try adding this after the last row delete:
tblData.Resize tblData.Range(1, 1).CurrentRegion
That should resize the table. Then hopefully your table operations should work.

Writing to Excel file containing formulas is extremely slow

We have an automatic process that opens a template excel file, writes rows of data, and returns the file to the user. This process is usually fast, however I was recently asked to add a summary page with some Excel formulas to one of the templates, and now the process takes forever.
It successfully runs with about 5 records after a few minutes, however this week's record set is almost 400 rows and the longest I've let it run is about half an hour before cancelling it. Without the formulas, it only takes a few seconds to run.
Is there any known issues with writing rows to an Excel file that contains formulas? Or is there a way to tell Excel not to evaluate formulas until the file is opened by a user?
The formulas on the summary Sheet are these:
' Returns count of cells in column where data = Y
=COUNTIF(Sheet1!J15:Sheet1!J10000, "Y")
=COUNTIF(Sheet1!F15:Sheet1!F10000, "Y")
' Return sum of column where data is a number greater than 0
' Column contains formula calculating the difference in months between two dates
=SUMIF(Sheet1!I15:Sheet1!I10000,">0",Sheet1!I15:Sheet1!I10000)
' Returns a count of distinct values in a column
=SUMPRODUCT((Sheet1!D15:Sheet1!D10000<>"")/COUNTIF(Sheet1!D15:Sheet1!D10000,Sheet1!D15:Sheet1!D10000&""))
And the code that writes to excel looks something like this:
Dim xls as New Excel.Application()
Dim xlsBooks as Excel.Workbooks, xlsBook as Excel.Workbook
Dim xlsSheets as Excel.Sheets, xlsSheet as Excel.Worksheet
Dim xlsCells as Excel.Range
xls.Visible = False
xls.DisplayAlerts = False
xlsBooks = xls.Workbooks
xlsBooks.Open(templateFile)
xlsBook = xlsBooks.Item(1)
' Loop through excel Sheets. Some templates have multiple sheets.
For Each drSheet as DataRow in dtSheets.Rows
xlsSheets = xlsBook.Worksheets
xlsSheet = CType(xlsSheets.Item(drSheet("SheetName")), Excel.Worksheet)
xlsCells = xlsSheet.Cells
' Loop though Column list from Database. Each Template requires different columns
For Each drDataCols as DataRow in dtDataCols.Rows
' Loop though Rows to get data
For Each drData as DataRow in dtData.Rows
xlsCells(drSheet("StartRow") + dtData.Rows.IndexOf(drData), drDataCols("DataColumn")) = drData("Col" + drDataCols("DataColumn").toString).toString
Next
Next
Next
xlsSheet.SaveAs(newFile)
xlsBook.Close
xls.Quit()
Every time you write to a cell Excel recalculates the open workbooks and refreshes the screen. Both of these things are slow, so you need to set Application.Screenupdating=false and Application.Calculation=xlCalculationManual
Also there is a high overhead associated with each write to a cell, so it is much faster to acuumulate the data in an array and then write the array to the range with a single call to the Excel object model.
With auto mode calculation, recalculation occurs after every data input/changed. I had the same problem, was solved by setting Manual calculation mode. (Reference MSDN link.)
xls.Calculation = Excel.XlCalculation.xlCalculationManual
Also, this property can only be set after a Workbook has been opened or it will throw a run-time error.
One way that has saved me over the years is to add
Application.ScreenUpdating = False
directly before I execute a potentially lengthy method, and then
Application.ScreenUpdating = True
directly after, or at least at some later point in the code. This forces Excel to not redraw anything on the visible screen until it is complete That issue is where I've found lengthy running operations to stem from quite often.

Resources