I have 3 worksheets (user1, user2, result). Each sheet has three columns (A: System_ID, B: Comment, C: Last Modified Time).
The code does this:
Gets maximum last modified time between user1 and user2 in column c.
The result is to get that comment in column b (adjacent to max time found in col c)
put the result (comment) in column b in resut sheet
Simply the comment with last modified time wins and gets pasted in result WS.
Anyways, my problem is that I only can index-match if both indexes in column A have the same sorting/order.
I need to match all records in column A even if they have different row.number or row index.
How to index-match no matter the order in column A
Sub Get_LastModified_Here()
Application.EnableEvents = False
Dim Location1 As Workbook
Set Location1 = GetWorkbook("C:\Users\HP\Desktop\User_1.xlsb")
Dim Location2 As Workbook
Set Location2 = GetWorkbook("C:\Users\HP\Desktop\User_2.xlsb")
Dim SourceCell As Range, SourceRange As Range, CurrentRange As Range
Dim rngTarget As Range
Dim strAdr As String
Dim vSource As Variant, vTarget As Variant, vCurrent As Variant
Dim i As Long
Set SourceRange = Workbooks("User_2.xlsb").Sheets("Data").Range("A2:" & "A1607")
With SourceRange
Set SourceRange = .Resize(.Rows.Count, .Columns.Count + 3)
End With
strAdr = SourceRange.Address
Set rngTarget = Workbooks("User_1.xlsb").Worksheets("Data").Range(strAdr)
Set CurrentRange = ThisWorkbook.Worksheets("Data").Range(strAdr).Offset(0, 1)
vSource = SourceRange
vTarget = rngTarget
vCurrent = CurrentRange
For i = 1 To UBound(vSource, 1)
'Match Column A
If vSource(i, 1) = vTarget(i, 1) Then
'Check max time in Column C (user1 vs user2)
If vSource(i, 3) > vTarget(i, 3) Then
'Get max comment from ((user max)) in column B (result ws)
vCurrent(i, 1) = vSource(i, 2)
ElseIf vSource(i, 3) < vTarget(i, 3) Then
vCurrent(i, 1) = vTarget(i, 2)
ElseIf vSource(i, 3) = vTarget(i, 3) Then
vCurrent(i, 1) = vSource(i, 2)
End If
End If
Next i
SourceRange = vSource
rngTarget = vTarget
CurrentRange = vCurrent
Application.EnableEvents = True
End Sub
Here is a detailed explanation of the issue (I apologize for CAPS letters):
User1 Sheet
I have the SYSTEM_ID in ## Row 1 ##
System_ID
Comment
LastModTime
ID_1
User1 notes
09/12/2020 10:00:01 PM
User2 Sheet
I have the SAME SYSTEM_ID in ## Row 2 ##
System_ID
Comment
LastModTime
ID_1
User2 notes
09/12/2020 10:00:02 PM
This is what I GET in Result Sheet
I have the SAME SYSTEM_ID but in ## Row 3 ##
System_ID
Comment
LastModTime
ID_1
This is what I Want in Result Sheet
I have the SAME SYSTEM_ID but in ## Row 3 ##
System_ID
Comment
LastModTime
ID_1
User2 notes
09/12/2020 10:00:02 PM
What our codes CAN do
Get the comment based on the last modified time, ONLY IF "ID_1" is on THE SAME ROW #. i have tried it (didn't work)
What our codes CAN'T do
Get the comment based on the last modified time, EVEN IF "ID_1" is on A DIFFERENT ROW #. this is where I need help?
EDIT to confirm that the assumptions match:
Sheet User1:
| Id | Comment | LastMod |
| --- | ------- | --------|
| 3 | S1 Comm3| 2 |
| 2 | S1 Comm2| 8 |
| 1 | S1 Comm1| 6 |
Sheet User2:
| Id | Comment | LastMod |
| --- | ------- | --------|
| 1 | S2 Comm1| 3 |
| 2 | S2 Comm2| 4 |
| 3 | S2 Comm3| 8 |
Expected Output:
Id
Comment
NOTES
1
S1 Comm1
Id 1 highest mod is on sheet 1
2
S1 Comm2
Id 2 highest mod is on sheet 2
3
S2 Comm3
Id 3 highest mod is on sheet 3
One option is to build up the result set into a separate collection, and then populate your result set when finished. Since this is an operation that involved multiple lookups (checking to see if a system Id has already been visited), I like to use dictionary objects. These offer highly performant lookup operations.
I'm going to post a much simplified example below that you can hopefully use for your purposes. The code below assumes that the SystemId column is a unique key that maps an entry in sheet1 to an entry in sheet2. It also assumes that each systemId appears once per sheet. If not, it can be tweaked to support that.
The code basically loops through the range and checks if the rows in both sheets have matching system ID. If so, it adds that row to the dictionary, using the ID as a key, and a two element array containing the comment and the last mod time.
If they don't match, it checks each entry against the dictionary to see if that systemID was already visited (earlier on the other sheet). If so, it compares the entries and keeps the most recent mod time, otherwise, it leaves it as is.
Try to work through it and let us know if you need additional help.
Sub Tester()
Dim oDict As Object
Dim a(0 To 1)
Dim sUser1 As Worksheet
Dim sUser2 As Worksheet
Set oDict = CreateObject("Scripting.Dictionary")
Set sUser1 = Sheets("User1")
Set sUser2 = Sheets("User2")
'Here I will assume that both ranges will always
'be the same length. I'm also hardcoding in the
'needed rows. You can use whichever logic
'works best for you to determine how to capture
'all rows in both sheets
For i = 2 To 8
'Two possibilities here:
' 1. The SystemId in both sheets match and
' can be directly compared
' 2. They differ and will each be checked
' to see if they already exist in the dict.
'You can bypass this and just treat each of the
'ranges individually, but I think it would be
'slightly more performant the way I'm doing it.
'
'Also, this assumes that each SystemId will only
'appear once in each sheet, and is a true Primary Key
If sUser1.Cells(i, 1).Value = sUser2.Cells(i, 1) Then
If sUser1.Cells(i, 3).Value > sUser2.Cells(i, 3).Value Then
MergeEntryToDictionary oDict, sUser1.Cells(i, 1).Value, _
sUser1.Cells(i, 2).Value, sUser1.Cells(i, 3).Value
Else
MergeEntryToDictionary oDict, sUser2.Cells(i, 1).Value, _
sUser2.Cells(i, 2).Value, sUser2.Cells(i, 3).Value
End If
Else
'In case they don't match, check each entry against the
'dictionary to see if the systemId has already been added.
'If not, then add it. Otherwise, compare the last mod date
'of the entry to the current, and update if needed.
MergeEntryToDictionary oDict, sUser1.Cells(i, 1).Value, _
sUser1.Cells(i, 2).Value, sUser1.Cells(i, 3).Value
MergeEntryToDictionary oDict, sUser2.Cells(i, 1).Value, _
sUser2.Cells(i, 2).Value, sUser2.Cells(i, 3).Value
End If
Next i
'Below prints back to sheet
Dim k As Variant
Dim n As Long
n = 2
For Each k In oDict.keys
Sheets("result").Cells(n, 1).Value = k
Sheets("result").Cells(n, 2).Value = oDict(k)(0)
Sheets("result").Cells(n, 3).Value = oDict(k)(1)
n = n + 1
Next k
End Sub
Function MergeEntryToDictionary(ByRef oDict As Object, _
SystemId As String, _
sComment As String, _
LastModTime As Double) As Boolean
Dim a(0 To 2)
If oDict.exists(SystemId) Then
If LastModTime > oDict(SystemId)(1) Then
a(0) = sComment
a(1) = LastModTime
oDict(SystemId) = a
End If
Else
a(0) = sComment
a(1) = LastModTime
oDict.Add SystemId, a
End If
MergeEntryToDictionary = True
End Function
Related
New to the forum and hope someone can help.
Create a function to loop through a set of data row by row for sorting.
Firstly need to check if column 1 is not equal to 9999. If not insert into the appropriate row using column 1 as the sort criteria. If it equals 9999 then insert into the appropriate spot using column 3 and column 2.
The problem I'm encountering is that some row and not sort. I think its because as I'm cutting and pasting the row is missed. Below is my code and the sample data
Sub insertionTableSort()
'PURPOSE: loop through all employee and apply the sort as follows:
'1) Seniority <> 9999 Seniority number
'2) Seniority = 9999 sort start date then employee number
Dim ws As Worksheet
Dim tbl As ListObject
Set ws = ThisWorkbook.Worksheets("Roster Applications")
Set tbl = ws.ListObjects("RosterRequest") '## modify to your table name.
Set tblRow = tbl.ListRows
'Loop Through Every Row in Table
For x = 2 To tbl.Range.Rows.Count - 1
'Debug.Print x & ", " & tbl.DataBodyRange(x, 1).Value, tbl.DataBodyRange(x, 2).Value, tbl.DataBodyRange(x, 4).Value
For y = 2 To tbl.Range.Rows.Count
'seniroity = 9999
If tbl.DataBodyRange(x, 1) = 9999 Then
'sort by start date then Staff Num
If tbl.DataBodyRange(x, 4) < tbl.DataBodyRange(y - 1, 4) And tbl.DataBodyRange(x, 2) < tbl.DataBodyRange(y - 1, 2) Then
tbl.ListRows(x).Range.Cut
tbl.ListRows(y - 1).Range.Insert
Exit For
End If
Else
'seniroity <> 9999
'sort by seniority
If tbl.DataBodyRange(x, 1) < tbl.DataBodyRange(y - 1, 1) Then
tbl.ListRows(x).Range.Cut
tbl.ListRows(y - 1).Range.Insert
Exit For
End If
End If
Next y
Next x
End Sub
sample data after running the above
sorts well until this point where row 2 should be before row 1 and there are other examples
Data initially sort by Register No.
Errors highlighted in yellow
Finished Sort
I am trying to add values from different sheets (Sheet 2 to 5) into my main sheet (Sheet 1). In Sheet 1 I want the cells to contain the right formula pointing to the different sheets (if possible).
Typically like this:
='Sheet2'!D5+'Sheet3'!D165
All my sheets have different products, but some sheets contain same products. So I want to search through them all and ADD them in my Main Sheet (Sheet 1).
Sub UpdateMainSheet()
' Kode for å Oppdatere Plukkeliste Alle Artikler Summert
Dim AktivtArk As String
Dim AktivtArkNavn As String
Dim K As Integer
Dim Count As Integer
'Line of code to delete old data in Main Sheet:
Worksheets("Sheet1").Range("A2:H10000").Clear
AktivtArkOverskrift = "List of Articles from Sheet 2 to 5"
'Creates Headline in Main Sheet:
eRow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
Worksheets("Sheet1").Cells(eRow, 1) = AktivtArkOverskrift
Worksheets("Sheet1").Cells(eRow, 1).Font.Bold = True
'Script to check and gather data from the other sheets (Sheet 2, 3, 4 and 5):
For K = 2 To 5
'For loop to check each line in sheet "K"
For I = 2 To 1000
'If function to check if the cell I in column F is empty, if so it_jumps to next row and do the same check:
If Worksheets(K).Cells(I, 6) > 0 Then
Count = 0
'For loop to check if I already have a row in the Main Sheet with the article I'm checking:
For L = 2 To 1000
'If function to check if the articles have the same article number:
If Worksheets(K).Cells(I, 1) = Worksheets("Sheet1").Cells(L, 1) Then
'Line of code that are supposed to ADD the values that is currently in the Main Sheet, togheter with the value in Sheet K:
Worksheets("Sheet1").Cells(I, 4).Formula = Worksheets("Sheet1").Cells(I, 4) + Worksheets(K).Cells(L, 4)
End If
Next L
End If
Next I
Next K
End Sub
So what I need to fix in my code is this part (located furthest inside the For Loop):
Worksheets("Sheet1").Cells(I, 4).Formula = Worksheets("Sheet1").Cells(I, 4) + Worksheets(K).Cells(L, 4)
And make it create a formula in the wanted cell, that looks something like this:
='Sheet2'!D5+'Sheet3'!D165
It must be able to add another cell as well, since the Loop are running through several Sheets (Sheet 2 to 5) that may contain the same products.
I.e. I only want one line in my Main Sheet for each product.
I managed to find the solution in the end.
It seemed I had switched the L and I in som of the looping, which resulted in the values not to be added togheter.
The following code (I did not translate to English, but can do this if someone wants/need it) solved my issue, and gave me the values from Sheet 2 to 5 sorted by product in Sheet 1:
Sub OppdaterePlukkelisteSummert()
'Kode for å Oppdatere Plukkeliste Alle Artikler Summert
Dim AktivtArk As String
Dim AktivtArkNavn As String
Dim K As Integer
Dim Teller As Integer
Dim value1 As Integer
Dim value2 As Integer
'Sletter Plukklisten for å oppdatere og sortere på nytt:
Worksheets(1).Range("A2:H10000").Clear
'HENTING AV DATA FRA ARKET "K":
AktivtArk = "Artikler Summert fra Alle Ark"
AktivtArkOverskrift = "Artikler Summert fra Alle Ark"
'Setter inn Overskrift som Forteller kva ark utstyret kommer fra:
eRow = Sheets(1).Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
Worksheets(1).Cells(eRow, 1) = AktivtArkOverskrift
Worksheets(1).Cells(eRow, 1).Font.Bold = True
'Sjekker hvilke/hvilket rader/utstyr som skal plukkes, og legger det inn i "Ark1":
For K = 2 To 5
For I = 2 To 1000
If Worksheets(K).Cells(I, 6) > 0 Then
Teller = 0
For L = 2 To 1000
If Worksheets(K).Cells(I, 1) = Worksheets(1).Cells(L, 1) Then
value1 = Worksheets(1).Cells(L, 4)
value2 = Worksheets(K).Cells(I, 4)
Worksheets(1).Cells(L, 4) = value1 + value2
Worksheets(1).Cells(L, 6) = value1 + value2
Else
Teller = Teller + 1
End If
Next L
If Teller > 998 Then
eRow = Sheets(1).Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
For J = 1 To 11
Worksheets(1).Cells(eRow, J) = Worksheets(K).Cells(I, J)
Next J
Worksheets(1).Cells(eRow, 6).Font.Color = RGB(0, 150, 0)
Worksheets(1).Cells(eRow, 7).Font.Color = RGB(0, 150, 0)
End If
End If
Next I
Next K
Worksheets(1).Range("A2").Select
End Sub
I hope this can be useful for someone else :-)
All help and suggestion in the comments are appreciated!
I was going to illustrate with this simple example:
I = 1 'for example
For K = 2 To 5
Worksheets("Sheet1").Cells(I, 4).Value = Worksheets("Sheet1").Cells(I, 4).Value + _
WorksheetFunction.SumIf(Worksheets(K).Range("A:A"), "Bananas", Worksheets(K).Range("D:D"))
Next K
I have a shared excel sheet with records being entered all the time. I want to find the last consecutive entry of a specific Name(its 'A' in this example) and record the value at the begining and ending of last occurance.
The output of the attached excel should be
A,2,34 ---when i open when there were 5 entries
A,5,null ---when i opened when there were 9 entries
A,9,6 ---when i opened when there were 11 entries
A,9,3 ---when i opened when there were 12 entries
please help me with the formula that i can use in a different tab of same excel.
Thanks
this should work.
in column C use this formula. Works from row2 and down. row1 should be irrelevant (no consecutive entries at this point).
=IF(B1=B2,B2&","&A1&","&A2,"")
You can also have a formula display whatever is the last entry for that value. This is for value "A".
=LOOKUP(2,1/(B:B=E1),C:C)
A UDF should be able to handle the relative loop.
Option Explicit
Function LastConColVals(rng As Range, crit As String, _
Optional delim As String = ",")
Dim tmp As Variant, r As Long, rr As Long
'allow full column references
Set rng = Intersect(rng, rng.Parent.UsedRange)
With rng
tmp = Array(crit, vbNullString, vbNullString)
For r = .Rows.Count To 1 Step -1
If .Cells(r, 2).Value = crit Then
tmp(2) = .Cells(r, 1).Value
For rr = r To 1 Step -1
If .Cells(rr, 2).Value = crit Then
tmp(1) = .Cells(rr, 1).Value
Else
Exit For
End If
Next rr
'option 1 - null last value for singles
If rr = (r - 1) Then tmp(2) = "null"
'option 2 - truncate off last value for singles
'If rr = (r - 1) Then ReDim Preserve tmp(UBound(tmp) - 1)
Exit For
End If
Next r
End With
LastConColVals = Join(tmp, delim)
End Function
I have a table where user can insert multiple rows over multiple columns where some data is string and some numeric. I want to create a button such that when the user clicks it, it will create a new table on the same excel sheet but with some of the rows combined based on predefined condition.
Eg. The table "pre defined condition" states that alpha and gamma are similar and so on(it can many rows like this which show the conditions to combine rows..condition will always pertain to second row of the user defined table i.e table 1)...Table 1 will be created by a different user and he can enter as many rows as he wishes to. So using these 2 tables (Table 1 & Pre defined condition tabel) I want to create a new table which has certain rows combined with stringfrom two rows separated using "/" and numbers added.
The structure will remain the same for all tables.
Edit:One value in column 2 will always have same value in column 1.Basically column 2 is a dependent list(on column 1 ). There can be many pre -defined conditions and not just limited to 2 . Usually there won't be any duplicate values in column 2,but in case there are I want to combine them in a row at click of the button.
Table 1
A Alpha 100 1
B Beta 200 2
C Gamma 300 3
D Kappa 400 4
Pre Defined Condition
Alpha Gamma
Beta Kappa
Desired Output
A/C Alpha/Gamma 400 4
B/D Beta/Kappa 600 6
Assuming that your data starts in A2:D2 (A1:D1 left for titles), that you state two conditions (for example Alpha Gamma) in columns F and G (starting in the second row; first row left for titles), that there is a command button, and that the worksheet is named "Sheet1", the following code should do the trick.
Dim i As Integer
Dim j As Integer
Dim lLastRowPDC As Integer
Dim lLastRowData As Integer
Dim sConditions As String
Dim sOrigin As String
Dim sColumnA As String
Dim sColumnB As String
Dim iColumnC As Integer
Dim iColumnD As Integer
Private Sub CommandButton1_Click()
lLastRowPDC = Worksheets("Sheet1").Cells(2, 6).End(xlDown).Row 'Rows with Conditions, starting in the second row
lLastRowData = Worksheets("Sheet1").Cells(2, 1).End(xlDown).Row 'Rows with data, starting in the second row
For i = 2 To lLastRowPDC
sConditions = Worksheets("Sheet1").Cells(i, 6).Value & Worksheets("Sheet1").Cells(i, 7).Value 'create a string with the two conditions
sColumnA = ""
sColumnB = ""
iColumnC = 0
iColumnD = 0
For j = 2 To lLastRowData
sOrigin = Worksheets("Sheet1").Cells(j, 2).Value
If InStr(sConditions, sOrigin) > 0 Then
If InStr(sColumnA, Worksheets("Sheet1").Cells(j, 1).Value) = 0 Then
sColumnA = sColumnA & Worksheets("Sheet1").Cells(j, 1).Value & "/"
End If
If InStr(sColumnB, Worksheets("Sheet1").Cells(j, 2).Value) = 0 Then
sColumnB = sColumnB & Worksheets("Sheet1").Cells(j, 2).Value & "/"
End If
iColumnC = iColumnC + Worksheets("Sheet1").Cells(j, 3)
iColumnD = iColumnD + Worksheets("Sheet1").Cells(j, 4)
End If
Next j
sColumnA = Left(sColumnA, Len(sColumnA) - 1) 'remove last "/"
sColumnB = Left(sColumnB, Len(sColumnB) - 1) 'remove last "/"
Worksheets("Sheet1").Cells(i, 8).Value = sColumnA
Worksheets("Sheet1").Cells(i, 9).Value = sColumnB
Worksheets("Sheet1").Cells(i, 10).Value = iColumnC
Worksheets("Sheet1").Cells(i, 11).Value = iColumnD
Next i
End Sub
I have a text data set that I need to reformat before I can use it. It's currently a text file that I've imported into Excel. Each record currently spans three rows but is in one column. I need to transform it so it's one row with three columns.
The sample below is how my data is currently structured. It shows three records out of 2,000+. The 'Row' column is just for reference and not actually in my data.
Row | Column
1 | File Number: 001
2 | File Code: ABC
3 | File Description: Text file
4 | File Number: 002
5 | File Code: DEF
6 | File Description: Text file
7 | File Number: 003
8 | File Code: GHI
9 | File Description: Text file
Just to clarify, row 1 to 3 would be one record. Row 4 to 6 would be the second record. The third record is from row 7 to 9. Every record in my data is currently split into three rows.
I want to reformat it so it looks something like this:
Row | File Number | File Code | File Description
1 | 001 | ABC | Text
2 | 002 | DEF | Text
3 | 003 | GHI | Text
Again, the row column is just for reference and I don't need it in my reformatted data. Copy and pasting does not appear to be a good option.
Is there a quick way to transform this?
You can use VBA to do this. Code like this might help you for this particular situation.
Option Explicit
Sub Test()
' Let's make the tabular structure in column C, D and E
' C D E
' File Number Code Description
Dim CurrentRow As Integer
CurrentRow = 2 ' Read from A2
Dim WriteRow As Integer
WriteRow = 2 ' Write to C2
Do
' if we see empty data in column A, then we are done with our work
If Len(Trim(Range("A" & CurrentRow))) = 0 Then Exit Do
' make 3 rows of data into 3 columns in a single row
Range("C" & WriteRow).Value = Trim(Replace(Range("A" & CurrentRow).Text, "File Number:", ""))
Range("D" & WriteRow).Value = Trim(Replace(Range("A" & CurrentRow + 1).Text, "File Code:", ""))
Range("E" & WriteRow).Value = Trim(Replace(Range("A" & CurrentRow + 2).Text, "File Description:", ""))
' increment our reading and writing markers
CurrentRow = CurrentRow + 3
WriteRow = WriteRow + 1
Loop
End Sub
Feel free to test out.
As a reference: this uses TextToColumns, AutoFilter, and places results on a new sheet
Option Explicit
Sub mergeRows()
Dim ws As Worksheet, fld As Variant, i As Long, cel As Range
fld = Split("File Number,File Code,File Description", ",")
Worksheets.Add After:=Worksheets(Worksheets.Count)
Set ws = Worksheets(Worksheets.Count)
Application.ScreenUpdating = False
With Worksheets(1)
Set cel = .Range("A1")
.UsedRange.Columns(1).TextToColumns Destination:=cel.Cells(1, 2), _
DataType:=xlDelimited, _
Other:=True, OtherChar:=":"
.Rows(1).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
cel.Cells(0, 2) = "Col 1": cel.Cells(0, 3) = "Col 2"
.UsedRange.AutoFilter
For i = 0 To 2
.UsedRange.AutoFilter Field:=cel.Cells(1, 2).Column, Criteria1:=fld(i)
.UsedRange.Columns(cel.Cells(1, 3).Column).Copy ws.Cells(1, i + 1)
ws.Cells(1, i + 1) = fld(i)
Next
.UsedRange.AutoFilter
.UsedRange.Offset(, 1).EntireColumn.Delete
cel.Cells(0, 2).EntireRow.Delete
End With
ws.UsedRange.Columns.AutoFit
Application.ScreenUpdating = True
End Sub