Okay, I have exhausted my feeble knowledge of Excel VBA coding and have not been able to figure out this solution.
I have a single column range of values as part of a table. The values in this column are groups of sequential strings such as:
ABC-001
ABC-002
XYZ-001
EFDDGE-001
ABC-003
XYZ-002
ABC-004
What I need to do is assign a value in the next row that is the next value in the whatever the group is.
Example:
If the next item is an "ABC" item, I need the value in the column to be ABC-005
If the next item is a "EFDDGE" item, I need the value in the column to be EFDDGE-002
etc.
The values in the column are in ascending order, by group (ie. XYZ-005 would never be before XYZ-003).
I have been working with the Range.Find method, but I can't seem to get it to work properly.
Here is a screen-shot of a sample portion of the table:
(Edit: apparently I can't post images since my "reputation is not a 10 or higher!)
Try to picture this series of columns:
[Next ID] [Item ID] [Description] [Disposition] [Original] [Final] [Weight]
In answer to some of the questions:
Yes, I am indeed trying to add the Item ID in the next available row in the table.
The group portion of the "Item ID" is determined by a VLookup into the "LocationID" table related to the entries in the "Original" or "Final" columns, depending on the "Disposition" value.
As you can see from the above screen shot, I have actually managed to implement a workable method of determining the "Next ID" and then having my VBA userform code copy that value and paste it into the adjacent "Item ID" column. It works, but it is ugly. Here is the bloated formula (take a deep breath):
=IF(NOT(ISERROR(CONCATENATE(VLOOKUP(IF(NOT(ISBLANK(G13)),G13,F13),LocationID,2,FALSE),"-",TEXT(SUMPRODUCT((ItemID>VLOOKUP(IF(NOT(ISBLANK(G13)),G13,F13),LocationID,2,FALSE))(ItemID<=CONCATENATE(VLOOKUP(IF(NOT(ISBLANK(G13)),G13,F13),LocationID,2,FALSE),"-999")))+1,"000")))),(CONCATENATE(VLOOKUP(IF(NOT(ISBLANK(G13)),G13,F13),LocationID,2,FALSE),"-",TEXT(SUMPRODUCT((ItemID>VLOOKUP(IF(NOT(ISBLANK(G13)),G13,F13),LocationID,2,FALSE))(ItemID<=CONCATENATE(VLOOKUP(IF(NOT(ISBLANK(G13)),G13,F13),LocationID,2,FALSE),"-999")))+1,"000")))," ")
So ... I have forced this to work, but I was thinking (hoping) that a bit of VBA code in the userform would obviate the need for such a messy method.
BTW, thanks to all of you for even looking at this and for asking pertinent questions and offering possible solutions.
-Bill
What I need to do is assign a value in the next row
Pretty sure you meant next column. Assuming that, try
=LEFT(A1,FIND("-",A1))&TEXT(VALUE(MID(A1,FIND("-",A1)+1,3))+1,"000")
It looks pretty messy. Let's break it down a little:
=LEFT(A1,FIND("-",A1)) ; isolates the non-numerical portion
=VALUE(MID(A1,FIND("-",A1)+1,3)) ; isolates the numerical portion, converts text to number
The remaining code concatenates the two pieces, adding one to the number we isolated, which is converted back to text while ensuring the 3-digit numerical format is preserved.
If you really need VBA we can go there. The technique is the same.
Related
Title says it all pretty much, So in the image the sum looks for the first entry as it has "mr human" in the cell next to it but when i try to designate my critera range for a single cell i get #value returned, I can solve this by entering "mr human" into all the adjacent cells however to sheet I am pulling the data from has is formatted like It is shown so it would be ideal If i didnt have to make a copy then do that as this can be for several hundred "mr & Ms/miss"
Thanks for any help in advance!
First of all, I would say that you should indeed consider using a different model data for this, as suggested by #ScottCraner.
Second, this solution may work, but if you have a lot of sets (when i mean sets, i mean Mr Human, Miss Human, Kid Human, Grandp Human, and many more) it can be kind of annoying.
Now, first thing you must do is creating named ranges of each set of data. So the values related to Mr Human will be namedMR_HUMAN and values of Miss Human will be named MISS_HUMAN. It's easy to do.
Remember:
Names can't have blanks, spaces, or any weird char. Just use underscore.
Each name must be unique
Each name must contain 2 columns: first one is Code and Second one Cost.
A video example (type the name and press ENTER
Now the formula for column C:
=IFERROR(VLOOKUP(B3;CHOOSE(MATCH($A$3;{"Mr Human";"Miss Human"};0);MR_HUMAN;MISS_HUMAN);2;FALSE);"Not found")
You can see below that if I change cell A3 to Miss Human, values change properly:
This is how the formula works:
MATCH($A$3;{"Mr Human";"Miss Human"};0) This will search the text in A3 into the array of sets and will return a number according to position. In this case, Mr Human=1 and Miss Human=2
CHOOSE(*number from step 1*;MR_HUMAN;MISS_HUMAN) We use the number obtained in step 1 to combine with function CHOOSE, which allows to select a result based on a list. So we can use this function to relate number 1 to name MR_HUMAN and number 2 to MISS_HUMAN and it will return our target range with right values.
VLOOKUP(B3;*name from step 2*;2;FALSE) We combine the range from previous step and use it as matrix of a normal VLOOKUP, that will search the CODE in first column, and will return the value from second one (COST)
We trap all above inside an IFERROR, just to avoid VLOOKUP returning an error (error in VLOOKUP means that CODE is not found in that range).
The big issue here is that if you got a lot of datasets for more values, besides Mr Human and Miss Human, you need to adjust the MATCH and CHOOSE part, and can be annoying.
Anyways, hope this helps a little bit.
VLOOKUP
function
IFERROR
function
MATCH
function
CHOOSE
function
Also, consider using a different data model and the resume data using Pivot Tables.
I have been trying to make a form for some of my team members who are not that computer literate, and I essentially want to make it click and go. I thought I could do it...but alas I am not as good with nesting functions as I thought I was.
I have this spreadsheet where I want to put data into the yellow cell. On the next sheet I have the below table. What I want to do is use a formula to fill H4 with the "Request Branch's" Account Number. Now, I have currently filled the cells with information. They, in fact, have drop down options - which are pulled from the Account List table. As a result the value in H4 will continually change based on the needs of the user - but must be within the confines of the Account List Table.
What I have tried is here and enter link description here. I keep getting result of #Value, or N/A. I can't figure out what I am doing wrong. I know that I need to nest the SUMIFS withing VLookUp, but I am not sure as to why it won't work.
I'm providing you with two possible solutions.
1) The first one uses the SUMPRODUCT function. You may not have seen this kind of notation before.
When ranges are multiplied by each other like so (B3:B8=G3)*(C3:C8=G4) they are actually turned into boolean arguments. If you highlighted this part of the code and pressed F9 it would look like this: {0;0;0;0;1;0;0}. This is an array where TRUE for both criteria meet. So our Branch is "A" and our Carrier is "F". In the rest of the cases either or both are false resulting in zeroes.
Now if you multiply this array by the range with account numbers, obviously the only number remaining will be the one multiplied by 1 and so you have the answer however keep in mind that as you are multiplying if the account is not a number the function will fail!
2) This is why we have a second method using =INDEX() and =MATCH() functions.
To overly simplify this - the INDEX function grabs contents from an array at a specified position (row and column), while the MATCH function gets the position of an item in an array.
The idea with using ranges as multiple criteria is the same as in the first example, however this time when we get our array of zeroes and ones {0;0;0;0;1;0;0} we use the match function to find at which position our criteria cross (as seen on the screenshot it's the 5th position, as it's in the 5th row of the entire column D, the match function searches the {0;0;0;0;1;0;0} array for a 1 and returns its position in the array) and so this is our ROW.
Knowing the position of the contents we searched for we use the INDEX function to grab the contents of the cell in that position so =INDEX(D2:D8,MATCH(1, INDEX((B2:B8=G3)*(C2:C8=G4),0),0)) is actually =INDEX(D2:D8, 5) meaning that the INDEX function grabs contents of the 5th row from the range D2:D8 which is cell D6.
The green boxes are just there to show the instance where both of our criteria are met (cross).
Please try this formula.
=INDEX(Table1[Account],SUMPRODUCT((Table1[Branch]=F$3)*(Table1[Carrier]=F$4)*ROW(Table1[Account]))-1)
Note that you may have to adjust the final -1. This is because the indexed table starts in row #2 and the SUMPRODUCT function returns a sheet row number. If your table would start in a different row the difference between the sheet row and table row would be larger. It must be adjusted here. Or you might work with sheet references (named ranges) and require no adjustment at all.
I have a problem that seems pretty easy, but still cannot find a proper solution, I want to avoid using vba.
I have two tables in one spreadsheet. both have the same columns - Name, City, Province.
My goal is compare both and if three out of three values in a row match, then pull "1", if not, pull 0.
I have used the formulas below , but it does not work for my case .
=IF(AND(A2=P:P,G2=M:M,H2=L:L),1,0)
=INDEX(A:P,MATCH(A2,P:P,FALSE),MATCH(G2,M:M,FALSE),2)
=INDEX(L:P,MATCH(A5,P:P,0),MATCH(G5,M:M,0),MATCH(H5,L:L,0))
=SUMPRODUCT(--(L2:L60=H2),--(M2:M60=G2),--(P2:P60=A2),B2:B60)
It seems that the solution is quiet simple , but I cannot find it,
Thanks in advance!
The key here is to merge the columns together, them Match on that.
Like this
=IFERROR( IF( MATCH(H3&"_"&I3&"_"&J3, $C$2:$C$60&"_"&$B$2:$B$60&"_"&$A$2:$A$60,0), "Yes"), "No")
Choose a seperator character that doesn't otherwise appear in your data (I've chosne _)
Assumption: Values just need to exist, not that they need to be of equivalent row.
=If(IfError(Match(A2,P:P,0),0)*IfError(Match(G2,M:M,0),0)*IfError(Match(H2,L:L,0),0)>0,1,0)
For each IfError, you will output a row number (>0) if you match, or if there is no match a zero will be output. Multiply anything by zero and you get zero, whcih allows a 1 or 0 output for true/false in the overarching If-statement.
If they need to be of the same row, you can compare 2 matches, which rely on the transitive property (A=B, B=C, so A=C):
=If(And(Match(A2,P:P,0)=Match(G2,M:M,0),Match(G2,M:M,0)=Match(H2,L:L,0)),1,0)
Edit1:
Per my comment (to this answer) about false negatives, a UDF or subroutine in VBA would be more appropriate, considering Match() returns the first row that has a match.
As this is not a VBA tagged post, this is a bit above the expected answer... My recommendation would be to:
A) Ensure you are comfortable using VBA.
B) Make a post about creating a user-defined function (note that any post on here about VBA has an expectation that the poster can interact with an expert on the topic and will be putting forth effort to write the code themselves, as StackOverflow is not a code-for-you service).
To help give a lead on what may be in your UDF:
A loop to go through the values from first row to last row in the search column (i.e., L, M, & P)
A variable to dynamically identify the last row of your search column
An if-statement to compare values from your lookup values (i.e., A2, G2, H2) to the search values at the current iteration of the loop
An output of 1 (has match) or 0 (no match).
There are many ways to go about this with VBA; hopefully that's a good start for you, Irina!
Summary
I need an array formula that takes a row of data of certain length from Sheet1. For that row, in each column that is not blank, I need to grab the Sheet1 header value for that column and display that data in a continuous row on Sheet2 (without any spaces in between the row's cells).
Background
I have a table of data (employees and industry certifications with expiration date being the table's cell data) on sheet 1, with a row for each employee the spreadsheet is tracking. The certifications are the columns.
We are using this information to link to ID Badge Printer software (Bodno Silver), where we are limited to linking columns of data to a particular textbox.
The problem lies in the fact that not everyone has every certification. The rows are peppered with blanks separating the certifications that each employee does have. While setting up the required text boxes in the badge software template, that each link to a specific column, I quickly realized that since not everyone has every certification if we used the data how it was we would have a bunch of strange looking blanks in between the listed certifications rather than a continuous list.
What I did
My solution to this (which I'm open to a better one if anyone knows of one, other than "use better software"), was to create a new sheet and array formulas that no one would use except for me and the id printer software. This sheet would have a similar data table that took the rows of data interspersed with blank cells between expiration dates, and put the matching column headers for cells that had a date in them into a continuous row of the same maximum length (eliminating the blank cells).
Essentially, this would allow me to circumvent the restrictions of the badge software and each textbox would be MatchedCert1, MatchedCert2, MatchedCert3, etc. up to the original maximum number of certifications.
Pictures are probably better than my words at explaining what I am going for:
Sheet1 (source)
Sheet2 (result)
The array formulas
I worked on this one for a while. What I thought would be a simple INDEX, MATCH, ISBLANK formula (that I could create using the appropriate relative and absolute cell linking) and then expand to the whole sheet turned into a witch hunt and me praying for forgiveness for my sins to all that may be holy. Also a lot of googling.... I realized quickly that this one may not be so simple after all.
Finally, I arrived at the following two array formulas in order to correctly show what I was going for:
First Column of training section
{=IFERROR(INDEX(Sheet1!$E$2:$P3,1,MATCH(FALSE,ISBLANK(Sheet1!E3:Q3),0)),"")}
(easy enough, right? I thought so...)
I felt good about this until I tried to think through what would be required to get the formula to be universal so that I could use it on the entire table.
I feel dirty just putting the following in public, but here goes...
Second column through last column array formula
{=IFNA(INDEX(INDIRECT(ADDRESS(ROW($E$2),(MATCH(E3,Sheet1!$2:$2,0)+1),1,1, "Sheet1")&":"&ADDRESS(ROW(E3),COLUMN($Q3),1)),1,MATCH(FALSE, ISBLANK(INDEX(INDIRECT("Sheet1!"&ADDRESS(ROW(E3),(MATCH(E3,Sheet1!$2:$2,0)+1),1)&":"&ADDRESS(ROW(E3),COLUMN($Q3),1)),0,0)), 0)),"")}
(please don't call the police...)
[ninja edit] While this array formula works for 2nd result column through the final column, it doesn't work if there's not a blank column following the result range. The actual spreadsheet has 4 different groups of certifications that run horizontally, but I was able to just add a blank column in the corresponding data from the other sheet easily enough, so I just let it go. I'd give somebody a nickle for the answer to why that's the case here too [/edit]
Results
The first array formula, and INDEX MATCH using ISBLANK is rather straightforward.
The biggest question for me here, and the thing that drove me absolutely nuts for a couple of days, is why the second array formula requires the additional INDEX function nested inside of the ISBLANK function.
While taking the function apart and experimenting I realized that if I have any INDIRECT reference inside a ISBLANK function, which is itself inside of a MATCH function, the result of the match was ALWAYS 1:
{=MATCH(FALSE,ISBLANK(INDIRECT("$E3:$Q3")), 0)}
The above ALWAYS returns 1, whereas if I put the range in explicitly, the function would work just fine. That wasn't an option for me, since I needed to dynamically return the starting position for the match using the previous cell's address.
However, adding an INDEX function (with a column and row value of 0) to encapsulate the INDIRECT function provides the correct answer. I figured this out just by trial and error.
Questions
Can someone with more knowledge please let me know what is causing this behavior?
As a broader question, given I am limited to using formulas (no VBA), I would also like to know if I'm going about this in the wrong way or if there is a much simpler way of accomplishing this without this behemoth of a formula?
I know this sheet will probably require maintenance in a year - good luck future self!
Put this in E3, Copy over and down
=IFERROR(INDEX(Sheet1!$2:$2,AGGREGATE(15,6,COLUMN(INDEX($E:$P,MATCH($C3,Sheet1!$C:$C,0),0))/(INDEX(Sheet1!$E:$P,MATCH($C3,Sheet1!$C:$C,0),0)<>""),COLUMN(A:A))),"")
As to why your formula is not working, it is too convoluted to parse. One note, unless the sheets is the variable, one should avoid INDIRECT as much as possible. INDEX can almost always be used in its place.
Both INDIRECT and ADDRESS are volatile functions. Volatile functions will re-calculate every time Excel re-calculates, leading to a lot of unnecessary computations.
Not a solution but to answer why you are seeing this behavior:
EDIT: PREVIOUS EXPLANATION WAS JUST PLAIN WRONG
This confused me so, I did a bit of investigation:
I think that your problem is actually coming from the ISBLANK function because it is intended to be used with single values, and cannot handle ranges. Any BLANKs which are returned by functions are only converted to numeric values (0), when the BLANK is returned to (or displayed on) the sheet. If the function is returning to another function, the BLANK value seems to be preserved.
EDIT: ADDING A SOLUTION WITHOUT ARRAY FORMULAS
This is probably more complex than using an array formula... but I strongly dislike them, so do all I can to remove them.
Firstly, I would add an index to your positions in the results sheet:
=IF(F$7>COUNTIFS($F3:$L3,"<>"),
"",
IF(
MINIFS(
$F$7:$L$7,$F$7:$L$7,
">" & IFNA(INDEX($F$7:$L$7,MATCH(E9,$F$2:$L$2,0)),0),
$F3:$L3,
"<>"
)=0,
"",
INDEX(
$F$2:$L$2,
MATCH(
MINIFS(
$F$7:$L$7,$F$7:$L$7,
">" & IFNA(INDEX($F$7:$L$7,MATCH(E9,$F$2:$L$2,0)),0),
$F3:$L3,
"<>"
),
$F$7:$L$7,
0
)
)
)
)
Basically, the formula looks at the cert in the previous cell, and looks for the next, minimum index, greater than that.
I have been working on a solution to this problem for a few hours now and I am basically no where except knowing that I don't know how to do it...So here goes.
I want to take the original data that I have in Excel that have 'code#s' for each 'category#'. With those 'code#s', I can look up the 'category#' name.
This has been so challenging because there are a varying number of categories for every 'title#'.
I have tried printing the 'category#' name next to 'title#', but it is seemingly impossible because Excel goes through every row in the original data and gives a True, False or #N/A instead of selecting and printing only the true statements without copying down a thousand rows. I want it to go through all the possibilities and only select the categories based on the criteria that they have the same 'title#' and their lookup code matches somewhere in the lookup table.
Thanks if you can offer any sort of help.
Here are some of the formulas I have tried:
IF(AND($M$5=TOP_TREND_CONTRIBUTORS!$W$2:$W$253,MATCH(TOP_TREND_CONTRIBUTORS!$A$2:$A$253,'Category Lookup'!$D$3:$D$30,0)<>"#N/A"),TOP_TREND_CONTRIBUTORS!$A$2:$A$253,FALSE)
....where M5, W:W is the 'title#', A:A is the code for the lookup-in that part I am trying to say that they are valid if the code registers in the lookup table and the 'title#s' are equal. The last part I am trying to get it to print the 'code#s' that are valid. But that only works when I drag the formula down all the rows.
Maybe I'm missing something, but I just tried to get from your original data and lookup table to the final result. I used VLOOKUP to put categories next to titles and then used pivot table to present the data in the way you wanted (after changing some settings of pivot table and fields). Is that what you need? (some words are in Polish, it doesn't matter).