VBA Script to Fill Cell into List Below and Repeat - vba

I have a spreadsheet that list a Case Manager and then list the students below it. Then it lists another Case Manager and students below it. I want to copy the Case Manager Name from the top of each list to the end of the row of respective students underneath, repeating with each Case Manager until I get to the end of my sheet. The number of Case Managers and students can vary.
I have the following code to do the first Case Manager but not sure how to loop it of if there is a better solution. I want all the data to stay in the original spot.
Original Source: (Imported Text File)
Modified Source: (After Macro is Run)
Sub CMWizard()
Dim CMName As String
Dim StopRow As Long
Dim r As Long
CMName = Range("A1").Value 'Get the Case Manager Name.
StopRow = Range("B2").End(xlDown).Row 'Get first blank cell in Column B.
For r = 2 To StopRow 'Start at Row 2 and continue until you reach the StopRow.
Cells(r, 6).Value = CMName 'Set every cell from Row 2 in Column F (6) to the Case Manager Name.
End Sub

Let's say your Excel file looks like this
Paste this code in a module. I have commented the code so that you will not have a problem understanding it.
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim i As Long, LRow As Long, R As Long
Dim CM As String
Dim delRng As Range
Application.ScreenUpdating = False
'~~> Replace Sheet 1 with the relevant sheet name
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
'~~> Get last row of Col A
LRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Loop through cells in Col A
For i = 1 To LRow
'~~> Check if the cell contains "Case Manager"
If InStr(1, .Cells(i, 1).Value, "Case Manager", vbTextCompare) Then
'~~> Store the Case manager's name in a variable
CM = .Cells(i, 1).Value
'~~> Store the row numbers which have "Case Manager"
'~~> We will delete it later
If delRng Is Nothing Then
Set delRng = .Rows(i)
Else
Set delRng = Union(delRng, .Rows(i))
End If
Else
'~~> Store the Case manager in Col F
.Cells(i, 6).Value = CM
End If
Next i
End With
'~~> Delete the rows which have "Case Manager"
If Not delRng Is Nothing Then delRng.Delete
Application.ScreenUpdating = True
End Sub
Output

i think you are just missing an next
Sub CMWizard()
Dim CMName As String
Dim StopRow As Long
Dim r As Long
CMName = Range("A1").Value 'Get the Case Manager Name.
StopRow = Range("B2").End(xlDown).Row 'Get first blank cell in Column B.
For r = 2 To StopRow 'Start at Row 2 and continue until you reach the StopRow.
Cells(r, 6).Value = CMName 'Set every cell from Row 2 in Column F (6) to the Case Manager Name.
Next
End Sub
just be aware that StopRow = Range("B2").End(xlDown).Row will return last row in worksheet if there are just empty cells below ("B2")
Hope it helps

Related

copy lane from different sheet if the same value

I have 5 columns in sheet1, and the same in sheet 2.The name of the product is in A. But sometimes the caracteristics of the products (in B,C,D,E) can change in sheet 2. I want that it actualize the caracteristics in Sheet1.
I tried a Vlookup, but it works only zith one Cell
Sub test()
With Sheets("Feuil1")
.Range("B1").Value = WorksheetFunction.VLookup(.Range("A1").Value, Sheets("Feuil2").Range("A1:B100"), 2, False)
End With
End Sub
Moreover, I cant copy all the line because the colomn F should not changeā€¦ And products in sheet1 in column A are not tidy and get some duplicates...
You need a loop for this to update each row and you need to update each column as well.
I recommend to use WorksheetFunction.Match instead so you only need to match once per row to get the row number and then you can copy the desired values of that row.
Option Explicit
Public Sub UpdateData()
Dim WsDest As Worksheet 'destination workbook to write in
Set WsDest = ThisWorkbook.Worksheets("Feuil1")
Dim WsSrc As Worksheet 'source workbook to match with
Set WsSrc = ThisWorkbook.Worksheets("Feuil2")
Dim LastRow As Long 'last used row in workbook
LastRow = WsDest.Cells(WsDest.Rows.Count, "A").End(xlUp).Row
Dim iRow As Long, MatchedRow As Long
For iRow = 1 To LastRow 'loop through all rows from row 1 to last used row and update each row
MatchedRow = 0 'initialize
On Error Resume Next 'if no match found then ignore error
MatchedRow = WorksheetFunction.Match(WsDest.Cells(iRow, "A"), WsSrc.Columns("A"), 0) 'get the row number of the match
On Error GoTo 0 'reactivate error reporting
'if it didn't match then MatchedRow is still 0
If MatchedRow > 0 Then 'if a match was found then copy values
WsDest.Cells(iRow, "B").Value = WsSrc.Cells(MatchedRow, "B").Value
WsDest.Cells(iRow, "C").Value = WsSrc.Cells(MatchedRow, "C").Value
WsDest.Cells(iRow, "D").Value = WsSrc.Cells(MatchedRow, "D").Value
WsDest.Cells(iRow, "E").Value = WsSrc.Cells(MatchedRow, "E").Value
Else
'didn't find a match
'you can remove the Else part if you want to do nothing here
End If
Next iRow
End Sub
If the columns you want to copy are continous like B, C, D, E you can do it in one copy action which is faster than 4 copy actions (1 for each column):
WsDest.Range("B" & iRow & ":E" & iRow).Value = WsSrc.Range("B" & MatchedRow & ":E" & MatchedRow).Value

VBA - Manipulate Specific Sheet Data With Macro - Not Activesheet

I have 10 sheets in a workbook - These sheets were imported from individual workbooks - These workbooks were extracts from different monitoring tools
I need to apply a filter across all 10 worksheets, however, not all the sheets are in the same format/structure.
With 6 of the worksheets, the column headers are the same and in the same order.
The remaining 4 sheets have different headers. For example: The filter needs to look for a header name Status - This works for the 6 sheets that have the same structure, however, the other 4 sheets have the following:
wsheet1:
User Status instead of Status - I need to change the header to Status
wsheet2:
Current_Status instead of Status - I need to change the header to Status
Below is sample code that is supposed to manipulate the specified sheet in in order to have it "look" the same as the others, however, I am having some really annoying issues where the code isn't applied to the sheet specified and is instead applied to the "Activesheet" when the macro is executed.
Here is the code I have:
Sub arrangeSheets()
Dim lastCol As Long, idCount As Long, nameCount As Long, headerRow As Long
Dim worksh As Integer, WS_Count As Integer, i As Integer, count As Integer
Dim rng As Range, cel As Range, rngData As Range
Dim worksheetexists As Boolean
worksh = Application.Sheets.count
worksheetexists = False
headerRow = 1 'row number with headers
lastCol = Cells(headerRow, Columns.count).End(xlToLeft).Column 'last column in header row
idCount = 1
nameCount = 1
' Set WS_Count equal to the number of worksheets in the active
' workbook.
WS_Count = ActiveWorkbook.Worksheets.count
'If Application.Match finds no match it will throw an error so we need to skip them
On Error Resume Next
For x = 1 To worksh
If Worksheets(x).Name = "wsheet1" Then
worksheetexists = True
Set rng = Sheets("wsheet1").Range(Cells(headerRow, 1), Cells(headerRow, lastCol)) 'header range
With Worksheets("wsheet1").Name
Rows(2).Delete
Rows(1).Delete
count = Application.Match("*USER STATUS*", Worksheets("wsheet1").Range("A1:AZ1"), 0)
If Not IsError(count) Then
For Each cel In rng 'loop through each cell in header
If cel = "*USER STATUS*" Then 'check if header is "Unit ID"
cel = "STATUS" & idCount 'rename "Unit ID" using idCount
idCount = idCount + 1 'increment idCount
End If
Next cel
End If
End With
Exit For
End If
Next x
End Sub
Consider using ., in the With-End with section to refer to the Worksheet mentioned:
The Like in If cel Like "*USER STATUS*" works with the *, thus will be evaluated to True for 12USER STATUS12 or anything similar.
The count variable should be declared as variant, thus it can keep "errors" in itself.
This is how the code could look like:
With Worksheets("wsheet1")
.Rows(2).Delete
.Rows(1).Delete
Count = Application.Match("*USER STATUS*", .Range("A1:AZ1"), 0)
If Not IsError(Count) Then
For Each cel In Rng 'loop through each cell in header
If cel Like "*USER STATUS*" Then 'check if header is "Unit ID"
cel = "STATUS" & idCount 'rename "Unit ID" using idCount
idCount = idCount + 1 'increment idCount
End If
Next cel
End If
End With
If you want the same headers across all sheets in the workbook you could just copy the headers from the first sheet and paste them on each sheet.
This wouldn't work if your column order is different across sheets, but from the example you gave it's just renaming columns rather than re-ordering?
Sub CorrectHeaders()
Dim cpyRng As Range
With ThisWorkbook
If .Worksheets.count > 1 Then
With .Worksheets(1)
Set cpyRng = .Range(.Cells(1, 1), .Cells(1, .Columns.count).End(xlToLeft))
End With
.Sheets.FillAcrossSheets cpyRng
End If
End With
End Sub
If the column headers are in different orders, but you just want to replace any cell that contains the text "Status" with just "Status" then you could use Replace. You may want to add an extra condition of MatchCase:=True.
Sub Correct_Status()
Dim wrkSht As Worksheet
For Each wrkSht In ThisWorkbook.Worksheets
wrkSht.Cells(1, 1).EntireRow.Replace What:="*Status*", Replacement:="Status", LookAt:=xlWhole
Next wrkSht
End Sub
I have additional solution which has also helped with this issue. Code below:
Sub ManipulateSheets()
Dim worksh As Integer
Dim worksheetexists As Boolean
worksh = Application.Sheets.count
worksheetexists = False
'If Application.Match finds no match it will throw an error so we need to skip them
On Error Resume Next
Worksheets("wSheet1").Activate
With Worksheets("wSheet1")
.Rows(2).Delete
.Rows(1).Delete
End With
Worksheets("wSheet2").Activate
With Worksheets("wSheet2")
.Rows(2).Delete
End With
End Sub

Fastest way to return multiple match values in Excel

I'm trying to see if there's a macro that can speed up a multiple match formula I'm using in a file.
The formula is:
=IFERROR(INDEX(Data!$D:$D,SMALL(IF('Department 1'!$A$1=Data!$B:$B,ROW(Data!$B:$B)-MIN(ROW(Data!$B:$B))+1,""), ROW(Data!A1))),"Enter New Client Name")
In a workbook, There's three worksheets: Data, Department 1, and Department 2.
In the "Data" worksheet, Column B has a list of all the departments (i.e. Department 1 and Department 2) and Column C has a list of Clients that belong to each department.
The Department 1 and Department 2 worksheets have the exact match formula that's looking up the list of clients based on its department name.
This formula is runs pretty slow even if I'm just looking up 10 clients so I'm wondering if it's possible to speed it up using a macro?
I checked this website and found something that was able to look up 40,000 entries instantly (see below), but it's only running the macro on one worksheet. The real workbook I'm working in has over 30 different departments and I need the formula to run on all 30 worksheets so that the list of clients is unique to the department.
I apologize in advance if the instructions are not as clear, I was hoping I could upload a sample file, but since I'm new here I didn't see an option to upload. Any help is greatly appreciated!
Private Sub Worksheet_Change(ByVal Target As Range)
Dim wb As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim vLoookupVal As Variant
Dim vValues As Variant
Dim aResults() As Variant
Dim lResultCount As Long
Dim i As Long
Dim lIndex As Long
Set wb = ActiveWorkbook
Set ws1 = Me 'This is the sheet that contains the lookup value
Set ws2 = wb.Sheets("Sheet2") 'This is the sheet that contains the table of values
Application.EnableEvents = False
If Not Intersect(Target, ws1.Range("A1")) Is Nothing Then
ws1.Columns("B").ClearContents 'Clear previous results
vLoookupVal = Intersect(Target, ws1.Range("A1")).Value
lResultCount = WorksheetFunction.CountIf(ws2.Columns("A"), Target.Value)
If lResultCount = 0 Then
MsgBox "No matches found for [" & vLoookupVal & "]", , "No Matches"
Else
ReDim aResults(1 To lResultCount, 1 To 1)
lIndex = 0
vValues = ws2.Range("A1:B" & ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row).Value
For i = LBound(vValues, 1) To UBound(vValues, 1)
If vValues(i, 1) = vLoookupVal Then
lIndex = lIndex + 1
aResults(lIndex, 1) = vValues(i, 2)
End If
Next i
ws1.Range("B1").Resize(lResultCount).Value = aResults
End If
End If
Application.EnableEvents = True
End Sub
If I understand you correctly, you want to allocate Client names to the Department sheets which they belong to.
Below code will add the department sheets if they do not exist so you don't have to worry about adding department sheets.
Assuming your department names are in Sheet "Data" Column B, Client Names are in Sheet "Data" Column C, and they both have a header (your data start from 2nd row), and all input data to be inserted into Column A of Department sheets:
Sub MyClients()
Dim lastrow As Long
Dim wsname As String
lastrow = Worksheets("Data").Cells(Worksheets("Data").Rows.Count, 2).End(xlUp).Row
Application.ScreenUpdating = False
For i = 2 To lastrow
wsname = Worksheets("Data").Cells(i, 2).Value
On Error Resume Next
Worksheets(wsname).Cells(Worksheets(wsname).Rows.Count, 1).End(xlUp).Offset(1, 0) = Worksheets("Data").Cells(i, 3).Value
If Err.Number = 9 Then
Sheets.Add(After:=Sheets(Sheets.Count)).Name = Worksheets("Data").Cells(i, 2).Value
Worksheets(wsname).Cells(Worksheets(wsname).Rows.Count, 1).End(xlUp).Offset(1, 0) = Worksheets("Data").Cells(i, 3).Value
End If
Next i
Worksheets("Data").Activate
Application.ScreenUpdating = True
End Sub

How do I loop through two columns and select rows and add to that selection of rows?

I'm fairly new to VBA. I'm currently trying to find a faster way to copy and paste information by using Macros. I'm not sure how to code this.
I have two columns I want to use with a For Each loop.
I wanted to loop through each row of these two columns and use an If function. If the first row has a value in Column B (Column B cell <> "" Or Column B cell <> 0) then, select that row (i.e. Range("A1:B1")).
After the loop, I will copy whatever is selected and paste it to a specific row.
However, I want to keep adding to that selection as it loops through each row and only if it satisfies the If condition, so I'm able to copy it all once at the end. How do I go about combining this?
A B
1 Abc 1
2 Def 2
3 Geh 3
This is how you can expand current selection:
Sub macro1()
Set selectedCells = Cells(1, 2)
Set selectedCells = Application.Union(selectedCells, Cells(2, 3))
selectedCells.Select
End Sub
I'm sure you can manage the rest of your code by yourself, it's really easy. You already mentioned everything you need: For Each cell In Range("B1:B5") and If statement
Please try the below code
Sub test()
Application.ScreenUpdating = False
Dim rng As Range, one As Variant
Dim i As Integer
'Change the sheet and range name as yours
'Finding lastrow of destination column
i = Sheets("Sheet2").Cells(Rows.Count, "A").End(xlUp).Row + 1
' getting input from user
Set rng = Application.InputBox("Please select a range of cells!", "Please select a range", Selection.Address, , , , , 8)
For Each one In rng
If one.Value <> "" Or one.Value <> 0 Then
Range(one.Offset(0, -1), one).Copy
'Change the sheet and range name as yours
Sheets("Sheet2").Activate
Range("A" & i).Select
ActiveSheet.Paste
i = i + 1
End If
Next one
Application.ScreenUpdating = True
End Sub
The above macro will prompt you for the input range to be validate and copy to sheet2 in column A.
The below code will validate and copy paste the current selected range to sheet2 column A
Sub test()
Application.ScreenUpdating = False
Dim rng As Range, one As Variant
Dim i As Integer
'Chnage the sheet and range name as yours
'Finding lastrow of destination column
i = Sheets("Sheet2").Cells(Rows.Count, "A").End(xlUp).Row + 1
' getting input from user
Set rng = Selection
For Each one In rng
If one.Value <> "" Or one.Value <> 0 Then
Range(one.Offset(0, -1), one).Copy
'Chnage the sheet and range name as yours
Sheets("Sheet2").Activate
Range("A" & i).Select
ActiveSheet.Paste
i = i + 1
End If
Next one
Application.ScreenUpdating = True
End Sub
I think you're probably going about this the wrong way. Do you already know to where you would like to copy all the data in the end? It sounds like it, as you refer to copying it "to a specific row". If so, you'd be better off using your macro to copy the data from Columns A:B on the fly.
So, for example:
Sub CopyData()
Const SOURCE_COLUMN1 As Long = 1 ' A
Const SOURCE_COLUMN2 As Long = 2 ' B
Const TARGET_COLUMN1 As Long = 5 ' E
Const TARGET_COLUMN2 As Long = 6 ' F
Dim lngSourceRow As Long
Dim lngTargetRow As Long
With ThisWorkbook.Sheets("Sheet1")
lngSourceRow = 1
lngTargetRow = 0 ' Change this to the row above the one you want to copy to;
Do While .Cells(lngSourceRow, SOURCE_COLUMN1) <> ""
If .Cells(lngSourceRow, SOURCE_COLUMN2) <> "" Then
lngTargetRow = lngTargetRow + 1
.Cells(lngTargetRow, TARGET_COLUMN1) = .Cells(lngSourceRow, SOURCE_COLUMN1)
.Cells(lngTargetRow, TARGET_COLUMN2) = .Cells(lngSourceRow, SOURCE_COLUMN2)
End If
lngSourceRow = lngSourceRow + 1
Loop
End With
End Sub

For loop doesn't run in worksheet

I tried to link the common columns together but when I click a cell in PolicyComponents Sheet, the for loop doesn't run - it just exits the sub.
Code Snippet:
Sub LinkName()
Dim i As Long
Dim ShtUsedRange, ShtUsedRangeCol
Dim name As String
Dim name1 As String
Dim lookup_range As Range
Dim box
ShtUsedRange = ActiveSheet.UsedRange.Rows.Count
'Count the used rows in the Activesheet
ShtUsedRangeCol = ActiveSheet.UsedRange.Columns.Count
'Count the used Column in the Activesheet
name = ActiveCell.Row
'Row of the Selected Cell
name1 = ActiveSheet.Cells(name, 1).Value
'name of the row selected
'MsgBox name1
Set lookup_range = ThisWorkbook.Sheets("PolicyDetails").Range("a1:z5000")
'set the range of the Policy details to search from
box = Application.WorksheetFunction.VLookup(name1, lookup_range, 1, False)
'to match the name to the policy details
MsgBox box
For i = 1 To ThisWorkbook.Sheets("PolicyComponents").Rows.Count Step -1
If ThisWorkbook.Sheets("PolicyComponents").Cells(i, 1).Value = box Then
ThisWorkbook.Sheets("Policy Viewer").Cells(16, 2).Value = ThisWorkbook.Sheets("PolicyComponents").Cells(i, 4).Value
End If
Next i
End Sub
You are using name as a string type variable but assigning it the row number value. This means that name is "2" and not 2 and cannot be used when a number is required. It is also never a good idea to call your variables the same as reserved words like VBA's .Name.
You are using Step -1 but starting at 1 which means it will never go anywhere.
That should be enough to get the loop going.
Sub LinkName()
Dim i As Long
Dim ShtUsedRange, ShtUsedRangeCol
Dim rw As Long
Dim lu As Variant
Dim lookup_range As Range
Dim box As Variant
'Count the used rows in the Activesheet
ShtUsedRange = ActiveSheet.UsedRange.Rows.Count
'Count the used Column in the Activesheet
ShtUsedRangeCol = ActiveSheet.UsedRange.Columns.Count
'Row of the Selected Cell
rw = ActiveCell.Row
'name of the row selected
lu = ActiveSheet.Cells(rw, 1).Value
'MsgBox lu
'set the range of the Policy details to search from
Set lookup_range = ThisWorkbook.Sheets("PolicyDetails").Range("a1:z5000")
'there is no error control here if there is no match
'to match the name to the policy details
box = Application.WorksheetFunction.VLookup(lu, lookup_range, 1, False)
MsgBox box
For i = 1 To ThisWorkbook.Sheets("PolicyComponents").Rows.Count Step 1
If ThisWorkbook.Sheets("PolicyComponents").Cells(i, 1).Value = box Then
ThisWorkbook.Sheets("Policy Viewer").Cells(16, 2) = _
ThisWorkbook.Sheets("PolicyComponents").Cells(i, 4).Value
'probably best to exit hte loop here unless you want to try and catch other matches
'Exit For
End If
Next i
End Sub
I renamed two of your variables. I didn't know the nature of the value (number/text/date) you were actually trying to look up so I left it as a variant.
You loop is going from 1 to the row count, but using i with a step of -1 which means you are counting backwards, never getting to ...Rows.Count.
Change the order of your loop, going from Rows.Count to 1 if you want to use a step like that or use Step 1 to count up by one (the default).