Countif with reference to different sheet - excel

Hello I will need help with problem I am facing right now and even Google couldn't help me.
I would like to add to field AS2 a COUNTIF formula with source information from different sheet.
This COUNTIF should jump to sheet ee_lpk and then take a range from column A2 down to the end of last used row. and compare that with criteria from field D.
so for AS2 will be comparing with D2 for AS3 with D3.
When I recorded that it showed:
ActiveCell.FormulaR1C1 = COUNTIF(ee_lkp!R[-143]C[-44]:R[217]C[-44],R[-143]C[-41])"
this is working but just in case that there is on ee_lpk page same number or rows what is changing from day to day.
Any help will be much appreciated.
Martin

You need to break this problem down using variables. Try something like this:
sub Answer()
Dim srcRng as Range
Dim srcLength as Long
'First find how many rows on sheet ee_lpk and store it as a variable
srcLength = Sheets("ee_lkp").UsedRange.Rows.Count
'Then use that variable to get your range
Set srcRng = Range(Cells(2,1), Cells(srcLength, 1))
'Or another viable option would be:
'Set srcRng = Range("A2:A" & srcLength)
'Then put that in your Countif formula
ActiveCell.FormulaR1C1 = _
"=COUNTIF(ee_lkp!" & srcRng.Address(True, True, xlR1C1) & ", R[-143]C[-41])
End Sub

Related

Changing number format on a specific sheet

I've searched this forum for a solution, but none of the tips helped me. Perhaps I'm way too novice to put the code together by myself.
I'm trying to set a date format of "dd.mm.yyyy" on the sheet "Sheet2" in range G3:G.
With Worksheets("Sheet2")
Range("G3, G").NumberFormat = "dd.mm.yyyy"
Could you guys please point out what I'm missing?
Due to the below issue, your code is not the right code.
a cell address should have both row & column details. In the code you have given, no last cell row is mentioned.
Use the Collan symbol ":" to select a range of cells between the first & last cell.
You have used "with" statement for the worksheet, but the range is not referenced to that statement. meaning, you will have to put a dot "." before the range to follow the correct practice.
Below is the corrected code.
With Worksheets("Sheet2")
.Range("G3:G25").NumberFormat = "dd.mm.yyyy" 'here i am assuming G25 is the last cell
End With
If you are not sure about the last cell, you can use the below code.
Sub Test()
With Worksheets("Sheet2")
.Range("G3: " & .Cells(.Rows.Count, "G").End(xlUp).Address).NumberFormat = "dd.mm.yyyy"
End With
End Sub

How to use a user defined range in a formula in vba

I am trying to define a range starting at B2 (constant) to the last cell with data which will change month to month. I want to take the same range length and define another range for column A which will also start at A2 (constant) but will extend only down as far as column B goes. I'm trying to identify them as range and use the dimmed range in a formula in vba but it doesn't like it...any ideas?
Dim Data As range
Dim Time As range
range("b2").Select
'Select Range
Set Data = range("B2", range("B2").End(xlDown))
Set Time("A2", range("A2").End(xlDown))
ActiveCell.Offset(1, 1).Select
ActiveCell.FormulaR1C1 = _
"=FORECAST.ETS([#Timeline],.address(data),.address(time):R[-1]C[-2],1,0)"
You need to close the formula string, add the address, and then continue:
"=FORECAST.ETS([#Timeline],.address(" & data.address & "),.address(" &
time.address & "):R[-1]C[-2],1,0)"
Note since you're using R1C1 style, you might have to do this on both .address parts,
time.address(ReferenceStyle:=xlR1C1)
so:
"=FORECAST.ETS([#Timeline],.address(" & data.address(ReferenceStyle:=xlR1C1) & "),.address(" &
time.address(ReferenceStyle:=xlR1C1) & "):R[-1]C[-2],1,0)"
Edit: Also, I would change the keyword Time, as I think that's a reserved word. Perhaps Dim timeRng as Range?
In addition to #BruceWayne's answer, to address the first part of your question:
If I have a range B2:B50, and I want the corresponding A column, then I can use the Offset function:
Set time = data.Offset(columnOffset:=-1)
Alternatively you can construct the column like this:
Set time = Sheet1.Range("A2").Resize(Rows(data), 1) 'nrows, 1 column
Then you could put A2 anywhere
FWIW:
range("b2").Select is unnecessary and will really slow down your code if you get into this habit (it's just because the macro recorder doesn't know what you want exactly). You could use Range("B2").Offset(1,1).FormulaR1C1 with no selecting
You can name cells in excel and refer to the names: Range("myNamedCell")
Always best practice to prepend the sheet name and fully qualify references (e.g. Sheet1.Range("A1")) since that will always refer to the same cell, whereas Range("A1") refers to A1 on whichever sheet happens to be selected when you run the macro

Autofill Dynamic Column

Trying to Autofill Column X and Column Y with text
Where Column Z determines the table length
Starting cell for column Z is "Z3" but column "X and Y" are dynamic
Last filled cell in column "X & Y" carries the text required.
Current Last cells is "X56" and "Y56"
Current last cell in column Z is "Z89"
I can easily get to x56 or y56 using
Range("Y3").Select
Selection.End(xlDown).Select
Selection.AutoFill Destination:=Range("Y56:Y89")
Range("Y56:Y89").Select
Range("X56").Select
Selection.AutoFill Destination:=Range("X56:X89")
Range("X56:X89").Select
However the solution eludes me to remove absolute references due to the dynamic nature of the information being imported and added to the column of previous information.
I tried this code i read through my research but couldn't make it work
lastRow = Range("Y3").End(xlDown).Row
Selection.AutoFill Destination:=Range("Y3:Y" & lastRow), Type:=xlFillDefault
Any assistance would be really appreciated as this appears to be the lynch pin to completing this task
Cheers
Mick
with I am trying to stack reports generated on a 12 hourly basis.
into an accrued 24 data table. This will then be accrued into a monthly data table.
As base information is downloaded in csv format. The four reports are formatted differently so i also have to stack the four reports in two table separated and itemised by date and shift.
This then allows the use of lookups, countifs sumifs etc to populate my outputs.
The four reports are dynamic and open to the potential of having a number of blank cells throughout.
I have written code that is robust enough to achieve this short of this one issue.
As the four reports do not have time stamps i am forced to use file names (column A:A) to populate the Date and Shift ranges (column A:B) as well as (Column X:Y) but need to drag the text down to cover all rows of information
Range("Y3").Select
Selection.End(xlDown).Select
Selection.AutoFill Destination:=Range("Y56:Y89")
Range("Y56:Y89").Select
Range("X56").Select
Selection.AutoFill Destination:=Range("X56:X89")
Range("X56:X89").Select
Autofill Columns with text without absolute references to allow for dynamic column range and without known starting point on the column
Do not use xlDown to find the last row. You may want to have a look at this Finding Last Row
Is this what you are trying? I have given you two option. Take your pick.
Option Explicit
Sub SampleA()
Dim ws As Worksheet
Dim lRow As Long
'~~> Change this to the relevant sheet
Set ws = Sheet1
With ws
'~~> Get last row in Col Z
lRow = .Range("Z" & .Rows.Count).End(xlUp).Row
'~~> Autofill formula in 1 go
.Range("X3:X" & lRow).Formula = .Range("X3").Formula
.Range("Y3:Y" & lRow).Formula = .Range("Y3").Formula
End With
End Sub
Sub SampleB()
Dim ws As Worksheet
Dim lRow As Long
Dim rng As Range
'~~> Change this to the relevant sheet
Set ws = Sheet1
With ws
'~~> Get last row in Col Z
lRow = .Range("Z" & .Rows.Count).End(xlUp).Row
Set rng = .Range("X3:Y3")
rng.AutoFill Destination:=.Range("X3:Y" & lRow)
End With
End Sub

VBA to reference the same cell even after the addition or deletion of rows & Columns

I'm using VBA code to write to cells in excel. For eg.
Range("C3") = code
Or
Cells(3,3) = code
If a row is inserted in the sheet, the code does then not update accordingly and would still write to Range("C3") etc. So the code then writes to the incorrect cell.
Is there a better way I can structure my code so it will update accordingly? Perhaps using a table instead of cells?
One solution is to used Named Ranges. You can define a Named Range in Formula Tab by clicking on Name Manager.
Then you will write.
Range("Name of the Range") = code
My believe is that named ranges update automatically when a row or column is inserted, so your code will print the value in the correct cell.
Thanks, good idea. I ended up defining the column filled with values as a range, then use a for loop to search for the defined string. That way it doesnt matter what row it is in aslong as the name and string doesnt change (Using a Named Range will probably be better for that exact reason).
Worksheets("Sheet1").Select
Set WS = ActiveSheet
With WS
LastRow = .Cells(.Rows.Count, 2).End(xlUp).Row 'Determine the last row number with data in it for column B
For Each acell In .Range("B1:B" & LastRow) 'Defines the search range from B1 to last row
If acell.Value = "String Searched For" Then
'Do stuff based on found cell location
End If
If acell.Value = "String Searched For#2" Then
'Do stuff based on found cell location#2
End If
Next
End With

Excel: Calculate difference between cell and cell above in an auto filtered table

I have a table with column A containing incrementing numerical values, and column B being a bunch of names. I need to filter the table according the names, and have column C update with the difference between the value in column A in the current row and the cell above..
For example, I'd like to have something like this
which,
when filtered according to the Name column, should update the difference like so
I have tried to use SUBTOTAL function in a few different ways but to no avail. Ideally it'd update once the filter in the table is changed. I tried to do this in VBA but so far I've gotten macro that only filters with the hard-coded filter criteria.
Solutions in either excel formulas/python/vba are all welcomed and greatly appreciated!
I apologise in advance if this question isn't up to standards as Im new here :) Thank you in advance!
#JvdV: This is the outcome of me trying to implement your formula, This is after filtering.
REVISED ANSWER
So after your explenation I have looked into a formula that will give you the difference of the current row B-value minus the B-value of occurance of the A-value before that.
=IFERROR(B2-LOOKUP(2,1/($A$1:A1=A2),$B$1:B2),0)
Taking your sample data, it would look like this:
Then when you apply the filter, it would look like this:
So with this workaround you dont have the correct value when no filter is applied, but in this case I assumed you are interested in the difference when it IS filtered!
The formula is entered in cell C2 and dragged down.
EDIT
If this is not the answer you'r after and you DO need the values when it is not filtered, make use of a UDF like below:
Public Function LastVisibleCell(CL As Range) As Long
Dim RW As Long, X As Long
RW = CL.Row - 1
On Error GoTo 1
If RW > 1 Then
For X = RW To 1 Step -1
If ActiveSheet.Rows(X).EntireRow.Hidden Then
Else
LastVisibleCell = Cells(CL.Row, 2).Value - Cells(X, 2).Value
Exit For
End If
Next X
Else
1: LastVisibleCell = 0
End If
End Function
Call it from cell C2 like: =LastVisibleCell(A2) and drag down. When you apply your filter, the cells will update.
Beware, this will take ages to update on large datasets!
After 3 days of intense (albeit ineffective) Google-ing, I finally came across this answer also on stack overflow.
However, as I'm working on a large set of data (>150,000 rows), the method in the question uses too much memory. Using VBA to paste the formulas into visible cells only does not seem to alleviate the problem.
Sub CopyPasteFormula()
Dim Ws As Worksheet
Dim LRow As Long
Dim PasteRng As Range
Set Ws = Worksheets("Translated Data")
Ws.Range("$D$2:$D$200000").AutoFilter Field:=4, Criteria1:="<>-", Operator:=xlFilterValues
LRow = Ws.Range("D" & Rows.Count).End(xlUp).Row
Set PasteRng = Ws.Range("A3:A" & LRow).SpecialCells(xlCellTypeVisible)
Ws.Range("A3").Copy
PasteRng.PasteSpecial xlPasteFormulas
Application.CutCopyMode = False
End Sub
Above is my macro code to attempt reduce the memory use... Appreciate any feedback!

Resources