I'm trying to copy text from sheet1, over to sheet2, depending on the header.
=IF(Sheet1!A1=Sheet2!A1,Sheet1!A2:A40,(IF(Sheet1!B1=Sheet2!A1,Sheet1!B2:B40,(IF(Sheet1!C1=Sheet2!A1,Sheet1!C2:C40,(IF(Sheet1!D1=Sheet2!A1,Sheet1!D2:D40,(IF(Sheet1!E1=Sheet2!A1,Sheet1!E2:E40,(IF(Sheet1!F1=Sheet2!A1,Sheet1!F2:F40,(IF(Sheet1!G1=Sheet2!A1,Sheet1!G2:G40,"")))))))))))))
=IF(Sheet1!A1=Sheet2!A1,Sheet1!A2:A40,
(IF(Sheet1!B1=Sheet2!A1,Sheet1!B2:B40,
(IF(Sheet1!C1=Sheet2!A1,Sheet1!C2:C40,
(IF(Sheet1!D1=Sheet2!A1,Sheet1!D2:D40,
(IF(Sheet1!E1=Sheet2!A1,Sheet1!E2:E40,
(IF(Sheet1!F1=Sheet2!A1,Sheet1!F2:F40,
(IF(Sheet1!G1=Sheet2!A1,Sheet1!G2:G40
,"")))))))))))))
This unsightly mess is what I've got so far, but it only works about 57% of the time. I have no idea why.
Say for example, that the headers were Test1, Test2, Test3 etc, how could I make it so that excel reads sheet1 for the header Test1, and copies the column starting the cell beneath, and copies it over to whatever column Test1 is on in sheet2?
I have a rather basic understanding of excel formula, and even less of VBA, so any help is welcome.
This is a good task for INDEX(), by passing a 0 for one of the arguments you can state that you would like the whole column to be returned (or all rows of the matched column to be more precise):
=INDEX(Sheet1!A2:G40,0,MATCH(Sheet2!A1,Sheet1!A1:G1,0))
Without some example data and expected output I am unable to justify whether this is exactly what you are after though. Please feel free to provide more scope and leave me a comment, I will update my answer.
EDIT:
To get the results for the columns, you would assemble a lookup something like this:
=INDEX(Sheet1!$A$2:$G$40,ROW()-1,MATCH(Sheet2!A$1,Sheet1!$A$1:$G$1,0))
So that you index the data you want to be returned, then return the current row that you are on (offset by -1 as the data begins on the second row). The MATCH() at the end returns the position of the column title that matches Sheet2!A$1.
The $$ is important here as the absolute referencing will stop the formula from changing when you drag it across the sheet (Sheet2!A$1 will only update when dragged horizontally but not when dragged vertically)
Related
I have scoured the internet but come up empty.
I am looking for a formula that will be in a single cell (I don't want to have to fill it down the side of the table for instance) that will return the header of the first column that has a value in it, from left to right. If there's a value in the last cell of the first column, for instance, I want that header returned rather than moving to column 2.
I have tried nested xlookups and index/match combinations and just can't find anything that will be in a single cell.
Any help is appreciated!!
EDIT: Yup, let me be more clear. My apologies!
Here is an excerpt of my table. In this instance, I would want the result to be Sep-21 (a reference to the cell is also fine).
I know I can easily drag the formula in A1 down and pull the column header of the first cell in that row with a value. What I want is to reference this on another sheet, so I don't want to have to do that. I want one formula in one cell to pull this information, if possible. If I can't do it that simply, maybe I have to do some other wizardry and hide a row/column or something and fill the formula down that way and then pick the latest date, but I'd like to avoid that if possible. One cell would be much more elegant!
As for what I've tried, all my attempts are pretty messy and incomplete, so I don't know if it would be helpful to paste them here, but essentially I've tried to use an xlookup where the lookup_array is B2:D6, and then the return_array is the header, but that doesn't seem to work. I guess the lookup_array has to be a single column/row? Something like:
xlookup(ISBLANK(FALSE), B2:D6, B1:D1)
It's kind of like an inverse xlookup, lol.
EDIT2: I've done some more messing about and have come SO CLOSE! Now my problem is with structured references in a table and trying to exclude my first two columns.
First, the solution that does work without structured references (assuming the table starts in A1):
=IFERROR(INDEX(B1:D1,SUMPRODUCT(MIN(IF((B2:D6<>0)*(COLUMN(B2:D6)) > 0, ((B2:D6<>0)*(COLUMN(B2:D6)))))-COLUMN(A1))), "error")
But like I said, my structured references are getting in the way now. I want to pull all the data in my dynamic table, except for the first two columns.
I know this is a completely different problem now, my apologies for that.
The solution (assuming the table starts in A1):
=IFERROR(INDEX(B1:D1,SUMPRODUCT(MIN(IF((B2:D6<>0)*(COLUMN(B2:D6)) > 0, ((B2:D6<>0)*(COLUMN(B2:D6)))))-COLUMN(A1))), "error")
If your data is in row 2:
=INDEX(1:1, 1, MATCH("", 2:2,-1))
should work
So I'm not a fan of VBA and I recently learned that OFFSET can be used with COUNTA to flashfill a range as far at it is as long as you aim for a longer range than you have data. Now I want to be able to achieve this both for columns and rows at the same time, where the rows are averaged. Could this be done? I am banging my head against the wall to find some logic to do it, but can only manage to combine it in a way that multiplies the rows with the number of the column.. which is not desired, of course.
I have posted a Minimal Reproducible Example in Excel Online:
https://onedrive.live.com/view.aspx?resid=63EC0594BD919535!1491&ithint=file%2cxlsx&authkey=!ALmV0VtFb7QZCvI
If you see Cell J9 and J11 you will see what I want to combine. The three rows in J11 and down, I want to average in J10, and spill/flashfill (like J9 and 11 does automatically because of the formula already) them from to the right, for as many columns as there data in the range A1-G4..
So I have raw data of numbers with titles in A1-G4, and by writing =OFFSET($A$1:$A$1,0,0,1,COUNTA($A$1:$EV$1)-1) in J9 I get all the titles of the columns filled from left to right, and by writing =OFFSET($A$1,1,0,COUNTA($A:$A)-1) in J11 I get the rows of the first column filled from top to bottom. They can also be combined, by writing OFFSET(Days,1,0,COUNTA($A:$A)-1,COUNTA(Days)), where "Days" is =OFFSET($A$1:$A$1,0,0,1,COUNTA($A$1:$EV$1)-1) (in a named range for readability) or OFFSET($A$1:$A$1,0,0,1,COUNTA($A$1:$EV$1)-1) without using a named range
As a thought, though I'm not sure how to implement it, maybe this could somehow be used in some form to get the column reference for the horizontal part in combination with =AVERAGE(OFFSET($A$1,1,0,COUNTA($A:$A)-1))
=MID(ADDRESS(ROW(),COLUMN()),2,SEARCH("$",ADDRESS(ROW(),COLUMN()),2)-2)
..found at https://superuser.com/questions/1259506/formula-to-return-just-the-column-letter-in-excel/1259507
Now, based on your explanation, here is the screenshot of my test:
Section A1:Exxx
I have converted that section into a Table, called «TblData», having numerous avantages:
It expands automatically without any additional efforts/formula
We can identify Data by its Columns attributed automatically by the Table [#1], [#2],[#3], [#4], [#5]
Section J9:N9
As a replica of the table name, I have used the following formula to retrieve it:
=INDEX(TblData[#Headers],1,COLUMN(A1)) '<--- This is for J9
=INDEX(TblData[#Headers],1,COLUMN(E1)) '<--- This is for N9
Section J11:Nxx
As a replica of the Table Content, I have used the following formula to populate the content:
=INDEX(TblData,ROW($A1),MATCH(J$9,TblData[#Headers],0)) '<--- This is on J11
=INDEX(TblData,ROW($A3),MATCH(N$9,TblData[#Headers],0)) '<--- This is on N13
Section J10:N10
Now this is the interesting part of the Average, so here is the formula I used for it:
=AVERAGE(TblData[1]) '<--- This is on J10
=AVERAGE(TblData[5]) '<--- This is on N10
NB: (1) Instead of using the Content below J10:N10, I prefer to reuse the Table as it expands automatically as more rows are added.
(2) Unless it is really necessary, I feel it is a double work as well to replicate again A1:Exxx from J9:Nxxx, because you can use the Table for whatever you need, with less maintenance.
Kindly find attached the file as well after I updated those items:
File Link: https://drive.google.com/open?id=1wRbpUxg0XLpfGqdvMF4fNKXDrL7xPPWs
We can correspond more below for further info. Hoping you to strech more your compentence :)
Sorry, mate, I can't figure out what you want to calculate. If it makes sense to add J9+J11 then you could just concatenate the two formulas in J9 and J11 with a plus sign. After much deliberation I decided to assume that your question is not one of formula but of formula-writing - "referencing" for short. Therefore I prepared this answer for you, hoping that it will prove helpful.
Building on your named range Days I suggest you create a dynamic named range Data with this formula.
[Data] =OFFSET(Sheet1!$A$1,0,0,COUNTA(Sheet1!$A:$A),COUNTA(Sheet1!$1:$1))
The range thus defined is dynamic in both directions. However, bearing in mind that OFFSET is volatile (slows down your worksheet) you may like to keep its use limited to this one formula and perhaps start the range at A2, but I shall tempt you to break the rule. Now you can use the INDEX function to refer to the Data range.
= INDEX(Data, [Row number], [Column number])
defines a single cell. But by setting either column or row to zero you can define an entire column or row. =INDEX(Data,0,1) defines column 1 of the Data range, =INDEX(Data,1,0) defines its first row.
=INDEX(OFFSET(Data,1,0),0,1) defines the first column of a range moved down by one row from its original position. I recommend the alternative and start the Data range from A2 and perhaps declare another range for the first row if needed.
=AVERAGE(INDEX(Data,0,1)) would draw the same average you already have in your sheet, provided that Data was defined starting at A2. For fun's sake, =AVERAGE(INDEX(OFFSET(Data,1,0),0,1)) would do the same without the change in the range's definition.
=COLUMN() returns the number of the column this formula resides in. So, you could enter =COLUMN()-6 in column G, copy to the right and get a count starting from 1. (You can do the same vertically with the ROW() function.) Applied to your formula, =AVERAGE(INDEX(Data,0,COLUMN()-6)) would return the average from column 1 if entered in column G, and from columns 2, 3 4, etc as copied to the right.
As I said, I don't understand enough of your request to bring this idea to a conclusion but I think that using the method described above will provide you with a tool to copy formulas into the table your sample has at its right. If you would elaborate on your requirement I might be able to assist more.
EDIT: I have revived the source data source to remove the ambiguity of my last screen shots
I am trying to transpose spreadsheet data where there are many rows where the customer name may be duplicated but each row contains a different product.
For instance
revised original data source
to
revised proposed data format
I would like to do it with formulae if possible as I struggle with VB
Thank you for any help
I realise this is a huge answer, apologies but I wanted to be clear. If you need anything from me, drop me a comment and I'll help out.
Here's the output from my formula:
EDITED ANSWER - Named ranges used for ease of understanding:
These are just an example of a few of the named ranges I have used, you can reference the ranges directly or name them yourself (simplest way is to highlight the data then put the name in the drop down next to the formula bar [top left])
Be wary that as we will be using Array formulas for AccNum and AccType, you will not want to select the entire column and instead opt for either the exact data length or overshoot it by 100 or so. Large array formulas tend to slow down calculation and will calculate every cell individually regardless of it being empty.
First formula
=IF(COUNTIF(D2:D11,">""")>0,CONCATENATE("Account Number ",LEFT((COLUMN(A:A)+1)/2,1)),"")
This formula is identical to the one in the original answer apart form the adjusted heading title.
=IF(Condition,True,False) - There are so many uses for the IF logic, it is the best formula in Excel in my opinion. I have used to IF with COUNTIF to check whether there is more than 0 cells that are more than BLANK (or ""). This is just a trick around using ISBLANK() or other blank identifiers that get confused when formula is present.
If the result is TRUE, I use CONCATENATE(Text1,Text2,etc.) to build a text string for the column header. ROW(1:1) or COLUMN(A:A) is commonly used to initiate an automatically increasing integer for formulas to use based on whether the count increase is required horizontally or vertically. I add 1 to this increasing integer and divide it by 2 so that the increase for each column is 0.5 (1 > 1.5 > 2 > 2.5) I then use LEFT formula to just take the first digit to the left of this decimal answer so the number increases only once every 2 columns.
If the result is FALSE then leave the cell blank ,""). Standard stuff here, no explanation needed.
Second Formula
=CONCATENATE(INDEX(Forename,MATCH(Sheet4!$A2,Reference,0)))
=CONCATENATE(INDEX(Surname,MATCH(Sheet4!$A2,Reference,0)))
CONCATENATE has only been used here to force blank cells to remain blank when pulled by INDEX. INDEX will read blank cells as values and therefore 0's whereas CONCATENATE will read them as text and therefore "".
INDEX(Range,Row,Column): This is a lookup formula that is much more advanced than VLOOKUP or HLOOKUP and not limited in the way that they are.
The range i have used is the expected output range - Forename or Surname
The row is then calculated using MATCH(Criteria,Range,Match Type). Match will look through a range and return the position as an integer where a match occurs. For this I have set the criteria to the unique reference number in column A for that row, the range to the named range Reference and the match type as 0 (1 Less than, 0 Exact Match, -1 Greater than).
I did not define a column number for INDEX as it defaults to the first column and I am only giving it one column of data to output from anyway.
Third Formula
Remember these need to be entered as an array (when in the formula bar hit Ctrl+Shift+Enter)
=IFERROR(INDEX(AccNum,SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(A:A)+1)/2,0))),"")
=IFERROR(INDEX(AccType,SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0))),"")
As you can see, one of these is used for AccNum and the other for AccType.
IFERROR(Value): The reason that this has been used is that we are not expecting the formula to always return something. When the formula cannot return something or SMALL has run out of matches to go through then an error will occur (usually #VALUE or #NUM!) so i use ,"") to force a blank result instead (again standard stuff).
I have already explained the INDEX formula above so let's just dive in to how I have worked out the rows that match what we are looking for:
SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0))
The IF statement here is fairly self explanatory but as we have used it as an array formula, it will perform =Sheet4!$A2 which is the unique reference on every cell in the named range Reference individually. In your mock data this returns a result of: {FALSE;TRUE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE} for the first entry (I included titles in the range, hence the initial FALSE). IF will do my row calculation* for every true but leave the FALSEs as they are.
This leaves a result of {FALSE;2;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE} that SMALL(array,k) will use. SMALL will only work on numeric values and will display the 'k'th result. Again the column trick has been used but to cover more ground, I used another method: ROUNDDOWN(Number,digits) as opposed to using LEFT() Digits here means decimal places so I used 0 to round down to a whole integer for the same result. As this copies across the columns like so: 1, 1, 2, 2, 3, 3, SMALL will alternatively (as the formulas alternate) grab the 1st smallest AccNum then the 1st Smallest AccType before grabbing the 2nd AccNum and Acctype and so forth.
*(Row number of the match minus the first row number of the range then plus 1, again fairly common as a foolproof way to always get the correct row regardless of where the data starts; actually as your data starts on row 1 we could just do ROW(Reference) but I left it as is incase you had data in a different format)
ORIGINAL ANSWER - Same logic as above
Here's your solution in 3 parts
Part 1 being a trick for the auto completion of the titles so that they will hide when not used (in case you will just copay and paste values the whole lot to speed up use again).
=IF(COUNTIF(C2:C11,">""")>0,CONCATENATE("Product ",LEFT((COLUMN(A:A)+1)/2,1)),"") in C
=IF(COUNTIF(D2:D11,">""")>0,CONCATENATE("Prod code ",LEFT((COLUMN(B:B)+1)/2,1)),"") in D
Highlight both of the cells and drag across to stagger the outputs "Product " and "Prod code "
Part 2 would be inputting the unique IDs to the new sheet, I would suggest copying your entire column A across to a new sheet and using DATA > REMOVE DUPLICATES > Continue with current selection to trim out the multiple occurrences of unique IDs.
In column B use =INDEX(Sheet2!$B$1:$B$7,MATCH(Sheet4!$A2,Sheet2!$A$1:$A$7,0)) to get the names pulled across.
Part 3, the INDEX
Once again, we are doing a staggered input here before copying the formula across the page to cover the entirety of the data.
=IFERROR(INDEX(Sheet2!$C$1:$D$11,SMALL(IF(Sheet2!$A$1:$A$11=Sheet4!$A2,ROW(Sheet2!$A$1:$A$11)-ROW(INDEX(Sheet2!$A$1:$A$11,1,1))+1),ROUNDDOWN((COLUMN(A:A)+1)/2,0)),1),"") in C
=IFERROR(INDEX(Sheet2!$C$1:$D$11,SMALL(IF(Sheet2!$A$1:$A$11=Sheet4!$A2,ROW(Sheet2!$A$1:$A$11)-ROW(INDEX(Sheet2!$A$1:$A$11,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0)),2),"") in D
The formulas of Part 3 will need to be entered as an array (when in the formula bar hit Ctrl+Shift+Enter) . This will need to be done before copying the formulas across.
These formulas can now be dragged / copied in all directions and will feed off of the unique ID in column A.
My Answer is already rather long so I haven't gone on to break the formula down. If you have any trouble understanding how this works, let me know and I will be happy to write up a quick guide, breaking it down chunk by chunk for you.
I have a big table like this (imagine round-robin result table) where both column and row are team names that First row will be exactly like First Column
Because the table is very big so it is hard to look up for value if I have to look for multiple values
So I'd like to create a table like this
Let's say I want to look up the first "?" in this small table. What formula can I use to look up A2(column)xA3(row) from the big table?
I hope I made it clear enough.
Any pointers or resource I could read online would be greatly appreciated.
I would break this down in two parts.
Get a lookup working for row values using VLOOKUP(). Here is an example: VLOOKUP($A3, BigTable!$A$2:$CW$101, 2, 0):
$A3: Lookup value to find. Dollar sign locks just the column so that when you drag the formula across A doesn't change
BigTable!$A$2:$CW$101: Range to find the result. Dollar sign completely locks the range so wont change
2: Column to bring back (For the time being it is always going to bring back second column)
0: Look for an exact match
Get a lookup working for the column values so that when the formula is copied across it automatically updates the column that it is looking for. I used MATCH() to find the position of the column value in BigTable. For example: MATCH(B$1, BigTable!$B$1:$CW$1, 0):
B$1: Column header to lookup up the position of in the BigTable. Dollar sign locks the row so when you move it down it remains as 1
BigTable!$B$1:$CW$1: Header column to look through
0: Look for an exact match
Finally put the two pieces of the formula together and check some of the values to make sure that it is working correctly: VLOOKUP($A2, BigTable!$A$2:$CW$101, MATCH(B$1, BigTable!$B$1:$CW$1, 0), 0)
This would then give you one formula to copy across the whole of the SmallTable to lookup up the relevant values in the BigTable.
http://www.contextures.com/xlFunctions03.html
Read example 3, it is exactly like my problem.. Thank #DirkReichel for suggesting Index function, so I could know where even to start.
I want to transfer data automatically from 2 sheets to one single combining one. That means I have 2 different exports that contain both the columns "Problem". I have one sheet, that represents an overview of the data. So when I have for example the value "A333" in A1 of my overview sheet, I want Excel to search in the two other export sheets the value "A333" and give back the value in the same row as "A333" but of the column "Problem" not "A".
The problem that I see is that I have to search TWO sheets and I don't know in which one the "A333" will appear.
Can you please help me? I would preferably like to solve the problem with a formula, not a macro. Thank you very much in advance.
1) write a formula (VLOOKUUP() for example) that looks for the value in the first sheet
2) write a formula that looks for the value in the second sheet
3)since VLOOKUP returns an ERROR if a value is not found you can combine the formulas together using IFERROR(). for example: =IFERROR(VLOOKUP(ref_cell,sheet1_range,2,0),VLOOKUP(ref_cell,sheet2_range,2,0))
EDIT:
It looks like you did not provide all the pertinent information in your question!
I suggested VLOOKUP(), but this will only work if you know which COLUMN the value you are looking for will appear in, but you said this is not the case...
using you comments I therefore assume the following:
the two test sheets are called "test1" and "test2"
The reference value we are looking for is in cell A5 on the main sheet, cell D1 on the sheet contains "Problem" (text)
The reference value may appear anywhere (I limit here to range A1:J100) on test1 or test2, but ONLY ONCE
The column "Product" on test1 and test2 may appear in different columns, but it will always have a heading "Product" in row 3 (test1!A3:J3 and test2!A3:J3)
see below of screenshot of the answer (column C shows result, column D shows the underlying formula)
If required use the information provided to create a single-cell formula (because Stack Overflow is not a we-write-the-answer-for-you service)
Following the scheme:
and add the formula:
E3 -> =CONCATENATE(IFERROR(VLOOKUP(D3;$A$12:$B$15;2;FALSE);"");IFERROR(VLOOKUP(D3;$A$3:$B$6;2;FALSE);""))
and autocomplete ...