I have a pretty large excel file that houses a list of employees, a few columns of paycheck data, then a fiscal week assigned to when that data was collected.
I am trying to search though this data and match an employee with a specific fiscal week in a macro. I have a solution that finds the name, but wont print out the fiscal week and it is very slow and I'm sure that there are much better ways of doing this simple task. Below is what I have, it's pretty simple and in the end I will need to capture the data in the rows but for now I am just printing to have proof of concept.
Sub loop_test()
Dim ClientTable As Range
Dim rng1 As Range, rng2 As Range, desired_emp As String, desired_fw As Integer
desired_emp = Application.InputBox("Select an Employee", Type:=8)
desired_fw = Application.InputBox("What FW would you like to do this for?", Type:=8)
Set FullName = Sheets("Query5").Range("A:A")
Set FiscalWeek = Sheets("Query5").Range("F:F")
For Each rng1 In FullName.Columns(1).Cells
If rng1.Value = desired_emp Then
matched_name = rng1.Cells.Value
For Each rng2 In FullName.Columns(1).Cells
If rng2.Value = desired_fw Then
matched_fw = rng2.Cells.Value
End If
Next
End If
Next
Range("i3").Value = matched_name
Range("j3").Value = matched_fw
End Sub
I set up an example range with names and fiscal weeks in columns A and B. Modify the code below to match the columns and range in your workbook, and set the target sheet to the appropriate place.
This code autofilters your range based on user inputs and copies the results to another sheet if there is a match:
Sub Autofilter_test()
Dim clientTable As Range
Dim desired_emp As String
Dim desired_fw As Integer
Dim MatchRange As Range
Dim tgt As Worksheet
Set clientTable = Range("A1:B8")
Set tgt = ThisWorkbook.Sheets("Sheet2")
ActiveSheet.AutoFilterMode = False
desired_emp = Application.InputBox("Select an Employee")
desired_fw = Application.InputBox("What FW would you like to do this for?")
With clientTable
.AutoFilter Field:=1, Criteria1:=desired_emp
.AutoFilter Field:=2, Criteria1:=desired_fw
End With
Call CopyFilteredData(tgt)
End Sub
Sub CopyFilteredData(tgt As Worksheet)
' by Tom Ogilvy source: http://www.contextures.com/xlautofilter03.html
Dim rng As Range
Dim rng2 As Range
With ActiveSheet.AutoFilter.Range
On Error Resume Next
Set rng2 = .Offset(1, 0).Resize(.Rows.Count - 1, 1) _
.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
End With
If rng2 Is Nothing Then
MsgBox "No data to copy"
Else
tgt.Cells.Clear
Set rng = ActiveSheet.AutoFilter.Range
rng.Offset(1, 0).Resize(rng.Rows.Count - 1).Copy _
Destination:=tgt.Range("A1")
End If
ActiveSheet.ShowAllData
End Sub
Related
Completely new to VBA. I basically copied the code below and I am repurposing it.. the code essentially selects a row based on whether a certain cell has a certain value. eg. if K5 is "yes" then select the row "K5" copy and paste into a new worksheet.
I am trying to do something slightly different. I want to select certain cells as opposed to the whole entire row - How do I do this
For example, If K5 is "yes", then select A5:D5 & K5 & I5??
Currently the below code below copys the whole "k5" row and pastes it in sheet 2 if there a "y" that appears in the cell "k5"..
Private Sub CommandButton1_Click()
'Declare variables
Dim sht1 As Worksheet
Dim sht2 As Worksheet
Dim sht3 As Worksheet
Dim lastRow1 As Long, lastRow2 As Long, lastRow3 As Long
Dim Cell As Range
Dim RngToDelete As Range
Application.ScreenUpdating = False
'Set variables
Set sht1 = Sheets("To DO")
Set sht2 = Sheets("Ongoing")
Set sht3 = Sheets("Done")
'Select Entire Row
'Selection.EntireRow.Select
'Move row to destination sheet & Delete source row
lastRow1 = sht1.Range("A" & sht1.Rows.Count).End(xlUp).Row
lastRow2 = sht2.Range("A" & sht2.Rows.Count).End(xlUp).Row
lastRow3 = sht3.Range("A" & sht3.Rows.Count).End(xlUp).Row
With sht2
' loop column H untill last cell with value (not entire column)
For Each Cell In .Range("H2:H" & .Cells(.Rows.Count, "H").End(xlUp).Row)
If Cell.Value = "Not started" Then
If RngToDelete Is Nothing Then
Set RngToDelete = Cell
Else
Set RngToDelete = Union(RngToDelete, Cell)
End If
lastRow1 = sht1.Range("A" & sht1.Rows.Count).End(xlUp).Row
' Copy>>Paste in 1-line (no need to use Select)
.Rows(Cell.Row).Copy Destination:=sht1.Rows(lastRow1 + 1)
'.Rows(Cell.Row).Delete
ElseIf Cell.Value = "Closed" Then
If RngToDelete Is Nothing Then
Set RngToDelete = Cell
Else
Set RngToDelete = Union(RngToDelete, Cell)
End If
lastRow3 = sht3.Range("A" & sht3.Rows.Count).End(xlUp).Row
' Copy>>Paste in 1-line (no need to use Select)
.Rows(Cell.Row).Copy Destination:=sht3.Rows(lastRow3 + 1)
'.Rows(Cell.Row).Delete
End If
Next Cell
End With
If Not RngToDelete Is Nothing Then RngToDelete.EntireRow.Delete
Application.CutCopyMode = 0
Application.ScreenUpdating = True
MsgBox "Update Done!"
End Sub
I tried to implement the below (ignore the actual cells being copied, the concept of multiple cells instead of the entire row is what im after - sourced from Select multiple ranges with VBA), which seems to work if I use it on its own, but im not able or sure where to implement it in the code above to do what I want it to do.
set rng = Union(.Range("A84:B" & LastRow),.Range("D84:E" & LastRow),.Range("H84:J" & LastRow))
Thanks for your time
Here's one way to do it:
Private Sub CommandButton1_Click()
Dim sht1 As Worksheet, sht2 As Worksheet, sht3 As Worksheet
Dim Cell As Range, e, rngDest As Range
Dim RngToDelete As Range, wsDest As Worksheet
Application.ScreenUpdating = False
Set sht1 = Sheets("To DO")
Set sht2 = Sheets("Ongoing")
Set sht3 = Sheets("Done")
For Each Cell In sht2.Range("H2:H" & _
sht2.Cells(sht2.Rows.Count, "H").End(xlUp).Row).Cells
Select Case Cell.Value 'check the row...
Case "Not started": Set wsDest = sht1
Case "Closed": Set wsDest = sht3
Case Else: Set wsDest = Nothing
End Select
If Not wsDest Is Nothing Then 'any row to copy?
BuildRange RngToDelete, Cell 'build up the delete range
Set rngDest = wsDest.Cells(Rows.Count, "A").End(xlUp).Offset(1)
For Each e In Array("A1:D1", "K1", "I1") 'array of cells/ranges to copy, in order
With Cell.EntireRow.Range(e) '#note Range() is *relative* to EntireRow
.Copy rngDest 'copy this cell/area
Set rngDest = rngDest.Offset(0, .Columns.Count) 'next paste destination
End With
Next e
End If
Next Cell
If Not RngToDelete Is Nothing Then RngToDelete.EntireRow.Delete
Application.CutCopyMode = 0
Application.ScreenUpdating = True
MsgBox "Update Done!"
End Sub
'utility sub for building up a range
Sub BuildRange(ByRef rngTot As Range, rngAdd As Range)
If rngTot Is Nothing Then
Set rngTot = rngAdd
Else
Set rngTot = Application.Union(rngTot, rngAdd)
End If
End Sub
I would like to compare 2 columns in the same worksheet, search for non-matching values in column A when compared to column D and copy the entire rows of these non-matching values in column A to another worksheet.
Here is a sample of the worksheet:
Therefore, I would like to compare column A with column D, find the values which do not match and copy the entire corresponding rows from Columns A and B to a new worksheet.
*Edit, I forgot to include my code
Dim CopyToRow As Integer
Dim rng1 As Range
Dim rng2 As Range
Dim cell As Range
Dim found As Range
'Start copying data to row 2 in Sheet2 (row counter variable)
CopyToRow = 2
Set rng1 = Range(ActiveSheet.Cells(2, 1), ActiveSheet.Cells(2, 1).End(xlDown))
Set rng2 = Range(ActiveSheet.Cells(4, 2), ActiveSheet.Cells(4, 2).End(xlDown))
For Each cell In rng1
Set found = rng2.Find(what:=cell, LookIn:=xlValues, lookat:=xlWhole, MatchCase:=False)
If Not found Is Nothing Then
cell.EntireRow.Copy Destination:=Sheets("Sheet2").Range("A" & CopyToRow)
CopyToRow = CopyToRow + 1
End If
Next cell
Many thanks and much appreciated!
I agree with Ron Rosenfeld that you should have demonstrated your own attempt. That being said, perhaps this will be of some help to you. Not the most elegant but should work provided you update references to your own sheet names.
Sub SOPractice()
Dim SearchCell As Range 'each value being checked
Dim SearchRng As Range 'column A
Dim LastRow As Long
Dim MatchFound As Range
Dim i As Long: i = 1
LastRow = YourSheet.Range("A" & Rows.Count).End(xlUp).Row
With YourSheet
Set SearchRng = .Range(.Cells(2, 1), .Cells(LastRow, 1))
Application.ScreenUpdating = False
For Each SearchCell In SearchRng
Set MatchFound = .Range("D:D").Find _
(What:=SearchCell.Value, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False)
If MatchFound Is Nothing Then 'No match hence copy to other sheet
.Range(SearchCell.Address, SearchCell.Offset(, 1)).Copy
YourCopyToSheet.Cells(i, 1).PasteSpecial xlPasteAll
i = i + 1
End If
Next SearchCell
End With
Application.ScreenUpdating = True
Application.CutCopyMode = False
End Sub
I have also found a solution, using a Dictionary object:
Dim Cl As Range, Rng As Range, Dic As Object
Set Dic = CreateObject("scripting.dictionary")
With Dic
For Each Cl In MyWorksheet1Name.Range("D2", MyWorksheet1Name.Range("D" & Rows.Count).End(xlUp))
.Item(Cl.Value) = Empty
Next Cl
For Each Cl In MyWorksheet1Name.Range("A2", MyWorksheet1Name.Range("A" & Rows.Count).End(xlUp))
If Not .Exists(Cl.Value) Then
If Rng Is Nothing Then Set Rng = Cl Else Set Rng = Union(Rng, Cl)
End If
Next Cl
End With
If Not Rng Is Nothing Then
Rng.EntireRow.Copy MyWorksheet2Name.Range("A" & Rows.Count).End(xlUp)
End If
Cheers!
I am new to VBA... I am trying delete all columns from Sheet1:"Template" ROW1/headers file that doesn't match any of the cell values on varList:"ColumnsList" (that is in Sheet3).
How do I select the headers or how do I select the row 1 range to search into?
Also, I have a runtime error 5 in this line: invalid procedure call or argument.
If Intersect(rng.Cells(1, i).EntireColumn, rngF) Is Nothing Then
Any kind soul that help me with that please?
Also, I need to do the same but with rows from Sheet1:"Template". I need to delete any row that doesn't CONTAIN any cell value from varList:"Agents" (that is in Sheet2).
Could you please help me out?
Maaaany thanks in advance!!!
Option Compare Text
Sub ModifyTICBData()
Dim varList As Variant
Dim lngarrCounter As Long
Dim rngFound As Range, rngToDelete As Range
Dim strFirstAddress As String
'Application.ScreenUpdating = False
varList = VBA.Array("ColumnsList") 'I want to keep columns with these values, NOT DELETE THEM
For lngarrCounter = LBound(varList) To UBound(varList)
With Sheets("Template").UsedRange
Set rngFound = .Find( _
What:=varList(lngarrCounter), _
Lookat:=xlWhole, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, _
MatchCase:=True)
If Not rngFound Is Nothing Then
strFirstAddress = rngFound.Address
If rngToDelete Is Nothing Then
Set rngToDelete = rngFound
Else
If Application.Intersect(rngToDelete, rngFound.EntireColumn) Is Nothing Then
Set rngToDelete = Application.Union(rngToDelete, rngFound)
End If
End If
Set rngFound = .FindNext(After:=rngFound)
Do Until rngFound.Address = strFirstAddress
If Application.Intersect(rngToDelete, rngFound.EntireColumn) Is Nothing Then
Set rngToDelete = Application.Union(rngToDelete, rngFound)
End If
Set rngFound = .FindNext(After:=rngFound)
Loop
End If
End With
Next lngarrCounter
Dim rngDel As Range
Set rngDel = NotIntersectRng(Sheets("Template").UsedRange, rngToDelete)
If Not rngDel Is Nothing Then rngDel.EntireColumn.delete
'Application.ScreenUpdating = True
End Sub
Private Function NotIntersectRng(rng As Range, rngF As Range) As Range
Dim rngNI As Range, i As Long, j As Long
For i = 1 To rng.Columns.Count
**If Intersect(rng.Cells(1, i).EntireColumn, rngF) Is Nothing Then**
If rngNI Is Nothing Then
Set rngNI = rng.Cells(1, i)
Else
Set rngNI = Union(rngNI, rng.Cells(1, i))
End If
End If
Next i
If Not rngNI Is Nothing Then Set NotIntersectRng = rngNI
End Function
Delete Columns, Then Rows
Description
Deletes columns that in the first row do not contain values from a list. Then deletes rows that in the first column do not contain values from another list.
The Flow
Writes the values from range A2 to the last cell in Sheet3 to the Cols Array.
Writes the values from range A2 to the last cell in Sheet2 to the Agents Array.
Using CurrentRegion defines the DataSet Range (rng).
Loops through the cells (cel) in first row starting from the 2nd column and compares their values to the values from the Cols Array. If not found adds the cells to the Delete Range(rngDel).
Finally deletes the entire columns of the cells 'collected'.
Loops through the cells (cel) in first column starting from the 2nd row and compares their values to the values from the Agents Array. If not found adds the cells to the Delete Range(rngDel).
Finally deletes the entire rows of the cells 'collected'.
Informs the user of success or no action.
The Code
Option Explicit
Sub ModifyTICBData()
' Define workbook ('wb').
Dim wb As Workbook
Set wb = ThisWorkbook
' Define Columns List ('Cols').
Dim ws As Worksheet
Set ws = wb.Worksheets("Sheet3")
Dim rng As Range
Set rng = ws.Cells(ws.Rows.Count, "A").End(xlUp)
Dim Cols As Variant
Cols = ws.Range("A2", rng).Value
' Define Agents List ('Agents').
Set ws = wb.Worksheets("Sheet2")
Set rng = ws.Cells(ws.Rows.Count, "A").End(xlUp)
Dim Agents As Variant
Agents = ws.Range("A2", rng).Value
' Define DataSet Range ('rng').
Set rng = wb.Worksheets("Template").Range("A1").CurrentRegion
Application.ScreenUpdating = False
' Define Delete Range ('rngDel') for Columns.
Dim rngDel As Range
Dim cel As Range
For Each cel In rng.Rows(1).Resize(, rng.Columns.Count - 1) _
.Offset(, 1).Cells
If IsError(Application.Match(cel.Value, Cols, 0)) Then
collectCells rngDel, cel
End If
Next cel
' Delete Columns.
Dim AlreadyDeleted As Boolean
If Not rngDel Is Nothing Then
rngDel.EntireColumn.Delete
Else
AlreadyDeleted = True
End If
' Define Delete Range ('rngDel') for Agents.
Set rngDel = Nothing
For Each cel In rng.Columns("A").Resize(rng.Rows.Count - 1) _
.Offset(1).Cells
If IsError(Application.Match(cel.Value, Agents, 0)) Then
collectCells rngDel, cel
End If
Next cel
' Delete Agents (Rows).
If Not rngDel Is Nothing Then
rngDel.EntireRow.Delete
AlreadyDeleted = False
End If
Application.ScreenUpdating = True
' Inform user
If Not AlreadyDeleted Then
MsgBox "The data was succesfully deleted.", vbInformation, "Success"
Else
MsgBox "The data had already been deleted.", vbExclamation, "No Action"
End If
End Sub
Sub collectCells(ByRef CollectRange As Range, CollectCell As Range)
If Not CollectCell Is Nothing Then
If Not CollectRange Is Nothing Then
Set CollectRange = Union(CollectRange, CollectCell)
Else
Set CollectRange = CollectCell
End If
End If
End Sub
I need a macro that need to filter a column and to take out the required date value along with the cell position (i.e say "4/22/2018" cell position "A9 or just 9"). Kindly help me out to fix this issue
See the code that I wrote below
Dim Date As String
Date = Sheets("alldata")
Rows("3:3").Select.AutoFilter.Range("$A$3:$AA$606").AutoFilter , Field:=1, Criterial:="#VALUE!"
Range("A3").Select.xlFilterValues.offset(1, 0).Copy.value
Sheets("Log").Cells(2, "AF").value = Date
Is this what you are trying?
Sub Sample()
Dim ws As Worksheet
Dim rng As Range
Set ws = Sheets("alldata")
With ws
Set rng = .Range("$A$3:$A$606")
'~~> Remove any filters
.AutoFilterMode = False
With rng
.AutoFilter Field:=1, Criteria1:="<>#VALUE!"
'~~> Get the Row Number
MsgBox .Offset(1, 0).SpecialCells(xlCellTypeVisible).Row
'~~> Get The cell Address
MsgBox .Offset(1, 0).SpecialCells(xlCellTypeVisible).Cells(1, 1).Address
'~~> Get the Date
Sheets("Log").Cells(2, "AF").Value = _
.Offset(1, 0).SpecialCells(xlCellTypeVisible).Cells(1, 1).Value
End With
'~~> Remove any filters
.AutoFilterMode = False
End With
End Sub
The following will filter the dates and for each date it will copy the value into Sheet Log in Column AF:
Sub foo()
Dim ws As Worksheet: Set ws = Sheets("alldata")
Dim wsLog As Worksheet: Set wsLog = Sheets("Log")
'declare and set your worksheet, amend as required
Dim LastRow As Long, LogLastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'get the last row with data on Column A
Dim c As Range, rng As Range
ws.Rows("3:3").AutoFilter
ws.Range("$A$3:$AA$" & LastRow).AutoFilter Field:=1, Operator:=xlFilterValues, Criteria2:=Array(0, "01/01/2018")
Set rng = ws.Range("$A$4:$A$" & LastRow).SpecialCells(xlCellTypeVisible)
For Each c In rng
LogLastRow = wsLog.Cells(wsLog.Rows.Count, "AF").End(xlUp).Row
c.Copy Destination:=wsLog.Cells(LogLastRow, "AF")
'if instead of copying the value, you want to return its address,
'you can get the address by using "c.Address" for each value in the range
Next c
End Sub
I have a workbook with 2 sheets.
Sheet1 contains a list of Product Codes in column A and Column R is Current Stock Level.
Sheet2 contains a list of Product Codes in column A and Column B contains the New Stock Level.
What I want to do is replace the Current Stock Levels in Sheet1 with the New Stock Level from Sheet2.
I found some code on this site already (below) which I have adapted slightly for my purpose and it works fine but only for one Product Code (as it references A1 and B1). What I would like to do is add a Loop so it works down all products in Sheet2 but I'm not sure how to and haven't been able to adapt any similar loops I've found online for this purpose.
Any help would be appreciated, my backup plan is to just do a v-lookup in Sheet1 to bring in the Sheet2 New Stock Level values and then replace the original column but I would like to get this other way working if possible.
Private Sub CommandButton1_Click()
Dim search_range As Range, search_value As Range, _
lastcell As Range, foundcell As Range
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
Set search_range = ws.Range("A1", ws.Range("A" & Rows.Count).End(xlUp))
Set lastcell = search_range.Cells(search_range.Cells.Count)
Set search_value = ThisWorkbook.Sheets("Sheet2").Range("A1")
Set foundcell = search_range.Find(What:=search_value, After:=lastcell,
LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not foundcell Is Nothing Then foundcell.Activate Else MsgBox "Not Found"
ActiveCell.Offset(0, 17).Value = Sheets("Sheet2").Range("B1").Value
End Sub
How about the following:
Private Sub CommandButton1_Click()
Dim search_range As Range, search_value As Range, lastcell As Range, foundcell As Range
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
Set search_range = ws.Range("A1", ws.Range("A" & Rows.Count).End(xlUp))
Set lastcell = search_range.Cells(search_range.Cells.Count)
For i = 1 To lastcell.Row
Set search_value = ThisWorkbook.Sheets("Sheet2").Range("A" & i)
Set foundcell = search_range.Find(What:=search_value, After:=lastcell, LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext)
If Not foundcell Is Nothing Then foundcell.Activate Else MsgBox "Not Found"
ActiveCell.Offset(0, 17).Value = Sheets("Sheet2").Range("B" & i).Value
Next i
End Sub
The idea is the following - you have two types of ranges - ranges where you search and ranges where your value should be. They are called Target and Search.
In the code below you loop through all cells in column A of the first worksheets and you look for their value in column A of the second worksheet. If you find the value, you write the value in column B of the second worksheet to the 17. column in the first worksheet:
Private Sub CommandButton1_Click()
Dim targetRange As Range
Dim targetValue As Range
Dim searchRange As Range
Dim lastSearchCell As Range
Dim foundCell As Range
Dim wsTarget As Worksheet
Dim wsSearch As Worksheet
Dim myCell As Range
Set wsTarget = ThisWorkbook.Worksheets(1)
Set wsSearch = ThisWorkbook.Worksheets(2)
With wsTarget
Set targetRange = .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
End With
With wsSearch
Set searchRange = .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
End With
Set lastSearchCell = searchRange.Cells(searchRange.Cells.Count)
For Each myCell In targetRange
Set foundCell = searchRange.Find(What:=myCell, After:=lastSearchCell).Offset(0, 1)
If Not foundCell Is Nothing Then
myCell.Offset(0, 17) = foundCell
Else
MsgBox "Not Found"
End If
Next myCell
End Sub