I need excel formula to assign serial number to duplicates but with an added criteria for dates in ascending order.
The Count if formula "=COUNTIF($A$1:A1,A1)" will assign number in ascending order based on the row for the column A data but not based on the date.
I have the below table in Column A and B and the result expected in Column C
Name Date Serial number(Expected Result)
Apple 1/1/2019 1
Orange 2/1/2019 1
Lemon 4/1/2019 2
Banana 5/1/2019 2
Apple 8/1/2019 3
Watermelon 1/1/2019 1
Lemon 1/1/2019 1
Orange 4/1/2019 2
Banana 2/1/2019 1
Apple 5/1/2019 2
If you see first Apple is 1 but next one is not 2 as the date is 8th so its the third date based on ascending order of the date hence its 3 and the last Apple is 2.
Hope I am clear what I am asking. Apologies if any inconvenience in writing as this is my first question here and I am still learning.
If you sort the data, the formula you have will work.
If you're not able to/willing to sort the data then you can use this custom formula ...
Public Function AssignSerialNo(ByVal strName As String, ByVal dtDate As Date, ByVal rngData As Range) As Long
Dim lngRow As Long, lngEmptyCount As Long, strThisName As String, dtThisDate As Date, strThisDate As String
Application.Volatile
AssignSerialNo = 1
' Process each row provided in the 3rd parameter. Give it 10 rows of blanks before exiting out
' and ending the process.
For lngRow = 1 To rngData.Rows.Count
strThisName = Trim(rngData.Cells(lngRow, 1))
strThisDate = rngData.Cells(lngRow, 2)
If strThisName = "" Then
lngEmptyCount = lngEmptyCount + 1
Else
lngEmptyCount = 0
If IsDate(strThisDate) Then
dtThisDate = rngData.Cells(lngRow, 2)
If UCase(strThisName) = UCase(strName) Then
' We have a match, determine if the date value is greater than or less than the parameter.
If dtThisDate < dtDate Then AssignSerialNo = AssignSerialNo + 1
End If
End If
End If
If lngEmptyCount >= 10 Then Exit For
Next
End Function
Add the following formula in the first "Serial Number" cell and fill down ...
=AssignSerialNo(A2,B2,A:B)
... this is all assuming that your example table (with headings) starts from cell A1.
Let me know how you go.
Related
Is there a way to automatically copy and insert a line in an Excel sheet if the user selects a specific value from a drop down list?
Suppose the drop down list is column 2 (product) and takes values "Apple" & "Pear". Each time a user selects Apple, the lines should be duplicated. For instance
Name
Product
Price
A
Apple
1
B
Pear
1
C
Apple
1
If the user selects Apple, the end result should be
Name
Product
Price
A
Apple
1
A
Apple
1
B
Pear
1
C
Apple
1
C
Apple
1
If so, could anyone tell me how to do it ?
I have written this code so far but no new lines are being created
Sub Addline()
Dim Rng As Range
Dim LR as Integer
LR = Sheets("Customer").Range("A7").EndXlDown.Row
For i = 7 to LR
Set Rng = Sheets("Customer").Range("E" & i)
If Rng = "Apple" Then
Rng.Offset(Rowoffset).EntireRow.Insert Shift:= xlShiftDown
End If
Next
End sub
Then in worksheet_change()
Call Addline
If i modify line in the sheet, it ends up adding several lines instead of only one.
Here is my problem, I have those data on my Sheet1
A B C
1 Name Account Amount
2 John HSBC -20000
3 Ashley JPM 140000
4 Rose BAML 70000
5 John DB 10000
6 Rose Barclays -25000
7 Ashley JPM -3000
My goal is to use vba in order to sort lines and group them by name and amount. The result that I'm looking for in Sheet2 is :
A B C
1 Name Account Amount
2 John HSBC -20000
3 John DB 10000
4
5 Ashley JPM -3000
6 Ashley JPM 140000
7
8 Rose Barclays -25000
9 Rose BAML 70000
I already succeeded in taking the negative values first, but I still have difficulties in taking the rest and leave a blank line between groups.
Here is the code that I started :
Option Explicit
Sub sort_account()
Dim list_amount As Range, amount As Range
Dim b As Integer
Worksheets("Sheet1").Activate
Set list_amount = Worksheets("Sheet1").Range("C2", Range("C2").End(xlDown))
For Each amount In list_amount
If amount.Value < 0 Then
b = Worksheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row
Worksheets("Sheet2").Cells(b + 1, 1).Value = amount.Offset(0, -2)
Worksheets("Sheet2").Cells(b + 1, 2).Value = amount.Offset(0, -1)
Worksheets("Sheet2").Cells(b + 1, 3).Value = amount
End If
Next amount
Worksheets("Sheet2").Activate
End Sub
And this gives me as a result :
A B C
1 Name Account Amount
2 John HSBC -20000
5 Ashley JPM -3000
8 Rose Barclays -25000
I really have difficulties for the rest. Do you have any ideas ? I thank you in advance for that.
Nb : The order doesn't matter, I just want that the first values of each group is the negative amount.
Thanks!
If this were my project, I would do it in three distinct steps: Copy all the data from sheet 1 to sheet 2; Sort the data in the preferred order; Insert the blank rows, starting from the bottom.
The following code should do what you’re after.
Option Explicit
Sub sort_account()
Dim LastRow As Long, i As Long
Sheet2.Cells.ClearContents
Sheet1.UsedRange.Copy Sheet2.Range("A1")
Sheet2.Columns("A:C").Sort Key1:=Sheet2.Range("A2"), order1:=xlAscending, _
Key2:=Sheet2.Range("C2"), order2:=xlAscending, Header:=xlYes
LastRow = Sheet2.Cells(Rows.Count, "A").End(xlUp).Row
For i = LastRow To 4 Step -1
If Sheet2.Cells(i, "A") = Sheet2.Cells(i - 1, 1) Then
Sheet2.Cells(i - 1, "A").EntireRow.Insert
End If
Next i
End Sub
If your version of Excel supports Dynamic Arrays then you can do the following
This solution adds an extra row for each unique name, sorts the new data, and then blanks out the added rows.
E2 is =CHOOSE({1,2,3},UNIQUE(A2:A7),"temp",99999999). This creates an array with all the unique names in the first column, "temp" in the second column and 99999999 in the third (to be used for sorting).
F6 is =ROWS(A2:C7) the count of the rows in the data
F7 is =ROWS(E2#) the count of unique names
A10 is =IF(SEQUENCE(F6+F7)<=F6,A2:C7,INDEX(E2#,SEQUENCE(F6+F7)-F6,SEQUENCE(1,3))). This appends the original data to the new data.
E10 is =SORT(A10#,{1,3}), the appended data sorted.
I10 is =IF(F10:F18="temp","",E10#). This blanks out all the temps rows.
If your version of Excel supports LET you can do this in one cell.
=LET(data,A2:C7,
tempRows,CHOOSE({1,2,3},UNIQUE(A2:A7),"temp",99999999),
totalRows,ROWS(data),
uniqueNames,ROWS(tempRows),
outRows, SEQUENCE(totalRows+uniqueNames),
unsorted,IF(outRows<=totalRows,data,INDEX(tempRows,outRows-totalRows,{1,2,3})),
sorted,SORT(unsorted,{1,3}),
result, IF(INDEX(sorted,outRows,2)="temp","",INDEX(sorted,outRows,{1,2,3})),
result)
In Excel, I'd like a list of the 1st and 3rd Mondays in each month, for say the next six months after today.
Using a formula-based approach, I can find the 1st or 3rd Monday after today. I got stuck when trying to populate the list after that. Particularly, a challenge is to account for months with 5 Mondays in them. The formulas get very complex very quickly!
This is the solution I have so far:
Private Sub Auto_Open()
Dim i, mday As Integer
Dim row, col As Integer
Dim d As Date
Dim min As Integer
min = 14 'Minimum set up period
col = 1 'Column to put results in
row = 2 'Row to start from
d = Date + min + 9 - Weekday(Date) 'Find Monday after Minimum set up period
Worksheets("options").Activate
For i = 1 To 26 'Results up to 26 weeks in future
mday = day(d)
If (mday - 7 <= 0) Then 'First week
Cells(row, col).Value = d
row = row + 1
ElseIf (mday - 14 > 0 And mday - 21 <= 0) Then 'Third week
Cells(row, col).Value = d
row = row + 1
End If
d = d + 7 '+1 week
Next
Worksheets("New Starter").Activate
End Sub
Try this:
On A1 place the first day of one month. On A2 place: =EOMONTH(A1,0)+1
On B1 place =A1+MOD(8-WEEKDAY(A22,2),7).
On C1 place =B1+14
Drag an drop down.
The first column is taking the first day of one month and consecutive month, the column Bis returning the first monday and colunm C is returning the third monday of that month.
If you are looking for the 5th monday:
On D1 place: =IF(A1+MOD(8-WEEKDAY(A22,2),7)+28<EOMONTH(A1,0)+1,A1+MOD(8-WEEKDAY(A22,2),7)+28,"")
Being beginner and first time on this site, I truly appreciate your help.
WK 1 WK 2 WK 3 WK 4 WK 5 TOTAL HOURS TOTAL OF FIRST 3 WEEKS <> 0
John 10 0 5 6 5 26 21
Smith 4 1 10 3 4 22 15
Peter 0 4 4 4 2 14 12
Susan 5 5 0 5 8 23 15
From my table I want to add only the first three columns that contain no zero. If there's zero on first three, check on next column and add it up to complete three columns again with no zero value. Some function like in Col H TOTAL OF FIRST 3 WEEKS <>0 (where I had to do it manually).
If I can learn set of VB code or any example with formula or macros, thank you so so much. I'm using Excel 2007.
This is the complicated formula Ali M refers to. It's an array formula entered with ctrl-shift-enter:
=IF(COUNTIF(A2:F2,"<>0")=0,0,SUM(A2:INDEX(A2:F2,SMALL(IF(A2:F2<>0,COLUMN(A2:F2),""),MIN(3,COUNTIF(A2:F2,"<>0"))))))
Note that it works if there are less than three non-zero values.
you can use formula but it would be complicated. instead you can use this subroutine that act exactly as you want!
Public Sub y()
Dim i, sum, c As Integer
Dim Rng, Row, cell As Range
Set Rng = Range("B2:F5")
i = 0
For Each Row In Rng.Rows
For Each cell In Row.Cells
If (cell.Value <> 0 And i < 3) Then
sum = sum + cell.Value
i = i + 1
End If
Next cell
Cells(Row.Row, 7).Value = sum
sum = 0
i = 0
Next Row
End Sub
It always put the sum in column H. you can change it by changing this line:
Cells(Row.Row, 7).Value = sum
I have the following dataset:
Name Code Output Type
Alice Apple -100 B
Alice Apple +60 S
Alice Banana -52 S
Alice Apple +40 S
Alice mango -5000 S
Bob Kiwi -500 B
Bob Kiwi +500 S
Bob peach -40 S
Dan Banana -50 S
Dan peach +28 S
I want to reduce this data using the following criteria:
IF records with a given name do not contain "B" in any record in column "Type" then I don't want to consider it. So the "Dan" records are out. Of the 5 Alice records, the first one has a "Type" "B" and Bob has a "Type" "B" as well.
For others, I want to see which fruit numbers don't net out to zero.
So this is what I would like to see:
Name Code output Type
Alice Banana -52 S
Alice mango -5000 S
Bob peach -40 S
Right now, First I am doing a SumIfs over Name and Code.
=SUMIFS($C$2:$C$21,$B$2:$B$21,B2,$A$2:$A$21,A2)
Then I create a column where I give the value 1 when type = B and 0 otherwise.
=IF(D2="B",1,0)
Then I am doing a Sumif to figure out which names have a "B"
=SUMIF($A$2:$A$21,A2,$F$2:$F$21)
Then I will filter the ones which don't have a B and where the SUMIFS are not zero.
Right now this is in-sheet. I intend to use these formula in a VBA macro. Is there a better way to do this? Say without creating new columns?
Assuming your columns are in the correct order as above. the below code will generate a new 5th column with 0, 1.
Option Explicit
Option Compare Text
Sub SetFilter()
Dim sh As Worksheet: Set sh = Sheet1
' YOU MUST add reference "Microsoft Scripting Runtime" from tools menu to use this object...
Dim FruitSums As New Scripting.Dictionary ' key = name of fruit, value is running total
FruitSums.CompareMode = TextCompare
Dim iR As Integer
Dim lbl As String
Dim value As Variant
'get fruit sums
For iR = 2 To sh.UsedRange.Rows.Count
lbl = sh.Cells(iR, 2)
value = sh.Cells(iR, 3)
If IsNumeric(value) Then
If FruitSums.Exists(lbl) Then
FruitSums(lbl) = FruitSums(lbl) + CLng(value)
Else
FruitSums(lbl) = CLng(value)
End If
End If
Next
' calculate the filter column
For iR = 2 To sh.UsedRange.Rows.Count
If sh.Cells(iR, 4) = "B" Then
sh.Cells(iR, 5) = 1 ' ok, is a B
Else
lbl = sh.Cells(iR, 2)
If FruitSums.Exists(lbl) Then
If CLng(FruitSums(lbl)) = 0 Then
sh.Cells(iR, 5) = 0 ' not ok, is total 0
Else
sh.Cells(iR, 5) = 1 ' ok, is not 0
End If
Else ' this case should not occur
sh.Cells(iR, 5) = -1 ' unexpected output.
End If
End If
Next
End Sub