Extract Top 10 products from a Excel Database (Multiple criteria) - vba

I have a database (example attached) that gets updated automatically from other 70 files on monthly bases by macro.
I would like to extract Top 10 ordered products based on various criteria.(example attached) The file will be more complex, just tried to keep it simple for demo.
I have used some formula =LARGE('Part numbers'!A3:A301,ROW(INDIRECT("1:"&ROWS('Part numbers'!A3:A301)))) & =SUMPRODUCT((Combine!B1:B10000='DATA '!Y3)*(Combine!C1:AB1=A1)*(Combine!D1:D10000=AC2),Combine!C1:AB10000)that aloud me tho get the SUM of top5 products the problem is when I use the INDEX MATCH to extract the name of the product if there are 2 same values the formula is stooping always at the first product name + I need to add a new criteria witch is the month
Thank you in advance for any suggestions
Its ok if it is macro or formula
.

Trying fixing the range by making reference using the INDIRECT-function:
=SUMPRODUCT((INDIRECT("Combine!$B$1:$B$5000")='DATA '!Y3)*(Combine!$C$1:$AB$1=$C$1)*(INDIRECT("Combine!$D$1:$D$5000")=$AC$2),INDIRECT("Combine!$C$1:$AB$5000"))
This ensures that the Range you are referencing, e.g. $B$1:$B$5000 doesn't become $B$1:$B$4999 when for example Row 2 is deleted.

maybe the pivot-table can help u?
there some autofilters to show the top x
if u want to set a dynamic filter on pivot table u can use this:
Sub UpdateFilter()
Dim m As String
m = Month(Now())
[filPivot] = m
End Sub

Issue solved more less.
The other problem that I have now is with the formula =SUMPRODUCT((Combine!$B$1:$B$5000='DATA '!Y3)*(Combine!$C$1:$AB$1=$C$1)*(Combine!$D$1:$D$5000=$AC$2),Combine!$C$1:$AB$5000) initially I have the range of the formula =5000 but every time when my database is updated this number is decreasing till it reaches =10.
My database is updated by a macro that deletes Blanks every time,I believe this could be the issue.
Any ideas how to make this =5000 range steady?

Related

Dynamic reference in excel formula

I have the following array formula which works for what I want to do but I'm trying to change the formula when a user selects a value.
=INDEX($A$2:$B$70,SMALL(IF($A$2:$B$70=$A$121,ROW($A$2:$B$70)),ROW(1:1))-1,1)
It's used for a monthly report and the user will choose from a drop down the day of the month, e.g 1,2,3 - 31.
So if the user selects 1 from the drop down menu I want the formula to use the above formula.
If they select 2 for example I want the formula to move over a column so it would change to
=INDEX($A$2:$C$70,SMALL(IF($A$2:$C$70=$A$121,ROW($A$2:$C$70)),ROW(1:1))-1,1)
and so on moving over a column at a time.
It this possible at all or can it even be done without VBA?
I have an example of what I want done on the following link
https://docs.google.com/spreadsheets/d/1MDOzoQxYLgW-UOyljZsMwSu8zyAB7O2k1V-bTNP5_F0/edit?usp=sharing
All the data is on the first tab called staff. Each employee has a row and the duty assigned under the corresponding day column.
On the Roster tab it summarises each day. So what I am trying to get to happen is when you choose the day of the month (or preferably the actual date) the sheet changes to reflect the data.
At the moment the code I have working does for just Day 1 because the column references are coded into the formula. I was hoping to somehow choose 6 for example from the drop down and then the formula will map chosen day to the corresponding range in the raw data and update the formula and change the formula from Staff!$A$2:$B$68 to Staff!$A$2:$G$68.
If the formula finds no more entries if shows #NUM! but I intended to use the function ISERROR() to replace #NUM! with "".
This is what I'm trying to achieve it if makes sense?
There are a few issues here/ You are returning the value from column A so the first range can be $A$2:$A$70 and that means you don't need the 1 to specify the column_num. The IF statement was covering A2:C70 when you really only want either B2:70 or C2:C70 depending on the 1 or 2.
Assuming that A122 has either a 1 or 2 in it then,
=INDEX($A$2:$A$70, SMALL(IF(INDEX($B$2:$C$70, 0, $A$122) = $A$121, ROW($1:$69)), ROW(1:1)))
Standard non-array alternative,
=INDEX($A$2:$A$70, SMALL(INDEX(ROW($1:$69)+(INDEX($B$2:$C$70, 0, $A$122) <> $A$121)*1E+99,, ), ROW(1:1)))

Excel, cycle through columns and rows

I have an excel table that calculates how many materials we need to order per job we are doing.
What I want to accomplish is to create a button that will copy the existing table on to page 2 of my excel workbook. The table is two columns wide. Therefore I would like to click the button, it copies the table thats on A and B of page 1 onto page 2 A and B. After having done so, I want excel to remember A and B are taken and next time I click the button, it goes in column C and D, then E and F and so on (always on page 2).
to explain why I would like this, I need to order 1000 sq ft of materials, but in sections. only 250 sq ft of materials at a time. So, I want to fill out how much im ordering, click the button and it saves the information of what was ordered on page 2. That way its easy to go back and see what was done, what date, how much was ordered, what is left to order, etc.
I know with numbers it would be easy by just incrementing i by two at every button click, but I dont know how to go about doing this for the excel columns (letters).
Is there some easy command I just cannot find online to do this sort of thing ?
Thanks for your help !
What you should learn in VBA and modify in this code below is how to determine the actual range of the table on Sheet1 -- instead of hard-coding it to "A1:B10"
UPDATE
Not sure why the previous version didn't work for you, but I've updated the code below to store the next column location in a helper cell to see if that works for you.
Option Explicit
Sub Button1_Click()
Dim srcTable As Range
Dim dstTable As Range
Dim nextLoc As Range
Set srcTable = Sheets("Sheet1").Range("A1:B10")
Set nextLoc = Sheets("Sheet2").Range("A20")
'--- if this is your first copy, then cell A1 should be empty
If IsEmpty(Sheets("Sheet2").Range("A1").Value) Then
Set dstTable = Sheets("Sheet2").Range("A1:B10")
nextLoc.Value = 3 'next location is column 3
Else
'--- we're adding the next table...
Set dstTable = Sheets("Sheet2").Cells(1, nextLoc.Value)
nextLoc.Value = nextLoc.Value + 2
End If
srcTable.Copy dstTable
End Sub

Find Last Row of Name with constantly changing names

I'm really stuck on this one. I have a spreadsheet with thousands of rows. I use this code to filter them based off of product in the E column.
Sub IsolateCCENCE()
Dim Operations As Workbook
Dim Operations_Sheet As Worksheet
Set Operations = Workbooks("Operations for Macros")
Set Operations_Sheet = Operations.Worksheets("Operations")
Operations_Sheet.Range("$A$6:$AH$13108").AutoFilter Field:=5, Criteria1:="=CCE" _
, Operator:=xlOr, Criteria2:="=NCE"
End Sub
Which works and leaves me with just under 1700 rows. Within these rows, in the A column, there are company names. Each company takes up approximately 20 rows. Each row represents a payment and has a corresponding date, in the D column. I need a macro (I'm assuming with a loop) that will then do the following:
Go through the rows, find the last row for each company
In that row, find the corresponding date
If that date is within 30 days from today, generate an email
Part 3 is easy. But Part 1 and 2 I can't seem to get. The data is always going to be changing.
Maybe it would be easier to have all of the data copy and pasted into another spreadsheet and then filter through every single company, find the last row (and thus the corresponding date)? But I don't know I would have a macro defined to filter through each company when the company names will be changing constantly.
I appreciate any help. Thanks in advance!
If a specific company name in say F1 then:
=MIN(IF(A:A=F1,D:D))
entered with Ctrl+Shift+Enter should give you the earliest date for the company named in F1, that if more recent than today()-30 (or less far into the future than today()+30 ?) you might use for your e-mail trigger (subject to other filtering etc).

Is there a way to check for duplicate values in Excel WITHOUT using the CountIf function?

A lot of the solutions here on SO involve using CountIf to find duplicates. When I have a list of 100,000+ values however, it will often take minutes for CountIf to search for duplicates.
Is there a quicker way to search for duplicates within an Excel column WITHOUT using CountIf?
Thanks!
EDIT #1:
After reading the comments and replies I realize I need to go into greater detail. Let's pretend I'm a birdwatcher, and after I return from a birdwatching trip I input anywhere from 1 to 25 or 50 new birds that I saw on my trip into my "Master List of Birds Seen". This is really a dynamically growing list, and with each addition I want to make sure I'm not duplicating something that already exists in my list.
So, in column A of my file are the names of the birds. Column B-M might contain other attributes of the birds. I want to know if a bird that I just added in column A after my latest birdwatching trip ALREADY exists somewhere ELSE in my list. And, if it does, I would manually merge the data of the 2 entries and throw away some and keep some after careful review. I clearly don't want to have duplicate entries of the same bird in my database.
So, ultimately I want some indication that there is or isn't a duplicate somewhere else, and if there is duplicate please tell me what row to look in (or highlight or color both of the duplicates).
The fastest way that I know of (in case you are using Excel 2007/2010/2011) is to use Data (In Ribbon) | Remove Duplicates to find the total number of duplicates OR to remove duplicates. You might want to move data to a temp sheet before you test this.
The 2nd fastest way is to use Countif. Now Countif can be used in many ways to find duplicates. Here are two main ways.
1) Inserting a New Column next to the data and putting the formula and simply copying it down.
2) Using Countif in Conditional formatting to highlight cells which are duplicates. For more details, please see this link.
suggestions for a macro to find duplicates in a SINGLE column
EDIT:
My Apologies :)
Countif is the 3rd fastest way!
The 2nd fastest way is to use Pivot Tables ;)
What exactly is your main purpose of finding duplicates? Do you want to delete them? Or Do you want to highlight them? Or something else?
FOLLOWUP
Seems like I made a typo in the formula. Yes for large number of rows, CountIf does take minutes as you suggested.
Let me see if I can come up with a VBA code to suit your exact needs.
Sid
You can use VBA - the following function returns a list of unique entries within a list of 100,000 in less than a second. Usage: select a range, type the formula (=getUniqueListFromRange(YourRange)) and validate with CTRL+SHIFT+ENTER.
Public Function getUniqueListFromRange(parRange As Range) As Variant
' Returns a (1 to n,1 to 1) array with all the values without duplicates
Dim i As Long
Dim j As Long
Dim locKey As Variant
Dim locData As Variant
Dim locUniqueDict As Variant
Dim locUniqueList As Variant
On Error GoTo error_handler
locData = Intersect(parRange.Parent.UsedRange, parRange)
Set locUniqueDict = CreateObject("Scripting.Dictionary")
On Error Resume Next
For i = 1 To UBound(locData, 1)
For j = 1 To UBound(locData, 2)
locKey = UCase(locData(i, j))
If locKey <> "" Then locUniqueDict.Add locKey, locData(i, j)
Next j
Next i
If locUniqueDict.Count > 0 Then
ReDim locUniqueList(1 To locUniqueDict.Count, 1 To 1) As Variant
i = 1
For Each locKey In locUniqueDict
locUniqueList(i, 1) = locUniqueDict(locKey)
i = i + 1
Next
getUniqueListFromRange = locUniqueList
End If
error_handler: 'Empty range
End Function
If using Excel 2007 or later (which is likely from the 100,000+ values) you can choose:
Home Tab | Conditional Formatting > Highlight Cell Rules > Duplicate Values...
Right-click a highlighted cell and filter by selected cell color to show just the duplicates (be aware however this can be slow with conditional formatting).
Alternatively run this code and filter for colored cells which takes only a second on 100,000 cells:
Sub HighlightDupes()
Dim i As Long, dic As Variant, v As Variant
Application.ScreenUpdating = False
Set dic = CreateObject("Scripting.Dictionary")
i = 1
For Each v In Selection.Value2
If dic.exists(v) Then dic(v) = "" Else dic.Add v, i
i = i + 1
Next v
Selection.Font.Color = 255
For Each v In dic
If dic(v) <> "" Then Selection(dic(v)).Font.Color = 0
Next v
End Sub
Addendum:
To select only duplicate values without code or formulas, i have found this method useful:
Data Tab | Advanced Filter... Filter in Place, Unique Records Only, OK.
Now select the range of unique values and press Alt+; (Goto Special... Visible cells only). With this selection clear the filter and you will see that all unselected cells are duplicates, you can then press Ctrl+9 (Hide Rows) to show just the duplicates. These rows can be copied to another sheet if needed or marked with an "X".
You do not mention what you want to do when you find them. If you merely want to see where they are...
Sub HighLightCells()
ActiveSheet.UsedRange.Cells.FormatConditions.Delete
ActiveSheet.UsedRange.Cells.FormatConditions.Add Type:=xlCellValue, Operator:=xlEqual, Formula1:=ActiveCell
ActiveSheet.UsedRange.Cells.FormatConditions(1).Interior.ColorIndex = 4
End Sub
Preventing Duplicates with Data Validation
You can use Data Validation to prevent you entering duplicate bird names. See Debra Dalgelish's site here
Handling existing duplicates
My free Duplicate Master addin will let you
Select
Colour
List
Delete
duplicates.
But more importantly it will let you run more complex matching than exact strings, ie
Case Insensitive / Case Sensitive searches (sample below)
Trim/Clean data
Remove all blank spaces (including CHAR(160)) see the " mapgie" and "magpie" example below
Run regular expression matches (for example the sample below replaces s$ with "" to remove plurals)
Match on any combination of columns (ie Column A, all columns, Column A&B etc)
I'm surprised that no one has mentioned the RemoveDuplicates method.
ActiveSheet.Range("A:A").RemoveDuplicates Columns:=1
This will simply remove any duplicate entries on the active worksheet in column A. It takes milliseconds to run (tested with 200k rows). Mind you, this will strictly delete all the duplicate entries. Although that isn't how the original question was worded, I do believe that this still serves your purpose.
One simple way of finding unique values is to use the advance filter and filter for unique values only and copy and paste them into other sheet as when the pivot is removed you will get the whole data with the duplicate in them.
Sort the range
and in next column put `=if(a2=a1;1;if(a2=a3;1;0))
"1" will be displayed for duplicates.

Excel countif Pulling apart a cell to do different things

Excel 2007
I have a row of cells with variation of numbers and letters (which all mean something.. not random.)
It's basically a timesheet. If they take a sick day they put in S, if they take a partial sick day they put in PS. The problem is they also put in the hours they did work too. They put it in this format: (number)/PS.
Now if it were just letters I could just do =countif(range,"S") to keep track of how many s / ps cells there are. How would I keep track if they are PS where it also has a number separated by a slash then PS.... I also still need to be able to use that number to add to a total. Is it even possible or will I have to format things different to be able to keep track of all this stuff.
Assuming this is something like what your data looks like:
A B C D E
1 1 2 S 4/PS 8
...then you could do this:
1- add a column that just totals the "S" entries with a COUNTIF function.
2- add a hidden row beneath each real data row that will copy the numerical part of the PS entries only with this function in each column:
=IF(RIGHT(B1,2)="PS",IF(ISERROR(LEFT(B1,LEN(B1)-SEARCH("/",B1)-1)),"",INT(LEFT(B1,LEN(B1)-SEARCH("/",B1)-1))),"")
3- add another column to the right that just totals the "PS" entries by summing the hidden row from step 2.
3- add another column that totals everything by just summing the data row. that will ignore the text entries automagically.
4- have a grand total column that adds those three columns up
If you don't want to see the "S" and "PS" total columns, you can of course just hide them.
So in the end, the sheet would look like this:
A B C D E F G H I J
1 1 2 S 4/PS 8 1 4 11 16
2 4 <--- hidden row
HTH...
My quick take on this is:
pass the cell value into a CSTR function, so no matter what is entered you will be working with a string.
parse the information. Look for S, PS, or any other code you deem to be valid. Use Left or Right functions if you need to look at partial string.
check for number by testing the ascii value, or trying a CINT function, which will only work if the string can be converted to integer.
If you can show a sample of your cells with variation of numbers and letters I can give you more help. Hope this works out.
-- Mike