I need some help. I have two columns: A and B. Column A and Column B have the following headers "Status" and "State". A filter has been applied to select "down" from a choice of "up" and "down" in Column A. When Column A is filtered some blank cells are revealed in Column B after some cells in Column B is cleared. The amount of data in the sheet varies and the position of these blanks also vary. I will like to fill down these blank cells in Column B using the values in visible cells only (not from the values in the hidden cells). Can someone help me edit this code?
In the pic above SO will fill down from 50476 to 50492 without erasing the values in the hidden cells.
Sub Filldownvisiblecells ()
Dim ws as worksheet
Dim dl as long
Dim rg as range
ws = Workbooks("Book1.xlsm"). Worksheets("Sheet1")
dl = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'Filter Column A by Down
ws.Range("A1").AutoFilter Field:=1, Criteria1:="Down"
'Clearing States in Column B (This action generates blanks that I will like to filldown from visible cells NOT hidden cells)
ws.Range("B2:B" & dl).SpecialCells(xlCellTypeVisible).Select
For Each rg In Selection.Cells
If rg.Text = "R1" Or rg.Text = "R2" Or rg.Text = "UT" Then
rg.ClearContents
End If
Next rg
'Select Filldown Range in Column B
ws.Range("B2:B" & dl). SpecialCells(xlCellTypeVisible).Select
'Filldown Blanks in Column X
For Each rg In Selection.Cells
If rg.Value = "" Then
rg.FillDown
End If
Next rg
End Sub
Fill Down With Visible Cells' Values (AutoFilter)
Option Explicit
Sub FillDownVisible()
Const wsName As String = "Sheet1"
Const fRow As Long = 1 ' First Row
Const fCol As String = "A" ' Filter Column
Const fCriteria As String = "Down" ' Filter Criteria
Const dCol As String = "B" ' Destination Column
Dim ws As Worksheet
' The Workbook Containing This Code ('ThisWorkbook')
Set ws = ThisWorkbook.Worksheets(wsName)
' An Open Workbook
'Set ws = Workbooks("Book1.xlsm").Wordksheets(wsname)
' Possibly Closed Workbook (Needs the Full File Path)
'Set ws = Workbooks.Open("C:\Test\Book1.xlsm").Worksheets(wsName)
' Clear possible previous ('active') filter.
If ws.AutoFilterMode Then
ws.AutoFilterMode = False
End If
' Create a reference to the Filter Range ('frg').
Dim lRow As Long: lRow = ws.Cells(ws.Rows.Count, fCol).End(xlUp).Row
Dim frg As Range: Set frg = ws.Cells(fRow, fCol).Resize(lRow - fRow + 1)
' Create a reference to the Destination Data Range (no headers).
Dim ddrg As Range: Set ddrg = frg.EntireRow.Columns(dCol) _
.Resize(frg.Rows.Count - 1).Offset(1)
' Filter Filter Range.
frg.AutoFilter Field:=1, Criteria1:=fCriteria
' Create a reference to the Destination Range ('drg').
Dim drg As Range: Set drg = ddrg.SpecialCells(xlCellTypeVisible)
Dim dCell As Range ' Current Destination Cell
Dim pValue As Variant ' Previous Value
Dim cValue As Variant ' Current Value
' Loop through the cells of the Destination Range.
For Each dCell In drg.Cells
cValue = dCell.Value
Select Case UCase(CStr(cValue))
Case "R1", "R2", "UT", ""
dCell.Value = pValue
Case Else
pValue = cValue
End Select
Next dCell
ws.AutoFilterMode = False
End Sub
Related
I am trying to find out how to fill a cell on the next empty row, using a loop.
I learned how to loop through a range, and how to fill cells conditionally, for example:
Dim column As Range: Set column = Sheets(1).UsedRange.Columns(1)
For Each cell In column.Cells
If cell.Value >= 0 Then
cell.Offset(0, 1).Value = "Positive"
ElseIf cell.Value < 0 Then
cell.Offset(0, 1).Value = "Negative"
End If
Next
However, my current task is a bit more complex, and I do not know how to solve a particular issue. I have two sheets, one in each workbook. If, when looping through a column in the first workbook, I find an empty cell, then the value in the cell that is 0,1 offset to it should be copied to a column in the second workbook.
My objective is thus that the second workbook contains a tidy column, with one value after the other row by row. The first workbook remains unchanged.
The particular issue is that I can't find what the exact syntax or condition to tell Excel to fill a cell on the first empty row that it finds.
This is what I have so far:
Dim wb As Workbook: Set wb = Workbooks("QuartalReport.xlsm")
Dim ws As Worksheet: Set ws = wb.Worksheets(1)
Dim column As Range: Set column = ws.Sheets(1).UsedRange.Columns(1) 'some cells in this column are empty
Dim wb2 As Workbook: Set wb2 = Workbooks("ClientList.xlsm")
Dim ws2 As Worksheet: Set ws2 = wb2.Worksheets(1)
Dim column2 As Range: Set column = ws2.Sheets(1).Columns(3) 'this column will be filled as the macro is used each time
For Each cell In column.Cells
If cell.Value = "" Then
???
Edited for clarification:
This code will go in the first workbook ("QuartalReport.xlsm"). Both workbooks have only one sheet.
The data in the first workbook has no table formatting, and it starts in row 3.
The data in the second workbook should begin with cell C2 (or any column in row 2), as the first row will be for the header (though like in the first workbook, it is unformatted). Save for this column, the worksheet will be empty.
The objective is to copy the value in the cell in column B of the first workbook if the cell in the same row in column A is empty. For example if cells A3 through A5 in "QuartalReport.xlsm contain values, the rows should altogether be skipped. But if A6 is blank, then the value of whatever is in B6 should be copied to the next empty row (being the first case, C2) in "ClientList.xlsm". If the next empty cell is in A12, then B12 should be copied to C3. As such the column in the second workbook will have no empty rows between data.
A VBA Lookup: Copy Matches Consecutively
Option Explicit
Sub CopyMatchesConsecutively()
' Reference the source range ('srg').
Dim swb As Workbook: Set swb = ThisWorkbook
Dim sws As Worksheet: Set sws = swb.Worksheets(1)
Dim sfrrg As Range: Set sfrrg = sws.Range("A3:B3") ' first row range
Dim srg As Range, srCount As Long
With sfrrg
' '.Resize(sws.Rows.Count - .Row + 1)' is 'A3:B1048576' (or 'A3:B65536')
Dim slCell As Range: Set slCell = .Resize(sws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , xlByRows, xlPrevious)
If slCell Is Nothing Then Exit Sub ' no data
srCount = slCell.Row - .Row + 1
Set srg = .Resize(srCount)
End With
' Write the values from the source range to an array ('Data').
Dim Data(): Data = srg.Value
' Write the results to the top of the first column of the array.
Dim sr As Long, dr As Long
For sr = 1 To srCount
If IsEmpty(Data(sr, 1)) Then ' empty
' Or:
'If Len(CStr(Data(sr, 1))) = 0 Then ' blank e.g. '=""' (includes empty)
dr = dr + 1
Data(dr, 1) = Data(sr, 2)
End If
Next sr
' The results are in the rows from 1 to 'dr' of the first column.
' Reference the destination range ('drg').
Dim dwb As Workbook: Set dwb = Workbooks("ClientList.xlsm")
Dim dws As Worksheet: Set dws = dwb.Worksheets(1)
Dim dfCell As Range: Set dfCell = dws.Range("C2")
Dim drg As Range: Set drg = dfCell.Resize(dr) ' single-column of size 'dr'
' Write the results to the destination range.
drg.Value = Data ' write
drg.Resize(dws.Rows.Count - drg.Row - dr + 1).Offset(dr).Clear ' clear below
' Inform.
MsgBox "Matches copied consecutively.", vbInformation
End Sub
I am currently using this code which goes through my worksheet and checks in the range O15:O300 to see if there are any cells that match the current date. If there is then it copies the entire row to worksheet "Today's Actions" then copies the site number (Situated in cell C3) to column AA in "Todays Actions".
I use the below code which works fine for this task for one specific sheet:
Sub rangecheck()
Application.ScreenUpdating = False
For Each cell In Range("O15:O300")
If cell.Value = Date Then
matchRow = cell.Row
Rows(matchRow & ":" & matchRow).Select
Selection.Copy
Sheets("Today's Actions").Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
ActiveSheet.Range("C3").Copy
Sheets("Today's Actions").Range("AA" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
End If
Next
Application.ScreenUpdating = True
End Sub
However, there are multiple sheets that I need to action this code for. So I use the below code to run this across all sheets:
Sub rangecheck_Set()
Dim ws As Worksheet
Dim starting_ws As Worksheet
Set starting_ws = ActiveSheet
Application.ScreenUpdating = False
For Each ws In ThisWorkbook.Worksheets
ws.Activate
Call rangecheck
Next
starting_ws.Activate 'activate the worksheet that was originally active ("Today's Actions")
Application.ScreenUpdating = True
End Sub
This issue I'm having is that it seems to work fine but randomly whenever there are a lot of dates that match todays date in range O15:O300, it duplicates some lines up to or slightly exceeding 300 rows (So as an example, if there were 15 rows that 'should' be brought back to "Today's action" tab, it would bring them back but then have a few other rows randomly duplicated down to around row 300).
I get this might be due to the range going down to 300 but I even edited the range to go to 'last row' and it still brings back the same issue. Any thoughts? I've been trying to solve this for days now. Any help appreciated
Don't use implicit references to worksheets and ranges. It is most likely that this is the reason for your problem.
Also you don't need to select and copy - another source for unforeseeable errors.
Another reason for your error could be that you don't exclude "Today's Actions"-sheet from the copying routine.
I re-wrote your sub that is copying the data:
Sub copyTodaysRows(wsSource As Worksheet, wsTarget As Worksheet)
If wsSource is wsTarget then Exit Sub 'don't run this for the target sheet
Dim c As Range, wsTargetNewRow As Long
For Each c In wsSource.Range("O15:O300")
If c.Value = Date Then
With wsTarget
wsTargetNewRow = .Range("A" & .Rows.Count).End(xlUp).Row + 1
c.EntireRow.Copy Destination:=.Range("A" & wsTargetNewRow)
.Range("AA" & wsTargetNewRow).Value = wsSource.Range("C3").Value
End With
End If
Next
End Sub
It takes the source sheet and the target sheet as input parameters.
You will call it like this within your "outer" routine:
Sub rangecheck_Set()
Application.ScreenUpdating = False
Dim wsSource as worksheet
Dim wsTarget as worksheet
Set wsTarget = Thisworkbook.Worksheets("Today's Actions")
For Each wsSource In ThisWorkbook.Worksheets
copyTodaysRows wsSource, wsTarget
Next
Application.ScreenUpdating = True
End Sub
Copy Values of Criteria (Dates) Rows From Multiple Worksheets
Option Explicit
Sub RetrieveTodaysActions()
' Calls 'RetrieveTodaysActionsCall'.
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet
For Each sws In ThisWorkbook.Worksheets
RetrieveTodaysActionsCall sws
Next sws
MsgBox "Today's actions retrieved.", vbInformation
End Sub
Sub RetrieveTodaysActionsCall(ByVal sws As Worksheet)
' Define constants.
' Source
Const sCriteriaColumnAddress As String = "O15:O300"
Const sCol1 As String = "A"
Const sCell2Address As String = "C3"
' Destination
Const dName As String = "Today's Actions"
Const dCol1 As String = "A"
Const dCol2 As String = "AA"
' Both
' Write the criteria date to a variable ('CriteriaDate').
Dim CriteriaDate As Date: CriteriaDate = Date ' today
' Exclude the destination worksheet.
If StrComp(sws.Name, dName, vbTextCompare) = 0 Then Exit Sub
' Reference the source criteria column range ('scrg').
Dim scrg As Range: Set scrg = sws.Range(sCriteriaColumnAddress)
' Check the number of matches, the number of rows to be copied
' to the destination worksheet.
If Application.CountIf(scrg, Date) = 0 Then Exit Sub
' Reference the range ('surg'), the range from the first cell
' in the source column ('sCol1') to the last cell of the used range.
Dim surg As Range
With sws.UsedRange
Set surg = sws.Range(sCol1 & 1, .Cells(.Rows.Count, .Columns.Count))
End With
' Reference the source range ('srg').
Dim srg As Range: Set srg = Intersect(scrg.EntireRow, surg)
If srg Is Nothing Then Exit Sub
' Write the number of columns of the source range to a variable (cCount).
Dim cCount As Long: cCount = srg.Columns.Count
' Write the criteria column number to a variable ('CriteriaColumn').
Dim CriteriaColumn As Long: CriteriaColumn = scrg.Column
' Write the values from the source range to an array ('Data').
Dim Data() As Variant: Data = srg.Value
Dim sValue As Variant ' Criteria Value in the Current Source Row
Dim sr As Long ' Current Source Row
Dim c As Long ' Current Source/Destination Column
Dim dr As Long ' Current Destination Row
' Loop through the rows of the array.
For sr = 1 To UBound(Data, 1)
' Write the value in the current row to a variable.
sValue = Data(sr, CriteriaColumn)
' Check if the current value is a date.
If IsDate(sValue) Then
' Check if the current value is equal to the criteria date.
If sValue = CriteriaDate Then
dr = dr + 1
' Write the values from the source row to the destination row.
For c = 1 To cCount
Data(dr, c) = Data(sr, c)
Next c
End If
End If
Next sr
' Reference the destination worksheet ('dws').
Dim dws As Worksheet: Set dws = sws.Parent.Worksheets(dName)
' Reference the destination first cell ('dfCell').
Dim dfCell As Range
Set dfCell = dws.Cells(dws.Rows.Count, dCol1).End(xlUp).Offset(1)
' Reference the destination range ('drg').
Dim drg As Range: Set drg = dfCell.Resize(dr, cCount)
' Write the values from the array to the destination range.
drg.Value = Data
' Reference the destination range 2 ('drg2').
Dim drg2 As Range: Set drg2 = drg.EntireRow.Columns(dCol2)
' Write the source cell 2 value to the destination range 2 ('drg2')
' (the same value to all cells of the range).
drg2.Value = sws.Range(sCell2Address).Value
End Sub
My process was different from the other responses, so I will still post it. I have also added a way of logging that a row has been logged because otherwise I saw that rows could be duplicated to the "Today's Actions" sheet.
Sub rangecheck(ByVal checkedSheet As Worksheet)
'#PARAM checkedSheet is the sheet to iterate through for like dates.
'Instantiate counter variables
Dim matchRow As Integer
matchRow = 0
Dim pasteRow As Integer
pasteRow = 0
Application.ScreenUpdating = False
For Each cell In checkedSheet.Range("O15:O300")
If cell.Value = Date Then
matchRow = cell.Row
'Checks if the row has been logged already (I use column "A" because I
'have no data in it, but this can be amy column in the row)
If checkedSheet.Cells(matchRow, 1) = "Logged" Then
'Do nothing
Else
'Sets value of "pasteRow" to one lower than the lowest used row in
column "AA"
pasteRow = Sheets("Today's Actions").Cells(Rows.Count,
27).End(xlUp).Row + 1
'Copies the values of the matchRow to the pasteRow
Sheets("Today's Actions").Rows(pasteRow).Value =
checkedSheet.Rows(matchRow).Value
'Copies the value of the Site Number to the paste row column "AA"
Sheets("Today's Actions").Cells(pasteRow, 27).Value =
checkedSheet.Cells(3, 3).Value
'Log that a row has been added to the "Today's Actions" sheet
checkedSheet.Cells(matchRow, 1) = "Logged"
End If
End If
Next
Application.ScreenUpdating = True
End Sub
I have also modifed your sub which calls the copying sub to check if it is trying to copy the "Today's Actions" sheet.
Sub rangecheck_Set()
Dim ws As Worksheet
Dim starting_ws As Worksheet
Set starting_ws = Worksheets("Today's Actions")
Application.ScreenUpdating = False
For Each ws In ThisWorkbook.Worksheets
'Check if the ws to check is "Today's Actions"
If ws.Name = "Today's Actions" Then
'Do Nothing
Else
Call rangecheck(ws)
End If
Next
starting_ws.Activate 'activate the worksheet that was originally active
Application.ScreenUpdating = True
End Sub
I am having trouble copying visible cells from a filtered data column (T) to another column (Q) in the same sheet. I have tried this method, but the data I am working with is over 100,000 columns and going line by line is taking forever. Another option I have explored is to manually change the formula for Q to =T but I don't know how to implement this into VBA as I am new to it.
Option Explicit
Sub Test1()
Dim ws As Worksheet: Set ws = ActiveSheet
ws.Range("$A$1", ActiveCell.SpecialCells(xlLastCell)).AutoFilter Field:=19, Criteria1:= _
"=NMCM", Operator:=xlOr, Criteria2:="=Houses"
ws.Range("$A$1", ActiveCell.SpecialCells(xlLastCell)).AutoFilter Field:=20, Criteria1:=Array _
("Test1", "Test2"), _
Operator:=xlFilterValues
' First Cell of the Data Range (in the row below headers)
Dim fCell As Range: Set fCell = ws.Range("T2")
' Last Cell of the Filtered Range
Dim lCell As Range: Set lCell = ws.Range("T" & ws.Rows.Count).End(xlUp)
' If no filtered data, the last cell will be the header cell, which
' is above the first cell. Check this with:
If lCell.Row < fCell.Row Then Exit Sub ' no filtered data
' Range from First Cell to Last Cell
Dim rg As Range: Set rg = ws.Range(fCell, lCell)
' Filtered Data Range
Dim frg As Range: Set frg = rg.SpecialCells(xlCellTypeVisible)
' Area Range
Dim arg As Range
For Each arg In frg.Areas
' Either copy values (more efficient (faster))...
arg.EntireRow.Columns("Q").Value = arg.Value
' ... or copy values, formulas and formatting
'arg.Copy arg.EntireRow.Columns("Y")
Next arg
End Sub
Write Filtered Column to Another Filtered Column
Option Explicit
Sub Extract_Airworthy_status()
Const sfCol As Long = 19 ' S
Const sCol As Long = 20 ' T
Const dCol As Long = 17 ' Q
Dim ws As Worksheet: Set ws = ActiveSheet
If ws.AutoFilterMode Then ws.AutoFilterMode = False
Dim sdrg As Range ' Source Data Range (no headers)
With ws.Range("A1").CurrentRegion
Set sdrg = .Columns(sCol).Resize(.Rows.Count - 1).Offset(1)
.AutoFilter Field:=sfCol, Criteria1:="=NMCM", _
Operator:=xlOr, Criteria2:="=Houses"
.AutoFilter Field:=sCol, Criteria1:=Array("Test1", "Test2"), _
Operator:=xlFilterValues
End With
Dim sdfrg As Range ' Source Data Filtered Range
On Error Resume Next
Set sdfrg = sdrg.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
ws.AutoFilterMode = False
If sdfrg Is Nothing Then Exit Sub
Dim cOffset As Long: cOffset = dCol - sCol
Dim ddfrg As Range ' Destination Data Filtered Range
Set ddfrg = sdfrg.Offset(, cOffset)
ddfrg.Formula = "=" & sdfrg.Cells(1).Address(0, 0)
Dim ddrg As Range ' Destination Data Range
Set ddrg = sdrg.Offset(, cOffset)
ddrg.Value = ddrg.Value
End Sub
There are 3 groups (A,B,C) of data in excel sheet1, and in my workbook i already create 3 sheets named (A, B, C).
I have no problem to copy group A,B,C data into their corresponding sheet, e.g. copy group A data into sheet A, however i find in some cases the selected cell at the beginning of each sheet is not in A1, e.g. the selected cell at the beginning maybe at somewhere other cells in excel (e.g. B10), this make the presentation looks messy, i want the all the data in each sheet start at A1. I know some of you may said using the code Range("a1").selected can manage this situation, however we need to use the "Do loop" to loop over each row in sheet1 to identify that row is belong to A,B or C, then we paste that row into the corresponding sheet. I found if i include the code Range("a1").selected, then each time the program will paste the row in Sheet1 into the cell A1 in sheet A,B and C, and at the end there will only one row appear in each sheets. What should i improve the program below so that each time the data in each group can be appeared at the beginning of cell A1 in their worksheet even sometimes the selected cell of each sheet is not in cell A1? Thanks.
Sub data_category()
Dim y As Integer
Dim x As String
Sheets("sheet1").Activate
Range("a3").Select
Do Until ActiveCell.Value = ""
y = ActiveCell.Offset(0, 3).Value
If y < 90 Then
x = "A"
ElseIf y < 120 Then
x = "B"
Else
x = "C"
End If
ActiveCell.Offset(0, 4).Value = x
Range(ActiveCell, ActiveCell.End(xlToRight)).Copy
Sheets(x).Activate
Range("a1").Select
ActiveCell.PasteSpecial
ActiveCell.Offset(1, 0).Select
Sheets("sheet1").Activate
ActiveCell.Offset(1, 0).Select
Loop
End Sub
Rather than the Do-Loop approach, I would do this slightly different for a faster execution.
Logic
Find last row in Sheet1 of Col A
Insert formula =IF(D3<90,"A",IF(D3<120,"B","C")) in Col E starting at row 3
Next I will use autofilter to filter column E on A first and copy all data in one go to Sheet A. I will repeat the process for B and C
My Assumptions
Row 2 has headers. If not, tweak the code accordingly.
Code
I have commented the code so you will not have a problem understanding it, but if you do, then simply ask.
Option Explicit
Dim ws As Worksheet
Dim rng As Range
Sub Sample()
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim lRow As Long
With ws
'~~> Remove any filters
.AutoFilterMode = False
'~~> Find last row
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Insert formula in Col E
With .Range("E3:E" & lRow)
.Formula = "=IF(D3<90,""A"",IF(D3<120,""B"",""C""))"
.Value = .Value
End With
'~~> Identify the range to work with
Set rng = .Range("A2:E" & lRow)
'~~> Copy rows with relevant criteria
CopyData "A"
CopyData "B"
CopyData "C"
.AutoFilterMode = False
End With
End Sub
Private Sub CopyData(shName As String)
Dim rngToCopy As Range
'~~> Filter column E on the search string
With rng
.AutoFilter Field:=5, Criteria1:=shName
Set rngToCopy = .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow
End With
'~~> Copy all data in one go
If Not rngToCopy Is Nothing Then rngToCopy.Copy ThisWorkbook.Sheets(shName).Rows(1)
ws.AutoFilterMode = False
End Sub
In Action
Following from Sid's comment:
Sub data_category()
Dim y As Long
Dim x As String, c As Range, ws As Worksheet, wb As Workbook, cDest As Range
Set wb = ActiveWorkbook 'or ThisWorkbook: always good to be specific here
Set c = wb.Worksheets("sheet1").Range("a3") 'get a reference to the starting cell
Do Until Len(c.Value) = 0
y = c.Offset(0, 3).Value
Select Case y 'tidier then if...else if
Case Is < 90: x = "A"
Case Is < 120: x = "B"
Case Else: x = "C"
End Select
c.Offset(0, 4).Value = x
'direct copy to next empty row with no select/activate
Set cDest = wb.Worksheets(x).Cells(Rows.Count, 1).End(xlUp)
If Len(cDest).Value > 0 Then Set cDest = cDest.Offset(1, 0)
c.EntireRow.Copy cDest
Set c = c.Offset(1,0) '<<<<<<<<<<<<< edit - added
Loop
c.Parent.Activate
End Sub
Update Category Reports
Option Explicit
Sub UpdateCategoryReports()
Const sfRow As Long = 3 ' First Row (headers are in row 'sfRow - 1')
Const sfCol As Long = 1
Const dfRow As Long = 2 ' First Row (headers are in row 'dfRow - 1')
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets("Sheet1")
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, "A").End(xlUp).Row
If slRow < sfRow Then Exit Sub ' no data (highly unlikely)
Dim slCol As Long
slCol = sws.Cells(sfRow - 1, sws.Columns.Count).End(xlToLeft).Column
Application.ScreenUpdating = False
Dim dws As Worksheet ' Destination Worksheet
Dim durg As Range ' Destination 'UsedRange'
Dim dcrg As Range ' Destination Clear Range
' Clear destination data.
For Each dws In wb.Worksheets(Array("A", "B", "C"))
Set durg = dws.UsedRange ' Destination Used Range
If durg.Rows.Count > 1 Then
' You don't want to clear the headers:
' e.g. if 'durg' is 'A1:J10' then 'dcrg' will be 'A2:J10'.
Set dcrg = durg.Resize(durg.Rows.Count - 1).Offset(1)
dcrg.Clear
End If
Next dws
Dim srrg As Range ' Source Row Range
Dim sRow As Long ' Source Row
Dim dfCell As Range ' Destination First Cell (Range)
Dim dRow As Long ' Destination (Available) Row
Dim sValue As Double ' Source Value
Dim dwsName As String ' Destination Worksheet Name
For sRow = sfRow To slRow
If IsNumeric(sws.Cells(sRow, "D").Value) Then
sValue = sws.Cells(sRow, "D").Value
If sValue < 90 Then
dwsName = "A"
ElseIf sValue < 120 Then
dwsName = "B"
Else
dwsName = "C"
End If
Set srrg = sws.Range(sws.Cells(sRow, "A"), sws.Cells(sRow, slCol))
sws.Cells(sRow, "E").Value = dwsName ' ?
Set dws = wb.Worksheets(dwsName)
dRow = dws.Cells(dws.Rows.Count, "A").End(xlUp).Row + 1
Set dfCell = dws.Cells(dRow, "A")
' This will copy values, formats, and formulas. You may need another
' way. If there are formulas in source and you only need values,
' copying by assignment is the most efficient way. If you also need
' the formats you will have to use the least efficient PasteSpecial.
srrg.Copy Destination:=dfCell
'Else ' sValue is not numeric: do nothing
End If
Next sRow
'sws.Activate
'sws.Cells(1).Activate
Application.ScreenUpdating = True
MsgBox "Category reports updated.", vbInformation, "Category Reports"
End Sub
I have data in Column A and B in Sheet2 and I have taken some of data from Column A and paste them in column A in Sheet1 and now I want to import data from Sheet2 Column B for matched data of column A in both sheet. I have used below logic to do this but getting error.
For k=2 To 400
Cells(k,2).Value = WorksheetFunction.Index(Sheet2!Range("B2:B1255"), WorksheetFunction.Match(Cells(K, 1).Value, Sheet2!Range("A2:A1255")))
Next k
Index Match Formula in VBA
In the second example, adjust the name of the destination worksheet (Sheet1) appropriately.
The Code
Option Explicit
Sub testFormula()
With Range("B2").Resize(400 - Range("B2").Row + 1)
.Formula = "=IFERROR(INDEX(Sheet2!B$2:B$1255," _
& "MATCH(A2,Sheet2!A$2:A$1255,0)),"""")"
.Value = .Value
End With
End Sub
Sub testVBA()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Define Source Lookup Range.
Dim srg As Range
With wb.Worksheets("Sheet2")
Dim sLast As Long: sLast = .Cells(.Rows.Count, "A").End(xlUp).Row
Set srg = .Range("A2:A" & sLast) ' i.e. '.Range("A2:A1255")'
' Or just:
'Set srg = .Range("A2:A" & .Cells(.Rows.Count, "A").End(xlUp).Row)
End With
' Define Destination Lookup Range.
Dim drg As Range
With wb.Worksheets("Sheet1")
Dim dLast As Long: dLast = .Cells(.Rows.Count, "A").End(xlUp).Row
Set drg = .Range("A2:A" & dLast) ' i.e. '.Range("A2:A400")'
' Or just:
'Set drg = .Range("A2:A" & .Cells(.Rows.Count, "A").End(xlUp).Row)
End With
' Loop through cells of Destination Lookup Range...
Dim dCell As Range
Dim cIndex As Variant ' Can be an error value, hence 'Variant'.
' Loop through cells of Destination Lookup Range.
For Each dCell In drg.Cells
' Attempt to find a match (the first occurrence) of the value
' in the current cell of Destination Lookup Range,
' in cells of Source Lookup Range.
cIndex = Application.Match(dCell.Value, srg, 0)
' If a match is found...
If IsNumeric(cIndex) Then
' Write the value from the cell associated (in the same row)
' to the matched cell (i.e. Source Column 'B'), to the cell
' associated (in the same row) to the current cell
' (Destination Column 'B').
dCell.Offset(, 1).Value = srg.Cells(cIndex).Offset(, 1).Value
' IF no match found (error value)...
Else
dCell.Offset(, 1).Value = ""
End If
Next dCell
End Sub