VBA excel Copy Paste - vba

Hi, I am totally new to Excel VBA. Firstly, I want to copy the data when the condition is met(copy data with reference to 144)
Secondly, compare the cells, if it is IT Operations(Table1) to IT Operations(Table2) then copy the price(money) to column F. If the variable is no there then leave blank.

This can be done with formulas. Here is one way of thinking about filling column F, with the prices for the matching items in column E, by matching the number given in the last row in E (144 Total); which i shall assume is E10 in this case.
Total formula in F1 which you then drag down is:
=IFERROR(IFERROR(VLOOKUP(E1,INDIRECT(CELL("address",OFFSET($H$1,MATCH(1*LEFT($E$10,FIND(" ",TRIM($E$10),1)-1),$G:$G,0)-1,,1,1))&":"&CELL("address",OFFSET($I$1,MATCH($E$10,$G:$G,0)-1,,1,1))),2,FALSE),VLOOKUP(E1,G:I,3,FALSE)),"")
In steps:
Extract the number of interest e.g. 144, and get rid of any trailing/leading whitespace using:
LEFT($E$10,FIND(" ",TRIM($E$10),1)-1)
Find which row this value is in as this will be the first row of the lookup range for this number. *1 converts text to a number.
MATCH(1*LEFT($E$10,FIND(" ",TRIM($E$10),1)-1),$G:$G,0)
This gives row 9.
We can use something simpler to find the last row of the range, which holds 144 Total
MATCH($E$10,$G:$G,0)
This gives row 15. So we know the data lies between rows 9 and 15 for 144.
We can turn this into a range to use in a VLOOKUP with INDIRECT and OFFSET.
=CELL("address",OFFSET($G$1,MATCH(1*LEFT($E$10,FIND(" ",TRIM($E$10),1)-1),$G:$G,0)-1,,1,1))&":"&CELL("address",OFFSET($H$1,MATCH($E$10,$G:$G,0)-1,,1,1))
This gives us $G$9:$H$15. Note adjustments of -1, to put OFFSET back in the right row, and that the OFFSET start cells are in different columns to provide the columns required for the VLOOKUP.
So we can now lookup column E values e.g. Enhancement, in our newly defined range which is accessed via INDIRECT:
=VLOOKUP(E1,INDIRECT(CELL("address",OFFSET($H$1,MATCH(1*LEFT($E$10,FIND(" ",TRIM($E$10),1)-1),$G:$G,0)-1,,1,1))&":"&CELL("address",OFFSET($I$1,MATCH($E$10,$G:$G,0)-1,,1,1))),2,FALSE)
This is saying VLOOKUP(E1,$G$9:$H$15,2,FALSE) i.e. get the price column from the range for the item specified in E1.
If this is not found i.e. returns #N/A, we can use this to first check if this is because of the merged cell that holds the 144 Total; where the value is actually in column G not H, and use an IFERROR to say, if not found in $G$9:$H$15 then try for a match using columns G:I and return column 3.
Which with pseudo formula, using priorLookup as placeholder, for the formula described in the steps above, looks like:
IFERROR(priorLookup, VLOOKUP(E1,G:I,3,FALSE))
If this still returns #N/A, we know the value is not present and we should return "". This we can handle this with another IFERROR:
IFERROR(IFERROR(priorLookup, VLOOKUP(E1,G:I,3,FALSE)),"")
So giving us the entire formula stated at the start.
Here it is used in the sheet:

Related

vba - Get row number of a cell with certain value in a named range

Is there a way to find the row of a cell containing certain value in a named range (Table)?
I have a table named "Table1" from C4 to D10.. I want to return the row number of a cell in column c that contains the value "CCC".. This value is found at the third row (C6).. So I want the code to return the number "3" which means the third row in the table "Table1" and not the number "6" that means it's found in cell "C6".
Thank you in advance.
Edit:
I missed the part about "relative to the table" but that's even easier...
Here's one that will work:
=MATCH("CCC",Table1,0)
or, referring to the cell range instead of the table directly:
=MATCH("CCC",C4:C10,0)
Original Answer:
If you want to know the row number of the first cell in Column C that contains CCC, you could use the MATCH function, either in a worksheet formula, or in VBA.
On the worksheet:
=MATCH("CCC",C:C,0)
or, in VBA:
WorksheetFunction.Match("CCC",Range("C:C"),0)
The fact that it's in a table is irrelevant since you've identified the column.
Incidentally, I can think of at least half a dozen other ways to get the same data just as easily.
Here's one that refers to the table directly:
=ROW(INDEX(Table1,MATCH("CCC",Table1,0)))
...and more variations:
=MATCH("CCC",C4:C10,0)-1+ROW(C4)
or
=MATCH("CCC",Table1,0)-1+ROW(Table1)
Note that a big difference between MATCH and VLOOKUP is that MATCH returns a range object, whereas VLOOKUP only returns the value of the matched cell, and therefore isn't suitable for a task like this.
More Information:
Office Support : MATCH Function
Microsoft Docs : WorksheetFunction.Match Method (Excel)
Office Support : INDEX Function

Find number of rows in an already filtered Column A in Excel

I have got an Excel spreadsheet. This spreadsheet has just one tab in it. The Tab name is dynamic in nature and changes every week also the number of rows.
I have column A filtered already with a VBA macro. A1 has the header.
Now, I wanna find how many rows are there in this already filtered column A.
I am looking for any VBA function.
I have tried using Subtotal function.
=Subtotal(103,A2:A1345)
But I don't know the end range. As of now the end range is A1345. It will change every time in future if the new rows are added.
I tried multiple things but those did not work. I am quite new to VBA.
If A1 will never be blank, you could use (in a column other than A)
=Subtotal(103,A:A)-1.
Or, if there will be data below your table not to be counted, then format your table as a Table and use structured references (and this formula could go into column A)
=SUBTOTAL(103,Table1[column_header])
You can put the formula in column A if you use another column's last populated cell as the demarcation point.
If column B contains numbers then,
=subtotal(103, a2:index(a:a, match(1e99, b:b)))
If column B contains text then,
=subtotal(103, a2:index(a:a, match("zzz", b:b)))

Extracting "hidden" data from expanding/collapsing pivot table - Excel

I'm not sure if this is possible but as you can see I have a pivot table with multiple dependent and expandable fields. I am trying to concatenate the data from columns A:D into one cell which works fine in row 2 but doesn't work with blank parent cells, as you can see in column F.
Any ideas for how to achieve this?
Pivot table
This answer assumes that you don't want to just Repeat All Item Labels in the PivotTable from the "Report Layout" drop-down on the Pivt Table Tools "Design" tab.
A formula to get the first non-blank value on or above the same row as the current cell from Column B can be constructed with a combination of AGGREGATE, SUMPRODUCT and OFFSET, like so:
=OFFSET($B2,SUMPRODUCT(AGGREGATE(14,6,ROW($B$1:$B$100)*--(ROW($B$1:$B$100)<=ROW())*--(LEN($B$1:$B$100)>0),1))-ROW(),0)
How does it work?
Starting with the outermost part, OFFSET($B2, VALUE, 0) - this will start in cell B2, then look up or down by VALUE rows to get the value.
Next we need to know how many rows we will need to look up-or-down. Now, if we can work out the bottom-most row with data, we can subtract the current ROW() from that, giving us OFFSET($B2, NON_BLANK-ROW(),0)
So, to finish up we need to work out which rows are not blank, AND which rows are on-or-above our current row, then take the largest of those. This is going to take an ArrayFormula, but we can use SUMPRODUCT to make that calculate properly. To find the largest number we could use MAX or LARGE - but we get less errors if we pick AGGREGATE(14,6,..,1). (The 14 means "we want the kth largest number", the 6 means "ignore error values", and the 1 is k - so "we want the largest number, ignoring errors")
But, what list of numbers are we going to look at, I don't hear you ask. Well, we want the ROW for output from our range (I'm using $B$1:$B$100, because using the whole column B would take far to long to calculate repeatedly), a comparison against the current ROW(), and check that the LENgth is > 0. Those last two are comparisons, so let's write them out first:
ROW($B$1:$B100)<=ROW()
and
LEN($B$1:$B$100)>0
We want to use -- to convert TRUE and FALSE to 1 and 0 - this means that any "bad" values become 0, and any "good" values are larger than 0:
ROW($B$1:$B$100)*--(ROW($B$1:$B$100)<=ROW())*--(LEN($B$1:$B$100)>0)
This gives us the Row number when the Row is on-or-before the current row AND Column B is not blank - if either of those are False, then we get 0 instead. Stick that in the AGGREGATE to find the largest number:
AGGREGATE(14, 6, ROW($B$1:$B$100)*--(ROW($B$1:$B$100)<=ROW())*--(LEN($B$1:$B$100)>0), 1)
Then put it in a SUMPRODUCT to force Excel to treat it as an ArrayFormula, and that's your NON_BLANK. This then gives you that first formula right at the top of the post

Compare Excel sheets values to update a third value

Example file So I have two sheets that each have lists of part numbers, plant where they come from and two columns on costs. What I need to do is scan them and if Sheet A and Sheet B both have a row with matching part numbers and the plant they come from, then A's two cost values are updated to match B's costs.
The next step is then to highlight all cells in Sheet A that are not on Sheet B and highlight all cells in Sheet B that were copied to Sheet A. I think this last part can be done at the same time the cell is being copied I'm just not sure how to do any of this.
This is a formula method.
Because you will not be changing all the values and I assume you want to keep those that do not have a match, then in an empty column next to the figures on sheet 1 put the following formula:
=IFERROR(INDEX(Sheet2!F$3:F$7,MATCH(1,INDEX((Sheet2!$D$3:$D$7=$A3)*(Sheet2!$B$3:$B$7=$C3),),0)),G3)
Then copy over one column and down the the end of the data.
The INDEX((Sheet2!$D$3:$D$7=$A3)*(Sheet2!$B$3:$B$7=$C3),) will create an array of 0 and 1's the same size as the data reference on sheet 2. In this instance it will create a 1 dimensional array that is 5 objects.
The position of these objects of 0 and 1 are relative to the rows. So for the first formula the return array will be {0,1,0,0,0} because only the second row of the data matches both the plant and the part number.
The MATCH(1,INDEX(...),0) then finds the first object in that array that is 1 and returns the relative position, in this case 2 as it is the second in the array.
The Outer INDEX(Sheet2!F$3:F$7,...) then returns the value in the range Sheet2!F$3:F$7 whose relative position is equal to the 2 passed from the MATCH(). So Sheet2!F4.
If no MATCH is found then the whole thing will throw a #N/A error so we capture that error with IFERROR(...,G3) and tell the formula to return the value in column G instead.
This will give you all the proper values:
Then you can copy and paste just the values back to the original spots and hide the columns with the formulas:
Sheet2 for reference:
If you want vba to do the last part of copy and past and hiding then use the macro recorder and then clean up the code.

Trailing Average Using AverageIf in Excel

I am trying to find the average for the last 3 instances only. I am using the AVERAGEIF statement and it will calculate the average for the entire range but I need it to only calculate for that last 3 instances it finds (or less if there is less than 3 available). I need the entire column for G and H to have the average for the last 3 games that the Team played.
This is what I have:
=AVERAGEIF(B3:C17,B17,D3:E17)
You can do this with array formulas (They have to be entered using the keys Ctrl+Shift+Enter)...
Basic steps are:
Find the row (including and above current) that is the third highest row number containing the team name (or use row 1 otherwise)
Use the INDIRECT ranges in your AVERAGEIF from B-that_row to C-current_row and D_that_row to E-current_row
So in cell F17 you would have the formula
{=AVERAGEIF(INDIRECT("B"&LARGE(IF(--($B$3:B17=B17)+($C$3:C17=B17),ROW($B$3:B17),1),3)&":"&CELL("address",C17)),B17,INDIRECT("D"&LARGE(IF(--($B$3:B17=B17)+($C$3:C17=B17),ROW($B$3:B17),1),3)&":"&CELL("address",E17)))}
We repeat some of the logic, because we have two ranges (criteria range and average range).
IF(--($B$3:B17=B17)+($C$3:C17=B17),ROW($B$3:B17),1) means that if column B or (using +) column C has the value of in B17, give me the row number, otherwise 1 (our <3 case... we could make this 3, the first row of team names)
LARGE(...,3) will give us the third highest of this array --> the third highest row number having our team name
INDIRECT("B"&...&":"&CELL("address",C17)) is going to give us the range using our third highest row number to the current row, columns B and C
then we do exactly the same thing as you were doing in AVERAGEIF but using this INDIRECT range and the equivalent for columns D and E
Fun question! Good luck. And remember to use Ctrl+Shift+Enter to enter it!
EDIT The above was giving an #NUM! error for the first two rows - that was because the LARGE function was trying to get the third largest in an array of 2! Also noticed that there were some cases where the column letter needed to be absolute (i.e. $) for copying to the Away column. So the updated formula:
{=AVERAGEIF(INDIRECT("B"&LARGE(IF(--($B$3:$B17=B17)+($C$3:$C17=B17),ROW($B$3:$B17),1),MIN(3,ROW()-2))&":"&CELL("address",$C17)),B17,INDIRECT("D"&LARGE(IF(--($B$3:$B17=B17)+($C$3:$C17=B17),ROW($B$3:$B17),1),MIN(3,ROW()-2))&":"&CELL("address",$E17)))}
Replaced the 3 with MIN(3,ROW()-2) so that we get 3 if there are, but 1 or 2 if we are in one of the first two data rows
OK I posted this prematurely and attempted to delete it when I realised it wouldn't work. It should work now.... providing you add another condition which is the game dates in column A. Remember that this is an array formula so hit ctrl+shift+enter. Dates in column A; teams in column B; stats in column D. This formula can reside somewhere permanent on the sheet so you can enter the team name (shown as F13 here) to get the three most recent stats.
=AVERAGE(VLOOKUP(LARGE(IF(B3:B24=F13,A3:A24),1),A3:D24,4),VLOOKUP(LARGE(IF(B3:B24=F13,A3:A24),2),A3:D24,4),VLOOKUP(LARGE(IF(B3:B24=F13,A3:A24),3),A3:D24,4))