I need to create a Match formula based on the Cells like the example bellow:
+------+--------+--------+
| Col1 | SumCol | Val |
+------+--------+--------+
| 1 | 8 | v1 | '=Match([otherWorkbook]MainSheet!C1,RC3,[otherWorkbook]MainSheet!C8)
| 2 | 5 | v44* | '=Match([otherWorkbook]MainSheet!C2,RC3,[otherWorkbook]MainSheet!C5)
| 3 | 7 | ls* | '=Match([otherWorkbook]MainSheet!C3,RC3,[otherWorkbook]MainSheet!C7)
+------+--------+--------+
To build the formula I need to get the string "[otherWorkbook]MainSheet" and concatenate with Cell from Column Col1. Then i need to get the value from Column Val. Finally I neet to concatenate again the string "[otherWorkbook]MainSheet" with cell from Column SumCol.
I expect a formula like =Match([otherWorkbook]MainSheet!C1,RC3,[otherWorkbook]MainSheet!C8). I could make it using two temp Columns to make the concatenation and then, build the wole formula.
PS: I'm using VBA to make the formula, so i can use it to reach my goal.
Maybe you need something like this :
Sub AddFormulas()
myOtherWorkbook = "[otherWorkbook]"
myFormula1 = "=Match(" & myOtherWorkbook & "MainSheet!C"
myFormula2 = ",RC3," & myOtherWorkbook & "MainSheet!C"
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For x = 2 To lastRow 'Loops from row 2 to the last of column "A"
Cells(x, 4).Formula = myFormula1 & Cells(x, 1) & myFormula2 & Cells(x, 2) & ")"
Next x
End Sub
Related
Given two columns (A and B), one with a text and one with an integer, such as:
A | B
pen | 3
pen | 5
How could I fill the columns C, D, E [...] with the concatenation of the given string on each row with all integers starting from 1 until the specified number?
The desired output for the given example would be:
A | B | C | D | E | F | G
pen | 3 | pen01 | pen02 | pen03 | |
pen | 5 | pen01 | pen02 | pen03 | pen04 | pen05
With a simple vba sub this can be achieved:
Sub CreateValues
With ActiveSheet
Dim LastRow as Long: LastRow = .Range("A" & .Rows.Count).End(xlup).Row
For i = 1 To LastRow
Max_Num = .Cells(i, 2)
For j = 1 to Max_Num
.Cells(i, j + 2) = .Cells(i, 1) & Format(j, "00")
Next j
Next i
End With
End Sub
If you are looking for a formula solution without needing to resort to VBA, you can use this formula in C1 and drag in both dimensions:
=IF(COLUMNS($C1:C1)<=$B1,CONCATENATE($A1,TEXT(COLUMNS($C1:C1),"00")),"")
I got 2 columns on 2 sheets of ~100000 cells long.
Those columns look like this:
---------
| 1 | a |
---------
| 2 | b |
---------
| 3 | c |
---------
| 4 | d |
---------
| 5 | e |
---------
and this:
---------
| 1 | a |
---------
| 3 | k |
---------
| 2 | b |
---------
| 4 | d |
---------
Now I am comparing the first columns to each other, if they match it has to check if the second column also matches. So the result will look like this:
---------------------
| 1 | a | correct |
---------------------
| 2 | b | correct |
---------------------
| 3 | c | wrong |
---------------------
| 4 | d | correct |
---------------------
| 5 | e | not found |
---------------------
I am using this function to do this: =IFERROR(IF(VLOOKUP(A3;newsheet!A:B;2;FALSE)=B3;"Correct";"Wrong");"Not Found") But to do this, it takes very long, I am using excel 2016 and all my 4 processors. Now it calculates slower and slower, probably because I got the first column on alphabetical order both, but the deeper it gets, the more rows it is going to check. So is there any way to let the VLOOKUP function not check the cells, it did already found an agreement.
So in my example: if it found the | 1 | a |, the next round it will search only the following remaining items:
---------------------
| 2 | b | correct |
---------------------
| 3 | c | wrong |
---------------------
| 4 | d | correct |
---------------------
| 5 | e | not found |
---------------------
Thanks in advance for helping me out with this problem
Unless you need the values to dynamically update; the VBA is a better alternative to 100K formulas. Using an ArrayList and arrays it took 1.98 seconds to process the data.
Sub ValidateData()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'You'll need to adjust these const values
Const LOOKUP_SHEET As String = "newsheet"
Const TARGET_SHEET As String = "oldsheet"
Dim x As Long, y As Long
Dim data As Variant, results As Variant
Dim key As String
Dim list As Object
Set list = CreateObject("System.Collections.ArrayList")
With Worksheets(LOOKUP_SHEET)
'Load the values from columns A and B into an array
data = .Range("A1", .Range("A" & .Rows.Count).End(xlUp)).Resize(, 2)
End With
For x = 1 To UBound(data, 1)
'Create a unique identifier
'using a delimiter to ensure value don't mix
key = data(x, 1) & "|" & data(x, 2)
If Not list.Contains(key) Then list.Add key
Next
With Worksheets(TARGET_SHEET)
'Load the values from columns A and B into an array
data = .Range("A1", .Range("A" & .Rows.Count).End(xlUp)).Resize(, 2)
'Resize the results array
ReDim results(1 To UBound(data), 1 To 1)
For x = 1 To UBound(data, 1)
'Create a unique identifier
'using a delimiter to ensure value don't mix
key = data(x, 1) & "|" & data(x, 2)
results(x, 1) = IIf(list.Contains(key), "Correct", "Wrong")
Next
.Range("C1").Resize(UBound(results, 1)) = results
End With
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Can't post comments because of rep issues, but assuming they are sorted suitably this I think does what you ask.
Edit:
Also if you want to check both columns at once instead of going one at a time, you can join the two columns to make a proxy. i.e. Autofilling down =A1 & B1
So you get a third column containing
1a
2b
2c
etc.
Cuts the vlookups required in half :)
Sub ihopethishelps()
Dim last As Long
Dim r As Long
Range("B1").Select
Selection.End(xlDown).Select
last = ActiveCell.Row - 1
Range("C1").Select
For r = 0 To last
ActiveCell.Offset(r, 0).Value = _
"=IFERROR(IF(VLOOKUP(A" & r + 1 & ",Sheet2!A" & r + 1 & ":O" & last & ",2,FALSE)=B" & r + 1 & "," & Chr(34) & "Correct" & Chr(34) & "," & Chr(34) & "Wrong" & Chr(34) & ")," & Chr(34) & "Not Found" & Chr(34) & ")"
Next
End Sub
I have a large data set which looks like this:
Employee ID |Job| Function| Level|Date of change
1 | x | a | A1 | 01/05/2014
1 | y | a | A1 | 02/04/2015
1 | y | a | A2 | 25/08/2015
1 | z | a | A3 | 27/12/2015
1 | z | c | A3 | 01/03/2016
2 | t | b | B1 | 12/05/2013
2 | v | b | B1 | 13/04/2014
2 | w | b | B3 | 12/01/2016
Each row contains a change in either job, function or level.
I need to create a table which puts together the latest change in level for each employee (so for employee 1, it would be row 4). So far I have used a combination of conditional formatting and pivots but I was wondering if there is a way to do this quicker in VBA.
Thanks!
Without VBA
This assumes that there are genuine dates in column E with format dd/mm/yyyy, In G1 enter the Array Formula:
=MAX(IF(A:A=1,E:E,""))
This gives the latest date for employee 1
Array formulas must be entered with Ctrl + Shift + Enter rather than just the Enter key.
Then in G2 enter:
=SUMPRODUCT(--(A1:A9=1)*(E1:E9=G1)*(ROW(1:9)))
This gives the row number of the record you are interested in.
From there you can use INDEX() to get any information from that row.
NOTE:
The formulas in G1 and G2 can be combined into a single cell if desired.
EDIT#1:
The same set of formulas should work with text values for the employee id as well as numbers:
Not sure this is the best solution, but since this is a one-off exercise and it did the trick I used this:
VBA to find all the rows where there was a change in level, and write a "yes" in column "F" where applicable:
Sub JLChange()
Dim Data As Worksheet
Dim i As Long
Dim lastrow As Long
Set Data = ThisWorkbook.Worksheets("Data")
lastrow = Data.Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lastrow
If Cells(i + 1, 4).Value <> Cells(i, 4).Value And_
Cells(i + 1,1).Value = Cells(i, 1).Value Then
Cells(i + 1, 6).Value = "Yes"
Else
Cells(i + 1, 6).Value = "No"
End If
Next i
End Sub
For all the records in column "F", I used the formulas suggested by Gary's student to get the very last change.
Alternatively, you can copy-paste this database of changes in a new sheet, sort by ID and by date of change from newest to oldest, then use vlookup to get the first entry for each ID.
I have a spreadsheet like this:
Item Category | Customer Category
--------------|-------------------
A | Z
A | Z
A | Y
B | Y
B | Z
B | Z
etc.. on to > 35K rows.
I am trying to write a VBA module to count and merge rows which are the same in both columns, but keep coming up short.
I want output like:
Item Category | Customer Category | Count
--------------|--------------------|------
A | Z | 2
A | Y | 1
B | Y | 1
B | Z | 2
And so on...
It sounds so simple, and I found numerous examples on here sorting and counting much more complicated spreadsheets, but can't get mine to work.
Try this easy way using Advance Filter.
Sub Test()
Dim rng As Range, lrow As Long
With Sheet1
.Columns("E:G").ClearContents: .Range("G1") = "Count"
Set rng = .Range("A1", .Range("B" & .Rows.Count).End(xlUp))
rng.AdvancedFilter Action:=xlFilterCopy, _
CopyToRange:=.Range("E1"), Unique:=True
lrow = .Range("E" & .Rows.Count).End(xlUp).Row
With .Range("G2", "G" & lrow)
.Formula = "=COUNTIFS(A:A,E2,B:B,F2)"
.Value = .Value
End With
End With
End Sub
I think this is ok with 35k. So everytime you run the code, it will summarize items in Columns A and B to Columns E to G. Just something to get you started. And of course the easiest would be a Pivot Table as commented by Tim. HTH
I have my excel sheet like this:
A | B
-----
0 | 2
0 | 3
0 | 4
0 | 5
0 | 6
0 | 7
1 | 8
1 | 9
1 | 10
1 | 11
1 | 12
2 | 13
2 | 14
...
How do I get the value of B for the last occurrence of each value in A?
The output is -
C | D
0 | 7
1 | 12
2 | 14
Is there an easy way of doing this? Thanks!
Assuming you already have 0, 1, 2 etc. listed in C1 down then use this formula In D1 copied down
=LOOKUP(C1,A:B)
Highlight the entire table.
On Data tab, in the Outline pane click the Subtotals button.
In the At change in... box, select A.
At the Use function box, select Max.
In the Add Subtotal to box make sure B has a check mark
Click OK.
Use the dashes to collapse each section.
That will avoid any programming or formulas and leave the data intact.
To get the last value in column A use this formula:
=INDEX(A:A, COUNTA(A:A), 1)
The following will get the last value in column B:
=INDEX(B:B, COUNTA(B:B), 1)
A sample using a macro:
Sub LastValueInB()
VarA = Range("A1").Value
VarB = Range("B1").Value
Output = ""
For i = 1 To 10
If Range("A" & i).Value = VarA Then
VarB = Range("B" & i).Value
Else
Output = Output + VarA & VarB & vbCrLf
VarA = Range("A" & i).Value
End If
Next i
MsgBox Output
End Sub