This seems extremely easy, but I just can't seem to get my head around it. So I have two columns. A has names and B has values. All I want to do is duplicate this list (into column D and E) just excluding 0 values in column B.(I put an example of what I am looking for below)
I am not that great at excel so this has been a bit of a challenge. I am trying to get it to work with a formula as I need it to automatically update when the values in column B change.
Any help would be greatly appreciated.
You could use a pivot table. Drag Goals to the rows, Values to the values field well. Then right-click any of the goals in the pivot table and select Filter > Value Filters, and filter on the value total to be not zero.
When more data is added to the sheet, just refresh the pivot table, which could be automated with VBA.
I believe I have a formula version that should work. Pull the first nonzero row over to D2:E2 (either manually or with simple index formulas) and then use the following in D3 and E3:
D3=IFERROR(INDEX(OFFSET($A$1,MATCH(D2&E2,$A$1:$A$99&$B$1:$B$99,0),0,99),MATCH(TRUE,(OFFSET($B$1,MATCH(D2&E2,$A$1:$A$99&$B$1:$B$99,0),0,99)<>0),0)),"")
E3=IFERROR(INDEX(OFFSET($B$1,MATCH(D2&E2,$A$1:$A$99&$B$1:$B$99,0),0,99),MATCH(TRUE,(OFFSET($B$1,MATCH(D2&E2,$A$1:$A$99&$B$1:$B$99,0),0,99)<>0),0)),"")
Then auto-fill to the bottom of your list.
Note that these are array formulas, so they must be entered using Ctrl+Shift+Enter. Also, if your list is longer than 99 then update all the 99's in the formula to a number at least as large as your list length.
The way this works is by using an OFFSET formula to start the search for non-zero values just below the previously listed result.
You could simply use if formulas to check the value like this...
'Column D formula:
=IF(E1="","",A1)
'Column E Formula:
=IF(B1=0,"",B1)
Although I doubt this is what you are looking for as it would just leave blank cells in column D and E if the value in column B is 0.
I would recommend using a macro that can be much more dynamic in nature.
Sub Check_Values()
Application.ScreenUpdating = False
Range("D:E").Select
Selection.ClearContents
Dim name As Integer, val As Integer
Dim name1 As Integer, val1 As Integer
Dim Emptyrw As Long, Emptyrw1 As Long, Emptyrw2 As Long
Dim i As Integer
name = 1
val = 1
name1 = 1
val1 = 1
Emptyrw = WorksheetFunction.CountA(Range("B:B")) + 1
Emptyrw1 = WorksheetFunction.CountA(Range("D:D")) + 1
Emptyrw2 = WorksheetFunction.CountA(Range("E:E")) + 1
i = 1
Do While val < Emptyrw
If Cells(val, 2) <> 0 Then
Range(Cells(name, 1), Cells(val, 2)).Select
Selection.Copy
Range(Cells(Emptyrw1, 4), Cells(Emptyrw2, 5)).Select
Selection.PasteSpecial
Application.CutCopyMode = False
End If
name = name + 1
val = val + 1
name1 = name1 + 1
val1 = val1 + 1
Emptyrw1 = Emptyrw1 + 1
Emptyrw2 = Emptyrw2 + 1
Loop
Do While i < Emptyrw1
If Cells(i, 4) = "" Then
Range(Cells(i, 4), Cells(i, 5)).Select
Selection.Delete Shift:=xlUp
End If
i = i + 1
Loop
End Sub
You can just copy this code into your VBA and assign a command button to it and should work for you.
Good Luck!
My effort...
Enter into D2 using Ctrl+Shift+Enter:
=INDEX(A:A,SMALL(IF($B$2:$B$20<>0,ROW($A$2:$A$20),999),ROWS(A$2:A2)),1)&""
Then fill down and across.
Make the "999" large enough to always be beyond the list of values.
Downside: appending the "" to prevent zeros showing up makes numbers behave as text.
Related
I have two sheets :
Sheet 1 consist of :
Sheet 2 consist of :
And the output should show in M column in Sheet1. I am attaching the sample output here :
So,what I have here is ID in Sheet 1, for eg : ID 'US' has Abhay,Carl and Dev
and in Sheet3, I have names in column and ID in Rows.
What i want is my Sample output column should populate using macro based on matched values from Sheet3
I am using below logic but something is going wrong :
For i = 2 To 10
j = i + 1
If ThisWorkbook.Sheets("Input").Range("N" & i) = ThisWorkbook.Sheets("Sheet3").Range("A" & i) And ThisWorkbook.Sheets("Input").Range("K" & i) = ThisWorkbook.Sheets("Sheet3").Range("B1") Then
ThisWorkbook.Sheets("Input").Range("O" & i) = ThisWorkbook.Sheets("Sheet3").Range("B" & j)
End If
Next i
Since you asked for a VBA solution, please see the code below.
Dim colLen As Integer
Dim i As Integer
Dim colPt As Integer
Dim rowPt As Integer
' Counts number of rows on Sheet 1, column B.
colLen = Sheets(1).Cells(Rows.Count, "B").End(xlUp).Row
' Loops through all names on Sheet 1.
For i = 2 To colLen
' Retain US or NA ID for blank cells.
If Sheets(1).Cells(i, 1) <> "" Then
If Sheets(1).Cells(i, 1) = "US" Then
colPt = 2
Else
colPt = 3
End If
End If
' Find name on Sheet 2 and set row.
rowPt = Sheets(2).Range("A:A").Find(Sheets(1).Cells(i, 2)).Row
' Add ID from Sheet 2 to Sheet 3
Sheets(1).Cells(i, 3) = Sheets(2).Cells(rowPt, colPt)
Next i
Assumptions:
Sheet 1 is the main worksheet, sheet 2 has the lookup data.
All names in the lookup data are unique.
I would recommend including the ID in every row instead of treating it as a heading but that's preference. There are formula solutions that would work for this as well if you want to skip VBA.
There are a few ways to approach this. Below is one of them:
NOTE: for simplicity, I have kept my data on one sheet. You can amend the below formulas as your data is on 2 sheets. Saying that, I have used the same columns as you have in your query
Solution:
Have a "holding column". In my example, I used column J as the holding column (you can hide this column if you want). In J2, type the following formula: =IF(ISBLANK($K2), $J1,$K2). Copy the formula down to all used rows. Then copy the following formula in M2: =VLOOKUP($L2,$A$3:$C$8,IF($J2="US",2,3),FALSE). As per before, copy the formula down to all used rows. This should give you your results
Heylo, I am trying to write an excel function that takes a user-selected range and performs different calculations based on the column the cell being populated lines up with. The screenshot below shows the setup of the columns.
I want to set AA5 to be "=myFunction($AA1:$AD4)", and then I want click-and-drag to use the autofill feature to populate AB5, AC5, and AD5 with the same "=myFunction($AA1:$AD4)" but this myFunction will do different things based on which cell is being populated during the autofill.
I know how to do this in a subroutine where the user would select the first open cell AA5, and is prompted for the range to use for calculations. I would do something along the lines of:
Sub CalcCells()
Dim myRange As Range
Set myRange = Application.InputBox("Select the cells you want to use...", Type:=8)
Dim numColumn As Long
For numColumn = 0 To myRange.Columns.Count - 1
Select Case numColumn
Case Is = 0
ActiveCell.Offset(0, numColumn).Formula = "=SUM(" + myRange.Columns(1) + ")"
Case Is = 1
ActiveCell.Offset(0, numColumn).Formula = "=SUMPRODUCT(" + myRange.Columns(1) + "," + myRange.Columns(2) + ")"
Case Is = 2
ActiveCell.Offset(0, numColumn).Formula = "=SUMPRODUCT(" + myRange.Columns(1) + "," + myRange.Columns(3) + ")/SUM(" + myRange.Columns(1) + ")"
Case Is = 3
ActievCell.Offset(0, numColumn).Formula = "=SUMSQ(" + myRange.Columns(4) + ")"
End Select
Next numColumn
End Sub
So basically I want to do exactly this, but I want it to be a function that when I click and drag and autofill AB5:AD5 it knows which column the cell lines up with and performs a calculation based on that, and uses it as an argument/parameter almost. It will not always be 4 rows either, so it needs to be capable of accommodating varying row counts, but the .Columns should work with that as long as the user selects only the same datatype.
Is this possible and how can I do it? Thank you for any help in advance. I've done a lot of searching and I don't know if I'm not searching the right way, but i cannot find anything that really helps.
What about something like this? Basically, you get the column of the cell you enter the formula into with Application.Caller.Column. Then inputRange.Column gives you the leftmost column of your input range. Based on the difference of the two, you know which worksheet function you want to use. If the difference is 0, your formula is entered in the 1st column, so you use Sum. If the difference is 1, you use Sumproduct, and so on.
Function SummarizeCells(inputRange As Range) As Double
Dim col As Long
col = Application.Caller.Column - inputRange.Column
Select Case col
Case 0
SummarizeCells = WorksheetFunction.Sum(inputRange.Columns(1))
Case 1
SummarizeCells = WorksheetFunction.SumProduct(inputRange.Columns(1), inputRange.Columns(2))
Case 2
SummarizeCells = WorksheetFunction.SumProduct(inputRange.Columns(1), inputRange.Columns(3)) / WorksheetFunction.Sum(inputRange.Columns(1))
Case 3
SummarizeCells = WorksheetFunction.SumSq(inputRange.Columns(4))
End Select
End Function
A sample view here:
I have a spreadsheet in which there are multiple rows that have three columns (K, L M) that contain text (inserted manually from a dropdown). The inserted text includes a 'score'. For the row shown in the image that score is 3 + 2 + 2 = 7.
What I'd like to be able to do is to have that score automatically calculated and shown in column N. I'm happy to do the score extraction given the text, but I'm completey unfamiliar with Excel's object model, and how to write a VBA macro that can be triggered across all of the rows. I assume it would be passed a range somehow, or a string designating a range, but how to do that is beyond me just now. Perhaps I just need a formula? But one that calls a function to strip non-numerical data from the cell?
Any help appreciated.
Put this formula in N2 cell and drag it all the way down.
=LEFT(K2, FIND("-", K2) - 2) + LEFT(L2, FIND("-", L2) - 2) + LEFT(M2, FIND("-", M2) - 2)
For more information see reference. It sum all numbers, that are present before the hyphen (-) in a cell.
Try:
N2 = LEFT(TRIM(K2),1) + LEFT(TRIM(L2),1) + LEFT(TRIM(M2),1)
As I said in comments, this solution does not scale so well if it is more than three columns and / or the scores are more than single digit [0-9]
A VBA solution to do all of your rows and enter the values into Column N:
Sub foo()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set your worksheet, amend as required
LastRow = ws.Cells(ws.Rows.Count, "K").End(xlUp).Row
'get the last row with data on Column A
For rownumber = 1 To LastRow 'loop through rows
For i = 11 To 13 'loop through columns
strValue = ws.Cells(rownumber, i).Value 'get text string from cell
pos = InStr(strValue, " -") 'find the dash - in cell
If pos > 0 Then 'if dash found
Value = Value + Val(Left(ws.Cells(rownumber, i).Value, pos - 1)) 'remove everything after number
End If
Next i
ws.Cells(rownumber, 14).Value = Value 'write value to column N
Value = 0
Next rownumber
End Sub
In Microsoft Excel I want to create a table to be something like in picture below.
I already try using vlookup and index but I can't make it work like I want.
Please help me
Try to use VBA:
Sub TransformTbl()
Dim i As Long, j As Long, cnt As Long
With ActiveSheet
.Range("G1:I1") = Array("Date", "Event", "Place")
cnt = 1
For j = 2 To 4 'column
For i = 2 To 5 'row
If Len(.Cells(i, j)) <> 0 Then
cnt = cnt + 1
.Cells(cnt, 7) = .Cells(1, j) 'Date
.Cells(cnt, 8) = .Cells(i, j) 'Event
.Cells(cnt, 9) = .Cells(i, 1) 'Place
End If
Next i
Next j
End With
End Sub
I wrote a solution and it works fine with me. The formula is really complex and probably hard to understand. Though I'll try my best to explain it, updating the formula may still be a difficult work. All these three formula are written in Array Formula, press ctrl+shift+enter to complete.
Formula in G6:
=IFERROR(OFFSET($A$5,0,SMALL(
IF($B$6:$D$9<>"",1,99999999)*(COLUMN($B$6:$D$9)-1),ROW(A1))),"")
The outer IFERROR keeps your sheet from any #Err. The OFFSET for calling the right date. The formula inside SMALL generate an array with the rule: If there is an event, the value will be the number of the date for offset, otherwise, it will be 99999999 which giving the OFFSET an error and be blocked by IFERROR. With the data you gave, the array will be
{ 1,99999999, 3;
1, 2,99999999;
1,99999999,99999999;
99999999,99999999, 3 }
Formula in H6:
=IFERROR(OFFSET($A$5,
SMALL(IF($B$6:$D$9<>"",ROW($B$6:$D$9)-5)*
IF(COLUMN($B$6:$D$9)=MATCH(G6,$B$5:$D$5,0)+1,1,99999999),99999999),COUNTIF($G$6:G6,G6)),
MATCH(G6,$B$5:$D$5,0)),"")
The IFERROR and OFFSET works the same as G6. The formula in OFFSET.ROW generate nearly the same array as G6. This time the value is the row of event with the date determined by column G. Other gives 999999999 or more.
Formula in I6:
=IFERROR(OFFSET($A$5,MAX((ROW($B$6:$D$9)-5)*($B$6:$D$9=H6)*
(COLUMN($B$6:$D$9)=MATCH(G6,$B$5:$D$5,0)+1)),0),"")
IFERROR and OFFSET are still the same. And this time only the event which matches the date and the name of itself has a value, other remains 0.
Finally, I apologize for the poor readability. Wish someone can help me out with this :]
I need to merge cells using a formula so that the cells only merge when cells on another tab are filled.
I have 2 tabs with the same amount of columns in each. I want cells a1-d1 to merge in tab 1 when cells a1-d1 in tab 2 are filled and for the value of d1 in tab 2 to be inputted into the newly merged cells in tab 1.
this is what I have:
Excel VBA Methods and Function (Excel Macros) overview
Since you want to change cells i do not believe that you can use a formula (even not a user defined one). Therefore i wrote an excel vba macro for your problem.
FirstRows(): Is the starting point. It loops over 10 rows and calls the other methods
CheckEmptyCellValues(curRow): This method checks for empty cells in tab2 (sheet 2 in excel)
MergeCells(curRow) takes the current row as a number (any integer from 1 to max amount of rows) and merges the cells from column 1 to 4 on Sheet 1 (the first sheet in excel)
Fully working demo tested with 4 columns and 10 rows
Sub FirstRows()
Sheets(1).Select
For curRow = 2 To 11
Merge = CheckEmptyCellValues(curRow)
If Merge = 4 Then
MergeCells (curRow)
cellValue = Sheets(2).Cells(curRow, 4).Value
Sheets(1).Cells(curRow, 1).Value = cellValue
End If
Next
End Sub
Sub MergeCells(curRow)
Sheets(1).Select
Range(Cells(curRow, 1), Cells(curRow, 4)).MergeCells = True
End Sub
Function CheckEmptyCellValues(curRow)
Merge = 0
Sheets(2).Select
For i = 1 To 4
If Len(Cells(curRow, i).Value) > 0 Then
Merge = Merge + 1
End If
Next
CheckEmptyCellValues = Merge
End Function
Below you can see the result. The values from sheet 2 haven been copied to sheet 1 (second image). In Sheet 1 the Cells in a row are merged (in row 2 from Cell A2 up to Cell D2 (A2-D2 is now just one cell) if in the first image (sheet 2) every cell (from column a to column d) in a row had a value.
Bugs in the modified code
There are a few things in the modifiend code that are not possible or could lead to a wrong understanding
Function CheckEmptyCellValues(curColumn)
Merge = 0
Sheets(2).Select
For i = A To d
If Len(Cells(curColumn, 11).Value) > 0 Then
Merge = Merge + 1
End If
Next
CheckEmptyCellValues = Merge
End Function
The line For i = A To d is not possible. If you want to use a loop you have to use numbers: For i = 1 To 4 this would repeat the code between For and Next4 times starting with 1
This line Cells(curColumn, 11).Value is technical correct but misleading. Excel uses the first value after (for the row-index and the second value for the column-index. Both values have to be a number: Cells(4,2).Value returns the Cell value from the 4th. row and the second Column (in the Excel Gui the Cell B4)
Try changing this line For i = A To d to this For i = 1 To 4 and see if that returns the wished result.
Bugs part 2
In your other modification you have some of the same bugs:
The loop For curColumn = A to d needs numbers instead of letters (unless A and d were a variable filled with a number but according to your code sample this is not the case
The line cellValue = Sheets(2).Cells(curColumn, d).Value has the same bug, if d is just the letter d and not something like d = 4 than you can not use it in a loop.
This is the code from your comment:
Sub FirstRows()
Sheets(1).Select
For curColumn = A To d
Merge = CheckEmptyCellValues(curColumn)
If Merge = d Then
MergeCells(curColumn)
cellValue = Sheets(2).Cells(curColumn, d).Value
Sheets(1).Cells(curColumn, d).Value = cellValue
End If
Next
End
Sub Sub MergeCells(curColumn)
Sheets(1).Select
Range(Cells(curColumn, 1), Cells(curColumn, d)).MergeCells = True
End Sub
Be carefull it is not running.