I am stuck in a weird situation where I need to perform a simple vlookup but the using different data points.
I have a mapper where I have a %Achievement of the employee # Enter & State wise with their Slabs.
On second hand, I have a data sheet where I have the actual %Achievement of the Center state wise and I need to update the Slab from the above table. I have updated few of the entries FYR, however I have similar thing for almost 12000 entries of different combinations.
If you are using excel 365, combination of FILTER & XLOOKUP should work.
Step 1: Filter the row from slab sheet for the Centre/State which you need
Step 2: Use xlookup with matchmode 1
Here is the rough code snippet in col F2 of actual sheet:
= XLOOKUP(E2, FILTER([slab sheet]!D2:N100, ([slab sheet]!B2:B100=B2)*([slab sheet]!C2:C100=C2), [slab sheet]!D1:N1, "#N/A", 1)
Related
My goal is to use parts of several sheets to compute basic stuff of each of the selected rows in those sheets.
The prior way to do this was to create a row with formulas manually. Let's say I have sheets: "Input1","TranslateTable", "Calculations". Then row 1 in "calculations" would have in cell A1 Input1!A1*2, B1 would have Input1!B1 / TranslateTable!D1, etcetera. The formula row would be autofilled using VBA, incrementing the rows used.This incrementing would work as all relevant rows would be sorted to the top rows in the input sheet using the VBA. Each month, all the data would be removed except for the row with the formulas, and it would be autofilled again with the amount of relevant input rows that month.
I didnt make this, and I think it's bad practise to change input data only to use it for another sheet.
Moreover, a new sheet "Input2" was added, making this method not usable. Technically, there needs to be two slightly different rows autofilled, with input2 calculations being right under the input1 calculation.
I am thinking of ways make this method more robust. Coming from Python, I'm used to calculations being very quick. So I'd figured removing the formula rows and recreating these with VBA directly. While it's working, it's extremely slow.
As I don't have much experience yet, I might not do things properly. Right now (example code), I have
Sub Calculations
For row_num = 2 to 20
Sheets("Calculations").Range("A" & row_num) = Sheets("Input1").Range("B" & row_num)*5
# and than here is the next calculation for the next cell in the row
# again, et cetera
End Sub
Is this the right way to do this loop this? I can imagine there is a more efficient way (I know in Python there is).
I have thought of several options
try to make the loop more efficient
create rows of formula in the sheet and use vba to autofill (but then more robust than before)
Create formulas using VBA and then to autofill.
All help is greatly appreciated!
update: based on Bankeris' answer, I would get the following using arrays:
Dim RangeArray As Variant
RangeArray = Sheets("Input1").Range("A1:AZ10").Value
'and then loop calculations like this
for row_num = 2 to 15
'my output table starts at a different row
output_row = row_num + 2
ValueArrayB1Cell = RangeArray(row_num, 2)
Range("A" & output_row) = ValueArrayB1Cell * 2
Looping through Excel Cells is very slow thing :)
Probably best way to solve this - calc everything in memory from array. Put everything into array, loop and calc and then write result in Excel.
Dim RangeArray As Variant
RangeArray = Sheets("Sheet1").Range("A1:A5").Value
ValueArrayA1Cell = RangeArray(1, 1)
ValueArrayB2Cell = RangeArray(2, 2)
I am trying to simplify a process of counting how many of a specified criteria are in a table.
What I need is to count the number of items that meet all of the following criteria:
[BusinessArea] = "Corporate"
[Application] = "CS"
[Status] = "Resolved"
[ResolvedDate] = *if the resolved date is between DateA and DateB eon a
separate worksheet.
I can do it using VBA or Formulas but I just cannot figure out the date part. I have them figured out separately as:
=IF(AND(Sheet1!I71 >= (TODAY()-7), Sheet1!I71 <TODAY()), TRUE, FALSE)
Where i71 is the [ResolvedDate] (it is searching just this one entry without the other filters.
=COUNTIFS(Table8[Business Area], "Corporate", Table8[Application], "CS")
Where it counts the number of entries that are Corporate_CS entries.
What I currently have:
'=COUNTIFS(Table8[Reported Date],AND(Table8[Reported Date]<='Ticket Summary'!F61, Table8[Reported Date]< TODAY()),Table8[Business Area], "Corporate", Table8[Application], "CS")'
Where F61 is a previous date (beginning of range)
Of which it is returning 9 instead of 6. There are 9 entries that match the criteria, 6 matching the date range and criteria
Try this:
=COUNTIFS(Table8[BusinessArea], "Corporate", Table8[Application], "CS",Table8[Status], "Resolved", Table8[ResolvedDate], ">=" & I61, Table8[ResolvedDate], "< " & I71)
I'm assuming that I61 is the start date and I71 is the end date.
I used this as a guide for the dates: count-cells-between-dates
Multi-criteria counting is a little tough in Excel. I used to make extra columns and concatenate values. Then you can use countif without too much trouble. But it was messy. You could also use DCOUNTA by setting up your query parameters on another part of your sheet (but it doesn't like tables - only cell ranges). Again, its a little messy, but it's very flexible.
My preferred method is to use the SUMPRODUCT function. Everything can be done in one formula and it works with tables. To get your count using SUMPRODUCT:
=SUMPRODUCT((Table8[BusinessArea]="Corporate")*(Table8[Application]="CS")*(Table8[Status]="Resolved")*(Table8[ResolvedDate]>DateA)*(Table8[ResolvedDate]<DateB))
This is my first post and I can't find an exact answer anywhere. I have an Excel spreadsheet that is becoming too large to operate because I have long formulas in millions of cells. I need to know how to calculate the formula using VBA but have only the value appear in Excel. An example is I want to multiply column B by column C:
I have tried this code:
Range("D3:D6").Formula = Evaluate("=B3*C3")
It correctly calculates for the first cell, but for the other cells it still tries to calculate B3*C3 as a fixed reference rather than as a dynamic references that changes as the cell position changes.
How could I fix this? Thankyou.
Edit:
My actual spreadsheet looks like this:
This formula needs to be applied down 17520 rows and across 300 columns, but I only want the values to appear in Excel. The purpose of this is to reduce file size and reduce calculation time.
=IF(-SUMIF(AIG$4:AIG4,"<0")>0.9*SUMIF(AIG$4:AIG4,">0"),0,IF(-SUMIF(AIG$4:AIG4,"<0")-IF(WQ5<'Battery Specs'!$B$13,-'Battery Specs'!$B$15,IF(WQ5=ROUNDDOWN('Battery Specs'!$B$13,0)+1,-('Battery Specs'!$B$13-ROUNDDOWN('Battery Specs'!$B$13,0))*'Battery Specs'!$B$15,0))>0.9*SUMIF(AIG$4:AIG4,">0"),-(0.9*SUMIF(AIG$4:AIG4,">0")+SUMIF(AIG$4:AIG4,"<0")),IF(WQ5<'Battery Specs'!$B$13,-'Battery Specs'!$B$15,IF(WQ5=ROUNDDOWN('Battery Specs'!$B$13,0)+1,-('Battery Specs'!$B$13-ROUNDDOWN('Battery Specs'!$B$13,0))*'Battery Specs'!$B$15,IF((0.9*SUMIF(AIG$4:AIG4,">0")+SUMIF(AIG$4:AIG4,"<0"))>'Battery Specs'!$B$10,0,IF(((0.9*SUMIF(AIG$4:AIG4,">0")+SUMIF(AIG$4:AIG4,"<0"))+$AIF5*0.9)>'Battery Specs'!$B$10,'Battery Specs'!$B$10-(0.9*SUMIF(AIG$4:AIG4,">0")+SUMIF(AIG$4:AIG4,"<0")),$AIF5))))))
Try
Range("D3:D6").Formula = "=B3*C3"
Range("D3:D6").Value = Range("D3:D6").Value
or simply
Range("D3:D6").Formula = Evaluate("(B3:B6)*(C3:C6)")
Using Evaluate to calculate the formulas and then transfer the values to Excel will be slower than having Excel calculate the formulas directly.
Here are a couple of things you could try:
a) Formulas
You only have 5 million formulas in 5 million cells - this is not an overwhelmingly large number but your formulas are very long and each formula references a large number of cells.
Your formula contains many repeated expressions and calculations - move them out to helper cells and try to simplify/shorten your formula.
b) VBA - don't use Evaluate - just grab the range of 5 million cells into a single variant array and use VBA Loops, arithmetic and logic to accomplish the same task as your formulas and then put the array back.
I believe best option is to keep formulas instead of using VBA to produce same formulas. Instead, when entering new data in SpreadSheet, be sure to set calculations to manual (go to Formulas tab=>Calculation Options=>Manual. This way you wont trigger calculations when entering/pasting new values, meaning your Excel file will operate just as fast as if there was no formulas. After you entered/pasted all new values, set Calculations to Automatic.
You might want to try this:
Dim i as Integer
For i = 3 to 6
Range("D" & i).Value = Range("B" & i).Value * Range("C" & i).Value
Next i
The other alternative is to name your formula, for instance, instead of saying =B3*C3, you can give it a name say times value, and then say =timesvalue. Next, remove the formula and leave the value only. E.g. range("D3:D30").value=range("D3:D30").value
I trying to create dynamic report out of a work sheet I have and I am kind of stuck not able to get unique values.
In A1:A15000k I have Ticket/Task#, the ticket can be worked on more than once, i am trying to apply another criteria to my formula to only allow unique Ticket numbers to be counted.
here is the formula i am using now:
=SUMPRODUCT(COUNTIFS(INDIRECT($C$3 & "!$G$1:$G$14989"),INDIRECT(D3),INDIRECT($C$3 & "!$S$1:$S$14989"),$B$3, INDIRECT($C$3 & "!$H$1:$H$14989"), E$10, INDIRECT($C$3 & "!$U$1:$U$14989"), ">="& $C$7, INDIRECT($C$3 & "!$U$1:$U$14989"), "<="& $D$7))
Non dynamic version of it
=SUMPRODUCT(COUNTIFS($G$1:$G$14989,Names, $H$1:$H$14989, "Priority", $N$1:$N$14989, ">=3/15/2016", $N$1:$N$14989, "<=3/16/2017"))
where Names represent a set of users....
I gut this finally working but with a helper column... just added a new column to my original sheet that is checking duplicates n the column i don't want to count when its duplicated
=IF(COUNTIF($C$6:$C6,C6)>1,"DUPLICATE",1)
After that all i needed to do a dd the new column to my countifs formula...
I'd like to reference a single cell in a table, from outside the table, using square-bracket sheet-formula notation.
Something like:
[MyTable[MyField] 3]
or
[MyTable[MyField] 3:3]
-to reference the 3rd row of the MyField column, or:
[MyTable[MyField] MyRow]
-to reference the MyRow row (leftmost row-header) of the MyField column.
Needs to work from outside the table, ie can't use # or #ThisRow.
Not looking for methods involving MATCH, INDEX, OFFSET, etc. Not looking for VBA methods. Just straightforward table-notation. Not looking for manually creating named ranges.
Why? Because, Tables :)
Pre-2013 Excel.
(PS, didn't there used to be a way (pre-Tables) to reference cells by row and column headers? I think it was maybe called "auto-naming", or something like that.)
heh, well this works:
=Table1[Column2] 3:3
So that's progress :)
Just awesome would be a way to reference a row by the contents of left-most column.
Thx!
You can also use index() function as in:
index(MyTable[MyField], 3)
So you get row 3 from the column MyField in table MyTable.
Reference:
https://www.ozgrid.com/forum/forum/help-forums/excel-general/116365-reference-a-single-cell-in-a-table-using-structured-referencing
We can reuse the idea of the intersection operator (i.e. a space between two references) and improve it to have the relative row number of the targeted item in the table, referred to as row_nb here:
=tbl[col] OFFSET(tbl[[#Headers],[col]],row_nb,)
or just without intersection actually (cf. comment below):
=OFFSET(tbl[[#Headers],[col]],row_nb,)
E.g. =Table1[Column2] OFFSET(Table1[[#Headers],[Column2]],2,)
This way you do not depend on the position of the table in the worksheet. Well, it yields a more complicated formula where table name tbl and column name col appear twice. Here are some comments about it:
You can of course keep the OFFSET(...) part only. The downside is that the formula will never return any error if row_nb exceeds the actual number of line items in the table. It'll return e.g. just 0 if the cells below the table are empty.
Keeping a formula that throws an error when we refer to an off-table row, we can further improve it: make it "dynamic" by letting tbl, col and row_nb be parameters:
=INDIRECT(tbl&"["&col&"]") OFFSET(INDIRECT(tbl&"[[#Headers],["&col&"]]"),row_nb,)
Assuming that we've defined tbl, col and row_nb as named ranges. Or else just use cell addresses:
=INDIRECT(A1&"["&A2&"]") OFFSET(INDIRECT(A1&"[[#Headers],["&A2&"]]"),A3,)
I'm not a big fan of INDIRECT but in this case it really comes in handy to let the formula adapt to various tables, columns and line items.
To handle tables that don't start at the first row of a worksheet, we can use the ROW() function. We can determine the first row of the data in the table with:
=ROW(myTable)
Using this and the Indirect() Function we can identify the first cell in a named column with
= myTable[myField] INDIRECT(ROW(myTable) & ":" & ROW(myTable))
The 3rd cell in that column would be:
= myTable[myField] INDIRECT(ROW(myTable)+3 & ":" & ROW(myTable)+3)