Ive got a spreadsheet which has 3 columns. These are name, age, value
I want to create an incell dropdown list based on unique values in the "name" column. There could be two cells in the "name" column with "John" in them for example. i.e. duplicates
When "John" is selected in a dropdown I want to create another dynamically created dropdown that shows only the age's for the entries. For example, if there were two rows with "John" in the name column then the other dropdown should show the age values for each of these only. Based on the two selections id like to show whatever's in the value column.
Do you think i need to use macros to achieve this?
To complicate matters the amount of rows in the list may change over time and therefore the blank names will need to be removed. The 'ignore blanks' when creating the incell dropdown does nothing and they are still shown in the list.
Any advice would be appreciated.
Based on your description I think you are creating list validated drop down cells. The lists can be subsets of an initial database. An example of such a database might look like:
With the validated drop downs adjacent like:
This can be achieved in a few steps.
1) Create a subset of all of the unique names in a helper column, I will do this in J.
=IFERROR(IF(NOT(INDEX($A$2:$A$20,MATCH(0,INDEX(COUNTIF($J$1:J1,$A$2:$A$20),0,0),0))=""),INDEX($A$2:$A$20,MATCH(0,INDEX(COUNTIF($J$1:J1,$A$2:$A$20),0,0),0)),NA()),"")
The range I am testing for uniques only extends to A20 but you could take this as far as you like.
2) Since you are doing this with validation lists that a user must select, you should probably alphabetize them. I do this in the next column over K.
=IFERROR(INDEX(INDIRECT("J1:J"&SUMPRODUCT(--(LEN(J:J)>0))+1),MATCH(ROWS($J$2:J2),COUNTIF(INDIRECT("J1:J"&SUMPRODUCT(--(LEN(J:J)>0))+1),"<="&INDIRECT("J1:J"&SUMPRODUCT(--(LEN(J:J)>0))+1)),0)),"")
This formula is an array formula and must be entered with ctrl+shift+enter for the first cell and then you can fill down. In a near by cell let's keep track of the complete range occupied by meaningful names used to make our alphabetized list (no blanks). Enter the following:
="K2:K"&SUMPRODUCT(--(LEN(J:J)>0))+1
Note that this is assuming my uniques are in column J. If you put them elsewhere you will need to modify this.
3) At this point we can make our first validated drop down. I'm using excel 2016 so I select the cell where I want the drop down (in my case E2) and then go to Data -> Validation. Under this I choose Allow: List; and Source: I enter the following:
=INDIRECT($K$1)
As K1 is the cell where I am keeping track of the range of useful and alphabetized uniques. Example:
Now back on the main sheet I have a drop down in E2 featuring that list. Next let's build the subset of useful ages.
4) In a new helper range (for me 'M2:M10') enter the following:
=IFERROR(SUM(LARGE(IF(($A$2:$A$20=$E$2)*ROW($A$2:$A$20),$B$2:$B$20,""),COUNTIF($A$2:$A$20,"="&$E$2)-ROW()+ROW($M$2))),"")
This is another array formula and must be submitted with ctrl+shift+enter, but in contrast the other array formula you must enter this for the whole range at once, I just selected a small number of cells because I know I won't have more than a few ages. If you suspect you will have more make this range large.
In the same fashion as the names lets track the range of useful ages in a nearby cell (I chose N1).
="M2:M"&COUNTIF((M:M),">0")+1
5) Make the next validated drop down. Select a cell (I picked F2) and again Data->Validation, choose a list and now use the age source:
=INDIRECT($N$1)
6) Getting the value that corresponds to the individual with that age is easy now. In the next cell over from enter:
=SUM(IF((A2:A20=E2)*(B2:B20=F2),C2:C20))
There you have it. An example of what my completed sheet looks like is here:
One last thing to mention. When you do this and toggle to a new name, it will not reset the age drop down automatically. So to make this appear reset, you can use some clever conditional formatting. I formatted F2 & G2 with the following rule and set the font color to white:
So while the value in each of those cells doesn't reset when a drop down with higher precedence is changed it appears to blank out forcing the user to pick a new age from that drop down.
Good luck!
Related
I have a table with all sorts of data (description, specifics, price, ...) stored in tab2.
In tab1 i want to be able (for an unfixed amount of lines) to first select a value from column 1, this i've got figured out, and then based on this value populate the dropdownlist on column 2. But this is the problem atm, i can't get this to work for the life of me... There's not a single option giving me this possibility to perform this on 100's of lines benath eachother.
Can someone please help me.?
Thanks in advance
Hidde
I assumed how the data in tab2 may be structured, but it's a bit unclear.
I assumed that in column 1 there could be values that occur more than once and the different values in column 2 that are behind the value are to be part of the second drop down data list.
If you're using office 365 for the first data of your drop-down list:
=UNIQUE(FILTER(tab2!A:A,tab2!A:A<>""))
for data in your second drop-down list (if the first drop-down is in A1):
=UNIQUE(FILTER(tab2!B:B,tab2!B:B=A1))
For older version of Excel I have the following, which is not as neat as the solution above:
If your 1st drop-down in tab1 is in cell A2, type the following in B2:
=IFERROR(INDEX('tab2'!B:B,MATCH(0,IF($A$2='tab2'!A:A,COUNTIF($B$1:$B1,'tab2'!B:B),""),0)),"")
Enter as array with ctrl + shift + enter
Drag down the formula to get the unique values from tab2 column B that meet the chosen value in A2.
In you second drop-down (cell C3 for instance) type the following in the source for your drop-down list:
=OFFSET('tab1'!$B$2,,,COUNTA($B:$B),)
This will result in the desired data in your drop-down, however this also shows all blanks from how far you copied down your formula in column B in your drop-down list.
Also referencing to whole columns in this examples makes it way slow, so please narrow the ranges as much as possible.
I hope somebody else can show a cleaner/faster solution, but this is something.
I want to filter a table in excel and return a different column to create a list for data validation.
My table contains a list of names and one of the columns is a Yes or No for being an admin.
I want to create a data validation list on another sheet and use the filter table to just show those names that have a Yes in their associated row in the table.
I recorded a macro to filter the table to show just the rows I need and now want those names to appear in the list.
ActiveSheet.ListObjects("Staff").Range.AutoFilter Field:=8, Criteria1:="<>"
Is this possible?
I had tried using the =FILTER() formula but it's not available in my version of Excel.
I'd prefer to do it with a formula in the validation settings rather than VBA.
This is something of a faff but I think it works, though by no means the best way of doing it.
Table of data on the left.
The "Yes" names are listed in D1 and down, the formula is an array (use Ctrl, Shift and Enter to confirm). I'm sure someone cleverer than me can shorten this.
=IF(ROWS(D$1:D1)<=COUNTIF(Table1[Admin],"Yes"),INDEX(Table1[Name],SMALL(IF(Table1[Admin]="Yes",ROW(Table1[Name])-ROW($A$2)+1),ROWS(D$1:D1)),1),"")
E1 is just the total of the names shown in D (another array formula):
=SUM(IF(LEN(D:D)>0,1,0))
The DV is in G1 and the formula there is
=OFFSET(D1,0,0,E1,1)
If you change e.g. Sarah to Yes, her name will appear in D and will be added to the DV list.
Once you've applied your filter to column 8, you can select the range that remains visible in a different column using:
ActiveSheet.ListObjects("Staff").Range.Columns(8).SpecialCells(xlCellTypeVisible).Offset(0, -2)
This would return a range consisting of column 6 (8-2) of your table. Adjust to suit your needs.
You could then cycle through that range one cell at a time and populate a new range from it, accordingly.
I would like to find the nth value in a list that matches specific criteria and have those values printed in separate places in separate worksheets.
More specifically I have a list of invoice numbers either beginning with a number or with PF and I want the first (or second, third etc) value beginning with PF to show on the Proforma Invoice worksheet, and the first (or second, third etc) value beginning with a number to show on the Invoice worksheet.
At the moment I have a selection of invoice numbers like so:
Invoice #
PF17-0982
43256
65342
96038
PF16-0934
10293
And I would like to print the nth value on this list matching the criteria I give, so either beginning in a number or beginning in PF, in a separate worksheet.
Initially I tried
=IF(LEFT('Top Sheet'!S5)="P",'Top Sheet'!S5,"")
which works to find the number beginning with PF but obviously only for the first cell in the list.
I also have
=IF(ISNUMBER(LEFT('Top Sheet'!S5)*1),'Top Sheet'!S5,"")
Which again works wonderfully for the first value in the list but not for much else.
So, naturally, I googled and tried using INDEX and MATCH and SEARCH functions as found here https://exceljet.net/formula/get-first-match-cell-contains but I don't want the output to be another list dependant on only one of the values in the invoice number list. However I don't mind having an intermediate list (e.g. list of TRUE and FALSE values) which will ultimately lead to me having a single output. I have this list at the moment which was done using:
=SUMPRODUCT(--ISNUMBER(SEARCH({"PF"},'Top Sheet'!S5)))>0
And that brings me here, I've tried various variations of the above techniques and failed hopelessly. I either get an error of some description or just TRUE and FALSE values. I hope this makes sense.
Another formula approach, with which you can enter the formula normally, is to use the AGGREGATE function to determine the row number within the array of invoices. With the SMALL operator, you can work on an array, ignore errors, and return multiple values.
If Invoices is a named range containing your list of invoices, then:
For invoices starting with PF
=IFERROR(INDEX(Invoices,AGGREGATE(15,6, 1/(LEFT(Invoices,2)="PF")*ROW(Invoices)-MIN(ROW(Invoices))+1,ROWS($1:1))),"")
For invoices starting with a digit
=IFERROR(INDEX(Invoices,AGGREGATE(15,6,1/ISNUMBER(-LEFT(Invoices,1)*ROW(Invoices))*ROW(Invoices)-MIN(ROW(Invoices))+1,ROWS($1:1))),"")
For either of these formulas, enter in some cell and fill down until the formula returns blanks. The ROWS... argument will increment and return the appropriate k for the SMALL function.
Another method would be to use a simple Filter, then copy/paste the visible cells to where you want.
Or you could use the Advanced Filter, which has a built-in method to paste the results to another location.
In order to extract multiple items from a list you can use the INDEX function with SMALL to create an array formula.
=IFERROR(INDEX($B$4:$B$9,SMALL(IF((ISNUMBER($B$4:$B$9)),ROW($B$4:$B$9)-3),ROW(1:1)),1),"")
IMPORTANT: use CTRL+SHIFT+ENTER when entering this formula to make it an array formula.
This formula takes the first numeric value from your list. If the formula is changed to ROW(2:2) it would select the 2nd numeric value from the list and you can autofill the formula down to extract as many as you like.
It's quite a complicated formula to follow but you first index a range "INDEX(B4:B9" then use SMALL with an if statement "(ISNUMBER(B4:B9)". Then define the first row of the source data "ROW(B4:B9)-3)" the minus 3 is because it's 3 rows from the top. Next the row that matches your criteria that you want to extract "ROW(1:1)" and last the column that contains the value that you want "),1"
I'm not the best person to explain this formula but there are some good tutorials online.
PivotTable alternative:
(optional) select the range of cells including the header "Invoice #" cell
Insert tab > PivotTable
make sure the header cell is included in the Table/Range: field
select Existing Worksheet and the Location range where you want the filtered list
on the PivotTable Field List that shows up on the right check the Invoice # field
on the sheet, in the Row Labels cell click on the triangle filter button and select Label Filters > Begins With... > PF
(optional) in the Design tab click Grand Totals > Off for Rows and Columns, uncheck Column Headers, and rename the Row Labels cell text if needed
For the numbers, you can copy the PivotTable and change the Label Filter to Less Than... > A
Whenever the source Invoice # range changes, you can click Refresh All on the Data tab for the PivotTables to refresh.
I am working on a project within an excel database and am trying to match 4 different properties which all have their own columns (A,B,C,D) to find a corresponding value on a different page (Sheet2!). One sheet 2 the values are once again found in their own columns (B,C,D,E) and if all of the values match I then want the value in column A Sheet2! to be displayed in column E on sheet1!
The problem is is that often times the values on Sheet1! will be able to match up with as many as 12 different unique rows on Sheet2! making this incredibly difficult with only intermediate experience in VBA. There can be duplicates that match all of the criteria. And for when this happens I would like to return the first item that matches, as long as a previous match was not made on that item.
To give you more information we have given products different values that designate where they belong based off their velocity. This has split them up into Section#, ShelvingType, Verticle, and Horizontal Location. And we are looking to match these values to the values of our previously existing locations that we have that have corresponding(matching) numbers or text values.
To go into even more detail, on sheet one we have the products with values on where they should go. One sheet two with have pre-existing locations for which products can go that have values that are represntative of that location. So, we want to take the products NEW location values off page one and match the existing location values on page two. The problem is that for every location there are up to 12products that could go there. So, we want to go in order saying that product1 goes in the first location with matched values while product2 goes in the next location with matched values, and so on and so fourth
Edited to remove previous responses
Based on your further elaboration, if I understand correctly, I agree with the comment left by #Aaron Contreras. You should create helper columns which show a 'unique ID' where all criteria match, as well as an additional helper column which increases as more items of the same criteria code are found. This will become the 'ultra-unique' ID for that item.
At this point I don't think array formulas will be possible, though I will leave in the answer which provides the result of the first matching criteria without further eliminating 'previously used' results. This could likely be further refined, but I doubt it would be more elegant than simply using the helper columns shown in my response below. At least, I can't figure out how to do it elegantly.
To summarize my assumptions:
-Your available space is in sheet1; column A contaions something like the location of that available space, and columns B-E contain criteria for anything which will be stored there.
-Your new list of items to be placed in a location is in sheet2; columnA will be where our formula goes, showing the available location to put that item.
Enter on Sheet1
In column F on sheet1, drag down this formula:
=B1&C1&D1&E1
This will create a unique ID key to be searched in the future.
However, as there will be multiple hits for the same criteria on sheet1 (because multiple locations can hold the same thing), we need to make each row 'more unique' by showing how many times that criteria combination has already occurred. This formula will thus go in column G on sheet1, starting in cell G1 and dragged down:
=F1&countif($F$1:F1,F1)
As you drag it down, this will count the nth time that the specific combination of criteria has appeared on sheet1.
Enter on Sheet2
Create the same columns in sheet2, in columns F & G. The formulas will be exactly the same, they will just refer to sheet2 instead of sheet1.
Then the formula in column A in sheet 2, dragged down from A1, would be:
=index(sheet1!A:A,match(G1,sheet1!G:G,0))
This will find the first time that all criteria match from sheet1, for the nth time that this criteria has been used on sheet 2.
Let me know if there is anything here I've missed.
Unfinished array method
Again, array responses are possible, but for your purposes likely unnecesarry; you should probably have a unique ID for all combinations anyway. However, in case you want to use the array method, you can like so (does not account for multiple locations being used; left for reference only if you want to take this up):
In sheet2, enter the following formula [confirmed with CTRL + SHIFT + ENTER instead of just ENTER, every time the formula is changed] on the row 1, with the different criteria (and copied down):
=index(Sheet1!A1:A100,match(1,(Sheet1!B1:B100=B1)(Sheet1!C1:C100=C1)(Sheet1!D1:D100=D1)*(Sheet1!E1:E100=E1),0))
This uses the inherent boolean logic of "TRUExTRUE = TRUE; TRUExFALSE = FALSE; FALSExFALSE = FALSE", to find the first row where there is a match of all criteria. Note that I have not made this go all the way down all columns, as with Array formulas this is a significant resource hog.
Assuming that your data starts from 2nd row (1st row for lables):
{MATCH(A1&B1&C1&D1,B2:B100&C2:C100&D2:D100&E2:E100,0)}
The above is an array formula, so you don't have to input the curly brackets {.
Simply press Ctrl + Shift + Enter after typing the formula
More info
Normally, where the values in the column of a lookup array are unique there is only a need to match the value in the last dynamic data validated list with the value in the relevant column of the lookup array to provide the range of values for the next dynamic data validated list. However, where values in a column are not unique, is there a way to create dynamic data validated lists in Excel? I assume that this could be achieved by ensuring the values in more than one column must have been selected in order to provide the dynamic range for the third, e.g. X must have been selected in the first drop down and Y in the second, in order to lookup the values for the third dynamic data validated list, but I can't work out how.
As an example let's say that my lookup array looks like this:
Field1,Field2,Field3
A,C,F
A,C,G
A,D,H
B,E,I
B,C,J
B,C,K
If I select B in the first dynamic data validated list and C in the second, I would want the range for the third to be J and K, not F, G, J and K.
You'd have to setup a second column for Field2 and for Field3.
If you assume your dropdowns are located in cell A10 to C10 and your fields are in column A-C then you could go over to column D and make D1 =if($a$10=a1,b1,"") and D2 would be if(countif(d$1:d1,if($a$10=a2,b2,""))=1,"",if($a$10=a2,b2,"")). You could drag D2 down for as many rows as you need. Once you do that you name that range to be Field2 (or whatever you're using as the name in your data validation list).
For Field3 you basically do the same thing except you use and. So in E1 you'd do =if(and($a$10=a1,$b$10=b1),c1,"") and E2 would be =if(countif(e$1:e1,if(and($a$10=a1,$b$10=b2),c2,""))=1,"",if(and($a$10=a1,$b$10=b2),c2,"")). When you do that, you name it Field3.
The downside is that the dropdown will have blanks and changing one of the first 2 won't reset the last ones. To overcome this pitfall you'd have to setup a worksheet change event in VBA.
EDIT:
OK start from scratch...
I'm putting the dropdowns in A12-C12 now.
You still have essentially formulas in column D and E but then you have to make 3 more columns to uniqueify (that's a technical term meaning to make unique) the previous columns. You can't see column H in this pic but it's the same template for field3. Those are array formulas so you don't hit enter after you've typed it in you hit CTRL-SHIFT-ENTER. You'll know you've done it right because it'll put curly braces around the formula. Once you make the formula copy it down.
Once you've done that then go to formulas define name.
Once there you fill out the name like this
Make sure you change the row in the countif to match your data but for the first argument of offset you just pick the first cell in the list and keep those two 0s as they are.
Once you've done that you make the dropdown based on the name from the previous step.
This should get you to about 99% of where you want to be. Unfortunately you are still susceptible to 1 blank if the first row is blank in the unique columns. I couldn't figure out how to get rid of it but since it's only 1 blank it shouldn't be too bad. Also, if you change a parent dropdown it won't reset the child dropdowns.