Thanks for taking the time to read this. I have a Master contact workbook containing a list of people who need follow up calls. In the very first column of this workbook the initials of the person being assigned the follow-up call are listed (example: CWS). What I want is a formula that will scan all cells in the first column for a set of initials, and then copy the data from columns E through J to a new workbook assigned specifically to that case manager. The code below is just a skeleton, but it was enough to do a small test run. I haven't touched VBA in 10 years so I'm sure it's far from perfect
Sub MoveContactInfo()
Dim xrow As Long
xrow = 4
Sheets("Master Data Set").Select
Dim lastrow As Long
lastrow = Cells(Rows.Count, 1).End(x1Up).Row
Dim rng As Range
Do Until xrow = lastrow + 1
ActiveSheet.Cells(xrow, 1).Select
If ActiveCell.Text = "CWS" Then
rng = Range(Cells(xrow, 5), Cells(xrow, 10))
rng.Copy
Workbooks.Open Filename:="D:\My Documents\Excel Spreadsheets\TEST.xls"
Worksheets("CWS").Select
Cells(4, 1).PasteSpecial
End If
xrow = xrow + 1
Loop
End Sub
Thanks so much for the help. Please let me know if there's anything else I can clarify. For now, I'm just trying to paste to a test workbook I've created filled with worksheets named after each Case Manager.
I would avoid the Do Loop if you're only searching for a single value one time. If you need to modify it to search for the same value more then once, you'll find some good examples of using Range().FindNext here: Range.FindNext Method (Excel).
Sub MoveContactInfo()
Dim Search As String
Dim f As Range
Dim wb As Workbook
Search = "CWS"
With Sheets("Master Data Set")
Set f = .Range("A1", .Range("A" & .Rows.Count).End(xlUp)).Find(What:=Search, After:=Range("A1"), LookAt:=xlWhole, MatchCase:=False)
If Not f Is Nothing Then
Set wb = Workbooks.Open(FileName:="D:\My Documents\Excel Spreadsheets\TEST.xls")
If Not wb Is Nothing Then
On Error Resume Next
f.EntireRow.Columns("E:J").Copy wb.Worksheets(Search).Cells(4, 1)
On Error GoTo 0
End If
End If
End With
End Sub
UPDATE: The OP states in a comment that there are multiple records that need to be copied.
I modified the code to collect the data in an array and write the data to the range in a single operation.
Sub MoveContactInfo()
Dim Search As String
Dim f As Range
Dim Data() As Variant
Dim x As Long
Dim wb As Workbook, ws As Worksheet
Search = "CWS"
ReDim Data(5, x)
With Sheets("Master Data Set")
For Each f In .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
If f.Value = Search Then
ReDim Preserve Data(6, x)
Data(0, x) = f(1, "E")
Data(1, x) = f(1, "F")
Data(2, x) = f(1, "G")
Data(3, x) = f(1, "H")
Data(4, x) = f(1, "I")
Data(5, x) = f(1, "J")
x = x + 1
End If
Next
If Not f Is Nothing Then
Set wb = Workbooks.Open(Filename:="D:\My Documents\Excel Spreadsheets\TEST.xls")
If Not wb Is Nothing Then
On Error Resume Next
Set ws = wb.Worksheets(Search)
On Error GoTo 0
If ws Is Nothing Then
MsgBox "Worksheet not found-> " & Search, vbInformation, "Retry"
Else
ws.Cells(4, 1).Resize(UBound(Data, 2), UBound(Data, 1)) = Application.Transpose(Data)
End If
End If
End If
End With
End Sub
Tidied a few things up. You were pretty close, good effort with being out so long.
Sub MoveContactInfo()
Dim xrow As Long
Dim rng As Range
Set ws = ThisWorkbook.Sheets("Master Data Set")
Set wsDest = Workbooks.Open("D:\My Documents\Excel Spreadsheets\TEST.xlsx")
xrow = 4
ilastrow = ws.Cells(Rows.Count, 1).End(xlUp).Row
initial = "CWS"
j = 1
For i = xrow To ilastrow
If ws.Cells(i, 1).text = initial Then
ws.Range("E" & i & ":J" & i).Copy Destination:=wsDest.Sheets(initial).Range(Cells(j, 1), Cells(j, 6))
j = j + 1
End If
Next i
End Sub
Related
so I have this invoice form that looks like this in Sheet Invoice_Form of an Excel workbook InvoiceForm.xlsm:
and a database of invoice records in Sheet Invoice Database of an Excel workbook InvoiceDatabase.xlsm:
I have created VBA codes that can link records from the form to the invoice database, but what the code manages to do right now is only recording the first row of the invoice form:
The code looks like this:
Sub Submit_Invoice()
Dim LastRow As Long, ws As Worksheet
Set ws = Sheets("InvoiceDatabase")
LastRow = ws.Range("I" & Rows.Count).End(xlUp).Row + 1
ws.Range("K" & LastRow).Value = Worksheets("Invoice Form").Range("C9:C16").Value
ws.Range("L" & LastRow).Value = Worksheets("Invoice Form").Range("D9:D16").Value
....
End Sub
So the question is: How do I modify my code so that it can create multiple records on different rows based on this one form if there are additional products added in the invoice form?
Thanks!
Build an array from the form and dump the array into the InvoiceDatabase.
Sub Submit_Invoice()
Dim lr As Long, ws As Worksheet
dim arr as variant, i as long
with Worksheets("Invoice Form")
lr = .cells(16, "C").end(xlup).row - 8
redim arr(1 to lr, 1 to 6)
for i=lbound(arr,1) to ubound(arr, 1)
arr(i, 1) = .cells(5, "D").value
arr(i, 2) = .cells(6, "D").value
arr(i, 3) = .cells(i+8, "C").value
arr(i, 4) = .cells(i+8, "D").value
arr(i, 5) = .cells(i+8, "E").value
arr(i, 6) = .cells(i+8, "F").value
next i
end with
WITH WORKSheets("InvoiceDatabase")
lr = .Range("I" & .Rows.Count).End(xlUp).Row + 1
.cells(lr, "I").resize(ubound(arr, 1), ubound(arr, 2)) = arr
end with
End Sub
You really should use a form/access database or Excel data form (2016) to do this.
That said, your code is overwriting each row as your write to the other sheet as it isn't incremented. Also, you are missing how you add dates and invoice numbers.
The following uses more meaningful names and adds in the missing data, along with some basic error checks (e.g. there is data to transfer) and housekeeping in terms of clearing the form after transfer.
Option Explicit
Public Sub Submit_Invoice()
Dim nextRowDest As Long, lastRowSource As Long, wsDest As Worksheet, wsSource As Worksheet, transferData As Range
Dim invoiceInfo As Range
Application.ScreenUpdating = False
Set wsDest = ThisWorkbook.Worksheets("InvoiceDatabase")
Set wsSource = Workbooks("Invoice_Form.xlsm").Worksheets("Invoice Form")
With wsSource
lastRowSource = wsSource.Range("C" & .Rows.Count).End(xlUp).Row
If lastRowSource < 9 Then Exit Sub '<==No data
Set transferData = .Range("C9:G" & lastRowSource)
Set invoiceInfo = .Range("D5:D6")
End With
With wsDest
nextRowDest = wsDest.Range("I" & Rows.Count).End(xlUp).Row + 1
If nextRowDest < 4 Then Exit Sub '<==Assume headers are in row 3
transferData.Copy .Range("K" & nextRowDest)
invoiceInfo.Copy
.Range("I" & nextRowDest).Resize(transferData.Rows.Count, invoiceInfo.Rows.Count).PasteSpecial Transpose:=True
End With
transferData.ClearContents
invoiceInfo.ClearContents
Application.ScreenUpdating = True
End Sub
I want to screen all sheets for values that starts with "D"
In the sheets I formed blocks (1 column, 4 rows) with
- owner
- area
- parcel (that is allways starting with a "D")
- year of transaction (blocks of 1 column and 4 rows).
I want to make a summary in sheet "Test".
I'm able to find the parcel, but how can I get the info from the cell above?
Sub Zoek_kavels()
Dim ws As Worksheet
Dim rng As Range
Dim Area
Dim Kavel As String
rij = 1
For Each ws In ActiveWorkbook.Sheets
Set rng = ws.UsedRange
For Each cell In rng
If Left(cell.Value, 1) = "D" Then 'Starts with D
Sheets("Test").Cells(rij, 1) = cell.Value 'Kavel D..
Cells(cell.row - 1, cell.Column).Select
Area = ActiveCell.Value
Sheets("Test").Cells(rij, 2) = Area 'Oppervlakte
Sheets("Test").Cells(rij, 3) = ws.Name 'Werkblad naam
rij = rij + 1
End If
Next
Next
End Sub
A nice simple loop should do the trick, you may have had spaces in the worksheet, that would throw off the used range.
Here is a different approach.
Sub Get_CellAboveD()
Dim LstRw As Long, sh As Worksheet, rng As Range, c As Range, ws As Worksheet, r As Long
Set ws = Sheets("Test")
For Each sh In Sheets
If sh.Name <> ws.Name Then
With sh
LstRw = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range("A1:A" & LstRw)
If LstRw > 1 Then
For Each c In rng.Cells
If Left(c, 1) = "D" Then
r = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row + 1
ws.Range("A" & r).Value = c
ws.Range("B" & r).Value = c.Offset(-1).Value
ws.Range("C" & r).Value = sh.Name
End If
Next c
End If
End With
End If
Next sh
End Sub
There are two important points (and two not so important) to take care of your code:
start from row 2, because you are using .row - 1. Thus, if you start at row 1, row-1 would throw an error;
try to avoid Select, ActiveCell, etc.;(How to avoid using Select in Excel VBA);
write comments in English, not in Dutch (also good idea for variable names as well, rij or kavel do not help a lot);
declare the type of your variables, e.g. dim Area as String or as Long or anything else;
Option Explicit
Sub ZoekKavels()
Dim ws As Worksheet
Dim rng As Range
Dim Kavel As String
Dim rij As Long
Dim cell As Range
rij = 2 'start from the second row to avoid errors in .Row-1
For Each ws In ActiveWorkbook.Worksheets
Set rng = ws.UsedRange
For Each cell In rng
If Left(cell, 1) = "D" Then
With Worksheets("Test")
.Cells(rij, 1) = cell
.Cells(rij, 2) = ws.Cells(cell.Row - 1, cell.Column)
.Cells(rij, 3) = ws.Name
End With
rij = rij + 1
End If
Next
Next
End Sub
Or you can use .Cells(rij, 2) = cell.Offset(-1, 0) instead of Cells(cell.Row - 1, cell.Column), as proposed in the comments by #Shai Rado.
I have written a macro to remove rows containing certain text in it. If either of the keyword contains any text, the macro will delete the row. However, the macro doesn't work at all. Perhaps, i did something wrong in it. Hope somebody will help me rectify this. Thanks in advance.
Here is what I'm trying with:
Sub customized_row_removal()
Dim i As Long
i = 2
Do Until Cells(i, 1).Value = ""
If Cells(i, 1).Value = "mth" Or "rtd" Or "npt" Then
Cells(i, 1).Select
Selection.EntireRow.Delete
End If
i = i + 1
Loop
End Sub
The keyword within the text I was searching in to delete:
AIRLINE DRIVE OWNER mth
A rtd REPAIRS INC
AANA MICHAEL B ET AL
ABASS OLADOKUN
ABBOTT npt P
AIRLINE AANA MTH
ABASS REPAIRS NPT
Try like this.
What about Using Lcase.
Sub customized_row_removal()
Dim rngDB As Range, rngU As Range, rng As Range
Dim Ws As Worksheet
Set Ws = Sheets(1)
With Ws
Set rngDB = .Range("a2", .Range("a" & Rows.Count))
End With
For Each rng In rngDB
If InStr(LCase(rng), "mth") Or InStr(LCase(rng), "rtd") Or InStr(LCase(rng), "npt") Then
If rngU Is Nothing Then
Set rngU = rng
Else
Set rngU = Union(rngU, rng)
End If
End If
Next rng
If rngU Is Nothing Then
Else
rngU.EntireRow.Delete
End If
End Sub
VBA syntax of your Or is wrong,
If Cells(i, 1).Value = "mth" Or "rtd" Or "npt" Then
Should be:
If Cells(i, 1).Value = "mth" Or Cells(i, 1).Value = "rtd" Or Cells(i, 1).Value = "npt" Then
However, you need to use a string function, like Instr or Like to see if a certain string is found within a longer string.
Code
Option Explicit
Sub customized_row_removal()
Dim WordsArr As Variant
Dim WordsEl As Variant
Dim i As Long, LastRow As Long
Dim Sht As Worksheet
WordsArr = Array("mth", "rtd", "npt")
Set Sht = Worksheets("Sheet1")
With Sht
' get last row in column "A"
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = LastRow To 2 Step -1
For Each WordsEl In WordsArr
If LCase(.Cells(i, 1).Value) Like "*" & WordsEl & "*" Then
.Rows(i).Delete
End If
Next WordsEl
Next i
End With
End Sub
I try to make my code sample as I can if you have any question please ask
Private Sub remove_word_raw()
'PURPOSE: Clear out all cells that contain a specific word/phrase
Dim Rng As Range
Dim cell As Range
Dim ContainWord As String
'What range do you want to search?
Set Rng = Range("A2:A25")
'sub for the word
shorttext1 = "mth"
shorttext2 = "rtd"
shorttext3 = "npt"
'What phrase do you want to test for?
ContainWord1 = shorttext1
ContainWord2 = shorttext2
ContainWord3 = shorttext3
'Loop through each cell in range and test cell contents
For Each cell In Rng.Cells
If cell.Value2 = ContainWord1 Then cell.EntireRow.Delete
Next
For Each cell In Rng.Cells
If cell.Value2 = ContainWord2 Then cell.EntireRow.Delete
Next
For Each cell In Rng.Cells
If cell.Value2 = ContainWord3 Then cell.EntireRow.Delete
Next cell
End Sub
Assist me with a VBA to color column from A:G, by searching a specific text, say 'UK'in Column A
Try this. Code1 works on every sheet in the workbook but if you like for this to work for the active sheet then try Code2. For Code2 remember to write the correct sheets name. Hope it helps.
Here you can choose an index color: https://stackoverflow.com/a/25000926/7238313
Code1:
Sub rowhighlight()
Dim sht As Worksheet
Dim nlast As Long
For Each sht In ActiveWorkbook.Worksheets
sht.Select
nlast = Cells(Rows.Count, "A").End(xlUp).Row
For n = nlast To 2 Step -1
If sht.Cells(n, "A").Value = "UK" Then
sht.Range("A" & n, "G" & n).Interior.ColorIndex = 37
'different color number place here----------------^
End If
Next n
Next sht
End Sub
Code2:
Sub rowhighlight()
Dim nlast As Long
Sheets("sheetname").Activate
Set sht = ActiveWorkbook.ActiveSheet
nlast = Cells(Rows.Count, "A").End(xlUp).Row
For n = nlast To 2 Step -1
If sht.Cells(n, "A").Value = "UK" Then
sht.Range("A" & n, "G" & n).Interior.ColorIndex = 37
'different color number place here----------------^
End If
Next n
End Sub
a very short and dirty and rude code is the following:
Sub ColorColumns()
On Error Resume Next
Range("A1", Cells(Rows.Count, 1).End(xlUp)).Find(what:=Application.InputBox("Text to search:", , , , , , , 2), LookIn:=xlValues, lookat:=xlWhole).Resize(, 7).Interior.ColorIndex = 6
End Sub
You can use the following code. Remember to keep the sheet containing the table active when running the code. Alternatively, you can specify the sheet explicitly when setting the ws variable.
Sub SelectivelyColorARowRed()
Dim ws As Worksheet
Set ws = ActiveSheet
lng_lastrow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim k As Long
For k = 2 To lng_lastrow
If Trim(ws.Cells(k, 1).Value) = "UK" Then
'you can also apply UCase if you want the search to be case-insensitive
'like: If UCase(Trim(ws.Cells(k, 1).Value)) = UCase("Uk") Then
ws.Range(Cells(k, 1), Cells(k, 7)).Interior.ColorIndex = 22
End If
Next k
End Sub
The point of this code is to take user inputs from a "Remove Flags" tab in which the user puts an item number and what program it belongs to, filters the "Master List" tab by the item number and the program, then match the name of the flag to the column and delete the flag. However the offset is not working. It is instead deleting the header. When I step through it everything works fine until the line I marked with '*******.
I am fairly new to VBA and am self taught so any and all help is greatly appreciated. Thank you very much for your time.
EDIT: Removed "On Error Resume Next" and fixed some spelling errors. Current issue is with rng not having >1 rows when it is filtered and definitely has two rows (one row is the header, one row is the returned data.)
Sub RemoveFlag()
Dim cel As Range
Dim rg As Range
Dim d As Double
Dim i As Integer
Dim m As Integer
Dim n As Integer
Dim rng As Range
Dim wsMaster As Worksheet
Dim wsFlag As Worksheet
Set wsMaster = Worksheets("Master List")
Set wsFlag = Worksheets("Remove Flags")
i = 6
'If there is no data. Do nothing.
If wsFlag.Range("C6") = "" Then
wsFlag.Activate
Else
Application.ScreenUpdating = False
'Add Leading zeroes
wsFlag.Activate
Set rg = Range("C6")
Set rg = Range(rg, rg.Worksheet.Cells(Rows.Count, rg.Column).End(xlUp))
rg.NumberFormat = "#"
For Each cel In rg.Cells
If IsNumeric(cel.Value) Then
d = Val(cel.Value)
cel.Value = Format(d, "000000000000000000") 'Eighteen digit number
End If
Next
'Clear all the filters on the Master List tab.
wsMaster.Activate
If wsMaster.AutoFilterMode = True Then
wsMaster.AutoFilterMode = False
End If
'Loop through all lines of data
Do While wsFlag.Cells(i, 3).Value <> ""
'Filter by the SKU number
wsMaster.Range("A1").AutoFilter Field:=4, Criteria1:=wsFlag.Cells(i, 3).Value
'Filter by the Program
wsMaster.Range("A1").AutoFilter Field:=2, Criteria1:=wsFlag.Cells(i, 2).Value
'If the filter is not empty find the column of the flag
Set rng = wsMaster.UsedRange.SpecialCells(xlCellTypeVisible)
If (rng.Rows.Count > 1) Then
wsMaster.Range("A1:Z1").Find(wsFlag.Cells(i, 4), LookIn:=xlValues).Activate
n = ActiveCell.Column
Sheets("Master List").Range.Offset(1, 0).SpecialCells(xlCellTypeVisible).Select
m = ActiveCell.Row
Cells(m, n) = ""
wsFlag.Activate
wsFlag.Range(Cells(i, 2), Cells(i, 4)).ClearContents
Else
wsFlag.Activate
wsFlag.Range(Cells(i, 2), Cells(i, 4)).Copy
wsFlag.Range("F4").End(xlDown).Offset(1, 0).Activate
ActiveCell.PasteSpecial Paste:=xlPasteValues
wsFlag.Range(Cells(i, 2), Cells(i, 4)).ClearContents
End If
wsMaster.Activate
wsMaster.AutoFilterMode = False
i = i + 1
Loop
'Make sure the entire Master List tab is not highlighted and pull the 'highlighted cell' to A1 in both tabs.
wsMaster.Activate
wsMaster.Range("A1").Activate
wsFlag.Activate
Range("A1").Activate
'Unfreeze the screen
Application.ScreenUpdating = True
End If
End Sub
As #Zerk suggested, first set two Worksheet variables at top of code:
Dim wsMaster As Worksheet
Dim wsRemoveFlags As Worksheet
Set wsMaster = Worksheets("Master List")
Set wsRemoveFlags = Worksheets("Remove Flags")
Then replace all other instances of Worksheets("Master List") with wsMaster and Worksheets("Remove Flags") with wsRemoveFlags.
Sometimes it's easier to just loop through your rows and columns. Something like the following:
Replace everything between:
Do While wsFlag.Cells(i, 3).Value <> ""
...
Loop
with:
Do While wsFlag.Cells(i, 3).Value <> ""
Dim r As Long ' Rows
Dim c As Long ' Columns
Dim lastRow As Long
Dim found As Boolean
lastRow = wsMaster.Cells.SpecialCells(xlLastCell).Row
found = False
For r = 2 To lastRow ' Skipping Header Row
' Find Matching Program/SKU
If wsMaster.Cells(r, 2).Value = wsFlag.Cells(i, 2).Value _
And wsMaster.Cells(r, 3) = wsFlag.Cells(i, 3).Value Then
' Find Flag in Row
For c = 1 To 26 ' Columns A to Z
If wsMaster.Cells(r, c) = wsFlag.Cells(i, 4) Then
' Found Flag
wsMaster.Cells(r, c) = ""
found = True
Exit For ' if flag can be in more than one column, remove this.
End If
Next 'c
End If
Next 'r
If Not found Then
' Here is where you need to put code if Flag wsFlag.Cells(i, 4) not found.
End If
Loop