Copying multiple cells in same row based on multiple criteria - vba

Background: I have an Excel file used for tracking credit card payables. There are 18 columns of data (A through R). Out of these 18 columns, I want to use a macro to filter for specific statement date and then for a specific company code.
Each company code will be assigned a new worksheet. In each of these worksheets, I want to bring over specific cells from the master worksheet based on the criteria. For instance, the macro should first sort for statement date (7/31/2012) and then company code (ABC). Then, I need to run a loop to bring over details. For instance, in the master worksheet, the GL code in column P needs to be copied to the "ABC" worksheet in column H.
Here's a summary of what needs to happen:
1. Clear any filters in filter range (A2:R2)
2. Filter for date in cell A1 on "Master" worksheet beginning in cell A3 (date column)
3. Filter for company code (ABC) in column O
That should give a data set for particular company's statement activity. Here's what needs to happen next:
4. Copy Column P cell values in "master" worksheet to Column C in "ABC" worksheet
5. Copy Column N cell values in "master" worksheet to Column D in "ABC" worksheet
6. Copy Column R cell values in "master" worksheet to Column H in "ABC" worksheet
7. Copy Column F cell values in "master" worksheet to Column G in "ABC" worksheet, but max of 30 characters
8. If Column G value in "master" worksheet is >=0, then copy that value to Column E in "ABC" worksheet (otherwise needs to be zero)
9. If column G value in "master" worksheet is <0, then copy that value to Column F in "ABC" worksheet (otherwise needs to be zero)
Is this possible?

Here's a sub that should get you started. I did not implement all your steps, but I believe this is enough to take and finish on your own. If you find this answer is helpful to get you where you need to go, please accept this answer. If you have problems with anything here, please add a comment to this answer asking for clarification.
I have only tested on dummy data, but what I did work with was successful.
Option Explicit
Sub TransferData()
Dim Master As Worksheet
Dim NewSheet As Worksheet
Dim CompanyList As Object
Dim lRow As Long, lMaxRow As Long, lNewRow As Long
Dim vDictItem As Variant
Set CompanyList = CreateObject("Scripting.Dictionary")
Set Master = ThisWorkbook.Sheets("Master")
If Master.FilterMode Then
Master.ShowAllData
End If
Master.Range("A:R").Sort Master.Range("A2"), xlAscending, Master.Range("O2"), , xlAscending, , , xlYes
lMaxRow = Master.Range("A" & Master.Rows.Count).End(xlUp).Row
For lRow = 3 To lMaxRow
If Not CompanyList.Exists(Master.Range("A" & lRow).Value) Then
CompanyList.Add Master.Range("A" & lRow).Value, Master.Range("A" & lRow).Value
End If
Next lRow
For Each vDictItem In CompanyList.Keys
Master.Range("A3:R" & lMaxRow).AutoFilter 1, vDictItem
If Master.Cells.SpecialCells(xlCellTypeVisible).Count > 0 Then
Set NewSheet = ThisWorkbook.Worksheets.Add
NewSheet.Name = vDictItem
lNewRow = 1
For lRow = 3 To lMaxRow
If Master.Rows(lRow).Hidden = False Then
lNewRow = lNewRow + 1
NewSheet.Range("C1").Value = Master.Range("P1").Value
NewSheet.Range("C" & lNewRow).Value = Master.Range("P" & lRow).Value
NewSheet.Range("G1").Value = Master.Range("F1").Value
NewSheet.Range("G" & lNewRow).Value = Left(Master.Range("F" & lRow).Value, 30)
NewSheet.Range("E1").Value = Master.Range("G1").Value & " (POS)"
NewSheet.Range("F1").Value = Master.Range("G1").Value & " (NEG)"
If Master.Range("G" & lRow).Value >= 0 Then
NewSheet.Range("E" & lNewRow).Value = Left(Master.Range("G" & lRow).Value, 30)
Else
NewSheet.Range("F" & lNewRow).Value = Left(Master.Range("G" & lRow).Value, 30)
End If
End If
Next lRow
End If
Next vDictItem
End Sub

Related

Excel loop condition based concatenation [duplicate]

This question already has answers here:
PowerQuery: How can I concatenate grouped values?
(3 answers)
Closed 4 years ago.
I am very new to excel macros and i need your help to fix one of my condition based concatenation problem.
i will explain the problem with simple scenario in below:
In my sheet , Column A contains customer name and Column B contains country names. Attached excel screenprint for reference ( column C and Column D will be my expected results)
In the column A, single customer name can be repeated as he can have multiple country representations
In the column B, countries placed as shown in the screenprint.
My expected results will be look alike in the column C and D as shown in the image.
I can do the column C using INDEX and i am able to get the unique values from column A
For the column D ,i am expecting the results in such a way that all countries will be concatenated and separated by ' / ' based on the corresponding customer in column A. I tried some vlookups and indexes, but i am unable
to do it.
it would be really helpful if you could provide any suggestions(function/Macros) how it will be achieved.
I am a lower intermediate vba user, so I will admit that I am sure someone can do this better than , however, this works. Add a button and then click on it, or add this to the worksheet and it will occur whenever you choose for it to be fired:
Option Explicit
Sub listout()
'declare your variables
Dim wbk As Workbook
Dim ws1 As Worksheet
Dim cprange As Range
Dim rmrange As Range
Dim bottomRow As Long
Dim row As Range
Dim countname As Variant
Dim copyname As Variant
Dim nametoRow As Long
'speed up process
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
'set what the variables are
Set wbk = ThisWorkbook
Set ws1 = wbk.Worksheets("Names List")
bottomRow = ws1.Range("A1").End(xlDown).row
'get ird of any excisting values
ws1.Range("C1:D100").ClearContents
'Set the range of the names that you want to copy, and put them into column C
Set cprange = ws1.Range(Range("A1"), Range("A1" & bottomRow))
ws1.Range(Range("C1"), Range("C1" & bottomRow)) = cprange.Value
'then remove all the duplicates
Set rmrange = ws1.Range(Range("C1"), Range("C1" & bottomRow))
rmrange.RemoveDuplicates Columns:=1, Header:=xlNo
'redclare the range as it will be shorter because you got rid of load sof duplicates
Set rmrange = ws1.Range(Range("C1"), Range("C1").End(xlDown))
'loop though each name in the 'unique' list and loop through their names in the original data then add the country to their new location in column D
For Each copyname In rmrange
For Each row In cprange
nametoRow = ws1.Application.WorksheetFunction.Match(copyname, rmrange, False)
countname = row.Offset(0, 1)
If row.Value = copyname Then
If Trim(ws1.Range("D" & nametoRow) & vbNullString) = vbNullString Then
ws1.Range("D" & nametoRow) = countname
Else
ws1.Range("D" & nametoRow) = ws1.Range("D" & nametoRow) & "/ " & countname
End If
End If
Next row
Next copyname
'turn these back on otherwise it messes with your computer/excel
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Here is a more efficient method.
Advanced Filter to remove duplicates from Col A, paste on Col C
Set necessary ranges
Loop through each unique name
Build String
Paste String
Loop 4 - 6 until complete
Assumptions/Actions: You have headers on Col A, B, C, & D. If you have duplicate countries for a person, the country will show up twice on the string.You will need to change "Sheet1" to your sheet name on the 3rd line.
Usually you would need to check if your value is found using the .Find method, but the below logic does not allow for a cell to not be found as it is looping through values determined by filter. It wouldn't make since for a filtered object to not be found in the range it came from.
Option Explicit
Sub CountryList()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim FoundCell As Range, SearchRange As Range, Names As Range, SearchCell As Range
Dim MyString As String, i As Long
Set SearchRange = ws.Range("A2:A" & ws.Range("A" & ws.Rows.Count).End(xlUp).Row)
SearchRange.AdvancedFilter Action:=xlFilterCopy, CopyToRange:=ws.Range("C2"), Unique:=True
ws.Range("C2").Delete Shift:=xlShiftUp
Set Names = ws.Range("C2:C" & ws.Range("C" & ws.Rows.Count).End(xlUp).Row)
For Each SearchCell In Names
Set FoundCell = SearchRange.Find(SearchCell)
For i = 1 To Application.WorksheetFunction.CountIf(SearchRange, SearchCell)
MyString = MyString & FoundCell.Offset(, 1) & "/"
Set FoundCell = SearchRange.FindNext(FoundCell)
Next i
SearchCell.Offset(, 1) = Left(MyString, Len(MyString) - 1)
MyString = ""
Next SearchCell
End Sub

Partial string match then return value

I'm working on a way to quickly code bank transactions. I have one tab of bank data downloaded (sheet 1) and I want to search the descriptions (column B) for a partial match with sheet 2, column A. Then if match found, return the value from sheet 2, column B to sheet 1 column D; and sheet 2, column C to sheet 1, column E.
Sheet 1
Column A Column B Column C Column D Column E
11/1/17 Transfer from Account 60617829-D 276 {acct} {location}
11/1/17 Transfer from Account 60692022-D 551.46 {acct} {location}
Sheet 2
Column A Column B (acct) Column C (location)
60617829-D 10430 03
60692022-D 10490 09
I was trying to use a solution similar to "Find and Get" described here: Excel Formula/VBA to search partial strings in other sheet
However, the following code returns the first value from sheet 2 to all values on sheet 1 without properly matching them. I think my error is in how I'm trying to use an array when it may not be necessary but I am at a loss.
Sub findAndGet()
Dim sh1, sh2 As Worksheet
Dim tempRow1, tempRow2 As Integer
Dim strList() As String
Dim name As String
Dim index As Integer
'Set sheets
Set sh1 = Sheets("list")
Set sh2 = Sheets("search")
'Set the start row of Sheet1
tempRow1 = 1
'Loop all row from starRow until blank of column A in Sheet1
Do While sh1.Range("A" & tempRow1) <> ""
'Get name
name = sh1.Range("B" & tempRow1)
'Split by space
strList = Split(Trim(name), " ")
'Set the start row of Sheet2
tempRow2 = 1
'Reset flag
isFound = False
'Loop all row from startRow until blank of column A in Sheet2
Do While sh2.Range("A" & tempRow2) <> ""
For index = LBound(strList) To UBound(strList)
'If part of name is found.
If InStr(UCase(sh2.Range("A" & tempRow2)), UCase(strList(index))) > 0 Then
'Set true to search flag
isFound = True
'exit do loop
Exit Do
End If
Next index
'Increase row
tempRow2 = tempRow2 + 1
Loop
'If record is found, set output
If isFound Then
'set account
sh1.Range("D" & tempRow1) = sh2.Range("B" & tempRow2)
'set location
sh1.Range("E" & tempRow1) = sh2.Range("C" & tempRow2)
End If
'Increase row
tempRow1 = tempRow1 + 1
Loop
End Sub
If formula solution is acceptable then assuming that data begins on both sheets on row number 2.
In cell D2 of Sheet1 insert following formula and copy down.
=LOOKUP(2^15,SEARCH(Sheet2!$A$2:$A$3,Sheet1!B2,1),Sheet2!$B$2:$B$3)
In cell E2 of Sheet1 insert following formula and copy down.
=LOOKUP(2^15,SEARCH(Sheet2!$A$2:$A$3,Sheet1!B2,1),Sheet2!$C$2:$C$3)

Search column in one sheet for cells containing string, then reference them another sheet

What I'd like to do is search for a specific string in a column in one sheet (let's call it Sheet 1), and reference the values in a column adjacent to those matched cells in another sheet (Sheet 2).
To make it more clear, here's a diagram illustrating what I'm trying to do:
What I'd like to do is search the Customer column in Sheet 1 for "Acme", then populate a column in Sheet 2 with each Acme entry's corresponding sample, ignoring any non-Acme entries.
I'm going to guess that this would be more complex than a regular Excel macro and would require a VBA function. Either way, I would be immensely grateful if someone could at least point me in the right direction as to where to begin searching.
Here is a single sheet example, without VBA, that you can adapt to your needs:
In D1 enter:
Acme
In D2 enter the array formula:
=IFERROR(INDEX($A$1:$B$9,SMALL(IF($A$1:$A$9=$D$1,ROW($A$1:$A$9)),ROW(1:1)),2),"")
and copy down.
Array formulas must be entered with Ctrl + Shift + Enter rather than just the Enter key.
This will find the first row of sheet1 with customer "Acme". It will find the first row of sheet2 with the customer name "Acme" and add the contents of sheet1 "Acme" row column C to whatever is in sheet2 Acme row column "C". It assumes these numbers are values, not strings. You can change that by deleting the addition. You can also change columns or anything else to suit your needs.
Sub updateSheet2()
Dim customerNameColumnSheet1 As String, customerNameColumnSheet2 As String
Dim lastRowSheet1 As Long
Dim lastRowSheet2 As Long
Dim customerName As String
Dim Sheet1Row As Long
Dim Sheet2Row As Long
customerNameColumnSheet1 = "A"
customerNameColumnSheet2 = "A"
customerName = "Acme" ' or customerName = Sheet1.Range("A12").value, etc
lastRowSheet1 = Sheet1.Cells(Rows.Count, customerNameColumnSheet1).End(xlUp).row
lastRowSheet2 = Sheet2.Cells(Rows.Count, customerNameColumnSheet2).End(xlUp).row
With Sheet1.Range(customerNameColumnSheet1 & "1:" & customerNameColumnSheet1 & lastRowSheet1)
Set c = .Find(customerName, LookIn:=xlValues, lookat:=xlPart)
If Not c Is Nothing Then
Sheet1Row = c.row
With Sheet2.Range(customerNameColumnSheet2 & "1:" & customerNameColumnSheet2 & lastRowSheet2)
Set D = .Find(customerName, LookIn:=xlValues, lookat:=xlPart)
If Not D Is Nothing Then
Sheet2Row = D.row
Sheet2.Range("C" & Sheet2Row).Value = Sheet1.Range("C" & Sheet1Row).Value' + Sheet2.Range("C" & Sheet2Row).Value ' assuming values, not string
End If
End With
End If
End With
End Sub

Search for same values in sheet1 and sheet2 and copy the values from sheet1 to sheet2

I have worked along time with excel but aren't very good at VBA, so I need help to make an macro and I cant get a recording macro to work :(
I have an excel file with 2 sheets (Sheet1 and Sheet2).
I want to compare a text from Sheet2 (column A) with sheet1 (column B) and if it finds same text in both sheets so do I want the macro to copy column A,B,C and D from sheet1 over to column B,C,D and E in sheet2.
In sheet 1 I have more than 6000 rows so I don't want to do this manually or do a formula in excel, I want a macro that does this for me.
The sheets have headers, can someone maybe help me with this ?
I'm a little unclear on what you are trying to do. This is my interpretation: suppose that, for a value in row X column A on sheet 1 -- if you find a corresponding value on sheet 2 in row Y column B -- you want to copy from sheet 1 the cells on row X belonging to columns A B C D and paste them on sheet 2 in row Y columns B C D E.
If that is correct, try this:
Sub copyCells()
Dim wb As Workbook, firstWs As Worksheet, secondWs As Worksheet
Dim matchIndex As Integer
Set wb = ThisWorkbook
Set firstWs = wb.Worksheets(1)
Set secondWs = wb.Worksheets(2)
Application.ScreenUpdating = False
' We'll start at i=2 to account for the header
For i = 2 To firstWs.Range("A2:A6000").Rows.count
On Error Resume Next
' MATCH will find the row number in sheet 2 - change the range specifications as needed
matchIndex = Application.WorksheetFunction.Match(firstWs.Range("A" & i), secondWs.Range("B2:B6000"), 0)
Err.Clear
On Error GoTo 0
' MATCH will throw an error if it finds no results.
' Hence: if matchindex contains an error, do nothing.
' But if it doesn't contain an error, it must contain a row number - so we can proceed.
If Not Application.WorksheetFunction.IsNA(matchIndex) Then
secondWs.Range("B" & matchIndex).Value = firstWs.Range("A" & i).Value
secondWs.Range("C" & matchIndex).Value = firstWs.Range("B" & i).Value
secondWs.Range("D" & matchIndex).Value = firstWs.Range("C" & i).Value
secondWs.Range("E" & matchIndex).Value = firstWs.Range("D" & i).Value
End If
Next i
Application.ScreenUpdating = True
End Sub

Create a VBA macro that Find and Copy?

I need a little bit help with a macro of Excel.
I need to create a macro that automatically find users and copy the values that i have in an other Sheet:
I have one sheet with values that contains the Users and their Kills and Deaths, I create 3 sheets more (3 different groups of users), and I need that the macro copy values automatically finding the users and copying values.
Images to describe it better:
----(Copy this values on)----->
You don't need a macro for this, using the worksheetfunction VLOOKUP is sufficient.
As an example, if you have your headers in row 1 and users in column A, what you'd put into cell B2 (the number of kills for the first user) would be =VLOOKUP($A2;Values!$A$2:$C$9;2;FALSE) and C2 would be =VLOOKUP($A2;Values!$A$2:$C$9;3;FALSE).
The arguments for the function (which you can also find in the linked document) is:
First, the value you're looking for, in your case whatever is in A2
Next the array of values which you want to return a result from - vlookup will only look through the first column, but since you want to return results from the other columns we include columns A:C in the formula.
What column in the range you search to return the result from for kills it is column 2, for deaths column 3.
Finally whether you want to have an exact match (false) or if an approximate one is ok (true).
If I understand what you're after, you should be able to do this with VLOOKUPs
(No VBA necessary)
The following source code solve your problem.
Option Explicit
Dim MyResultWorkbook As Workbook
Dim ValuesWorksheet As Worksheet
Dim SniperWorksheet As Worksheet
Dim ARsWorksheet As Worksheet
Sub CopyResult()
Set MyResultWorkbook = ActiveWorkbook
Set ValuesWorksheet = MyResultWorkbook.Sheets("Values")
Set SniperWorksheet = MyResultWorkbook.Sheets("Sniper")
Set ARsWorksheet = MyResultWorkbook.Sheets("Ars")
Dim SniperLastRow As Long
Dim ARLastRow As Long
Dim RowPointer As Long
Dim ValuePointer As Long
ValuePointer = 2
'Update the Sniper worksheets
SniperLastRow = SniperWorksheet.Cells(SniperWorksheet.Rows.Count, "A").End(xlUp).Row
For RowPointer = 2 To SniperLastRow
Do While (SniperWorksheet.Range("A" & RowPointer).Value <> ValuesWorksheet.Range("A" & ValuePointer).Value)
ValuePointer = ValuePointer + 1
Loop
SniperWorksheet.Range("A" & RowPointer).Offset(0, 1).Value = ValuesWorksheet.Range("A" & ValuePointer).Offset(0, 1).Value 'copy kill
SniperWorksheet.Range("A" & RowPointer).Offset(0, 2).Value = ValuesWorksheet.Range("A" & ValuePointer).Offset(0, 2).Value 'copy death
ValuePointer = 2
Next
'Update the Ars worksheets
ARLastRow = ARsWorksheet.Cells(ARsWorksheet.Rows.Count, "A").End(xlUp).Row
For RowPointer = 2 To ARLastRow
Do While (ARsWorksheet.Range("A" & RowPointer).Value <> ValuesWorksheet.Range("A" & ValuePointer).Value)
ValuePointer = ValuePointer + 1
Loop
ARsWorksheet.Range("A" & RowPointer).Offset(0, 1).Value = ValuesWorksheet.Range("A" & ValuePointer).Offset(0, 1).Value 'copy kill
ARsWorksheet.Range("A" & RowPointer).Offset(0, 2).Value = ValuesWorksheet.Range("A" & ValuePointer).Offset(0, 2).Value 'copy death
ValuePointer = 2
Next
End Sub