I have 5 columns. If column 3 has no value, I want all other adjacent cells (column 1,2,4,5) to clear.
I got this from another site:
Sub ClearCust()
'Clears data in column if there is no Amt number next to it.
'Used in conjunction to fill blanks.
Dim j As Range
For Each j In Workbooks("OH Details_v1").Worksheets("Sheet1").Range("C2:D" & Worksheets("Sheet1").Range("a65536").End(xlUp).Row)
If j.Value = 0 Then
j.Offset(0, 1).ClearContents
End If
Next j
End Sub
But it only clears column C, D, E...
Something like this might be what you're looking for:
Sub ClearCust()
Dim wb As Workbook
Dim ws As Worksheet
Dim rLast As Range
'Set wb = Workbooks("OH Details_v1")
Set wb = ThisWorkbook
Set ws = wb.Worksheets("Sheet1")
Set rLast = ws.Range("A:E").Find("*", ws.Range("A1"), xlValues, , , xlPrevious)
If rLast Is Nothing Then Exit Sub 'No data
With ws.Range("C1:C" & rLast.Row)
.AutoFilter 1, "="
Intersect(.Parent.Range("A:E"), .Offset(1).EntireRow).ClearContents
.AutoFilter
End With
End Sub
EDIT:
To address your request of iterating over sets of columns to perform this same task, you can do something like this:
Sub ClearCust()
Dim wb As Workbook
Dim ws As Worksheet
Dim rLast As Range
Dim aClearAreas() As String
Dim i As Long
'Set wb = Workbooks("OH Details_v1")
Set wb = ThisWorkbook
Set ws = wb.Worksheets("Sheet1")
ReDim aClearAreas(1 To 3, 1 To 2)
'Define columns that will be cleared Define column within that range to evaluate for blanks
aClearAreas(1, 1) = "A:E": aClearAreas(1, 2) = "C"
aClearAreas(2, 1) = "F:J": aClearAreas(2, 2) = "H"
aClearAreas(3, 1) = "K:O": aClearAreas(3, 2) = "M"
'loop through your array that contains your clear area data
For i = LBound(aClearAreas, 1) To UBound(aClearAreas, 1)
'Get last populated row within the defined range
Set rLast = ws.Range(aClearAreas(i, 1)).Find("*", ws.Range(aClearAreas(i, 1)).Cells(1), xlValues, , , xlPrevious)
If Not rLast Is Nothing Then
'Filter on the column to be evaluated
With ws.Range(aClearAreas(i, 2) & "1:" & aClearAreas(i, 2) & rLast.Row)
.AutoFilter 1, "=" 'Filter for blanks
Intersect(.Parent.Range(aClearAreas(i, 1)), .Offset(1).EntireRow).ClearContents 'Clear cells only in the defined range
.AutoFilter 'Remove the filter
End With
End If
Next i
End Sub
Your explanation and title are two different subjects but based on your explanation-i understand you want to loop through column C and if a cell is empty, then you make other cells value to blank-i wrote below code. You may use. Tested
Sub test()
Dim ws As Worksheet
Set ws = ActiveSheet
With ws
lr = .Cells(Rows.Count, "C").End(xlUp).Row
For i = 2 To lr
If .Cells(i, "C") = "" Then
.Cells(i, "A") = ""
.Cells(i, "B") = ""
.Cells(i, "D") = ""
.Cells(i, "E") = ""
End If
Next i
End With
End Sub
Related
I am trying to write a macro that will look in column A on sheet1 and see if it is missing any values from column A on sheet2 or column A on sheet3. If it is missing have the value added to the bottom of the column A on sheet1. The same value may exist on sheet2 and sheet3 but it only needs to be represented once on sheet1.
I'm working with the code below.
Sub newRow()
Dim rngSh1 As Range, rngSh2 As Range, rngSh3 As Range, mySelSh2 As Range, mySelSh3 As Range
Dim lastRowSh1 As Long, lastRowSh2 As Long, lastRowSh3 As Long
Dim wb As Worksheet
Dim cell As Range
Set wb = ThisWorkbook
With wb
lastRowSh1 = Worksheets("Sheet1").Range("A" & .Rows.Count).End(xlUp).Row
lastRowSh2 = Worksheets("Sheet2").Range("A" & .Rows.Count).End(xlUp).Row
lastRowSh3 = Worksheets("Sheet3").Range("A" & .Rows.Count).End(xlUp).Row
Set rngSh1 = Worksheets("Sheet1").Range("A1:A" & lastRowSh1)
Set rngSh2 = Worksheets("Sheet2").Range("A1:A" & lastRowSh2)
Set rngSh3 = Worksheets("Sheet3").Range("A1:A" & lastRowSh3)
End With
For Each cell In rngSh2.Cells
If IsError(Application.Match(cell.Value, rngSh1, 0)) Then
If mySelSh2 Is Nothing Then
Set mySelSh2 = cell
Else
Set mySelSh2 = Union(mySelSh2, cell)
End If
End If
Next cell
If Not mySelSh2 Is Nothing Then mySelSh2.Copy Destination:=Worksheets("Sheet1").Range("A" & lastRowSh1 + 1)
For Each cell In rngSh3.Cells
If IsError(Application.Match(cell.Value, rngSh1, 0)) Then
If mySelSh3 Is Nothing Then
Set mySelSh3 = cell
Else
Set mySelSh3 = Union(mySelSh3, cell)
End If
End If
Next cell
If Not mySelSh3 Is Nothing Then mySelSh3.Copy Destination:=Worksheets("Sheet1").Range("A" & lastRowSh1 + 1)
End Sub
I've made every adjustment I can think of but with every change I make I get a different error.
Any help would be greatly appreciated. Thanks!
Save yourself a little bit of time using a Scripting.Dictionary:
Option Explicit
Sub test()
Dim dict As New Scripting.dictionary, sheetNum As Long
For sheetNum = 2 To Sheets.Count
With Sheets(sheetNum)
Dim lastRow As Long: lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Dim rowNum As Long
For rowNum = 1 To lastRow
Dim dictVal As Long: dictVal = .Cells(rowNum, 1).Value
If Not dict.Exists(dictVal) Then dict.Add dictVal, 0
Next rowNum
End With
Next sheetNum
With Sheets(1)
Dim checkableRangeLastRow As Long: checkableRangeLastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Dim checkableRange As Range: Set checkableRange = .Range(.Cells(1, 1), .Cells(checkableRangeLastRow, 1))
Dim dictKey As Variant
For Each dictKey In dict.Keys
If IsError(Application.Match(dictKey, checkableRange, 0)) = True Then
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
.Cells(lastRow + 1, 1).Value = dictKey
End If
Next dictKey
End With
End Sub
You add all values in your not-master-sheet into dict then loop through that list; if it's not found in your master-sheet, then you add then to the end of the list.
A significant note is that the Type of value used as the dictVal may cause the IsError() statement to always be True if it is not the same Type as the data being assessed in the checkableRange.
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 been trying to create a function which checks that if Col"B" <> Empty then copy the third cell which is under the same row.
I have this Data:
Where from i want to copy the Col"D" highlighted cells and paste them into same row where Col"B" <> empty.
Here is the final result. Your help will be appreciated in this regards.
Option Explicit
Sub CopyPasting()
Dim ws As Worksheet
Dim r As Long
Dim LastRow As Long
Dim n As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
LastRow = .Range("D" & .Rows.Count).End(xlUp).Row
For r = LastRow To 2 Step -2
If .Cells(r, "B") <> "" Then
.Rows(r + "D").Copy
.Rows(r + "D").PasteSpecial
n = n + 1
End If
Next
End With
End Sub
Please, try the next code:
Sub testRetOffset3()
Dim sh As Worksheet, lastR As Long, rngV As Range, rngFin As Range, c As Range
Set sh = ActiveSheet 'use here the sheet you need
lastR = sh.Range("B" & sh.rows.count).End(xlUp).row 'last sheet row
On Error Resume Next 'if not empty cells in column, it will not return the range and raise an error
Set rngV = sh.Range("B2:B" & lastR).SpecialCells(xlCellTypeConstants)
On Error GoTo 0
If rngV Is Nothing Then Exit Sub 'stop the code if run on a wrong sheet, without empty cells in column B:B
For Each c In rngV.cells 'iterate between the discontinuous range cells
If rngFin Is Nothing Then 'if the final range is not set (first time)
Set rngFin = c.Offset(3, 2) 'set the range = the Offset necessary cell
Else
Set rngFin = Union(rngFin, c.Offset(3, 2)) 'make a Union between existing range and the Offset necessary cell
End If
Next
If Not rngFin Is Nothing Then 'copy both ranges in consecutive columns
rngV.Copy sh.Range("F2")
rngFin.Copy sh.Range("G2")
End If
End Sub
It will return in columns F:G, starting from the second row. It is easy to modify the range where to return...
You can even clear the existing processed columns and return in B:C, or in another sheet.
Edited:
In order to solve the last request, please use the next code:
Sub testRetOffsetMoreRows()
Dim sh As Worksheet, lastR As Long, rngV As Range, rngFin As Range, A As Range
Set sh = ActiveSheet
lastR = sh.Range("B" & sh.rows.count).End(xlUp).row
On Error Resume Next
Set rngV = sh.Range("A2:D" & lastR).SpecialCells(xlCellTypeConstants)
On Error GoTo 0
If rngV Is Nothing Then Exit Sub
For Each A In rngV.Areas 'iterate between the range areas
If rngFin Is Nothing Then
Set rngFin = A.cells(1,2).Offset(3, 3) 'use the second cell of the area
Else
Set rngFin = Union(rngFin, A.cells(1,2).Offset(3, 3))
End If
Next
If Not rngFin Is Nothing Then
rngV.Copy sh.Range("H2")
rngFin.Copy sh.Range("L2")
End If
End Sub
But take care to have continuous ranges when have a value in column B:B. Otherwise, the code may fail... The areas property will return differently.
I wasn't sure where you wanted the output, this will put it into a sheet called "Sheet2". (You'll have to make that before running the code it won't create it for you.)
Dim i As Long
Dim j As Long
Dim lr As Long
Dim srcWS As Worksheet
Dim destWS As Worksheet
Set srcWS = ThisWorkbook.Sheets("Sheet1")
Set destWS = ThisWorkbook.Sheets("Sheet2")
With srcWS
lr = .Cells(.Rows.Count, 4).End(xlUp).Row
j = 2
For i = 2 To lr
If .Cells(i, 2).Value <> "" Then
destWS.Cells(j, 1).Value = .Cells(i, 2).Value
destWS.Cells(j, 2).Value = .Cells(i, 4).Offset(2, 0).Value
j = j + 1
End If
Next i
End With
If you need the colors copied over as well then use this:
.Cells(i, 4).Offset(2, 0).Copy
destWS.Cells(j, 2).PasteSpecial xlPasteAll
instead of:
destWS.Cells(j, 2).Value = .Cells(i, 4).Offset(2, 0).Value
I am trying to format some numbers where some have a leading zero so that I can then search them.
I am needing to format a set of numbers where all are 6 digits and some have a leading zero. I then have a separate code search those numbers for a specific one so the resulting format needs to be searchable. The first code below is the formatting I can't figure out and then the search code. If I simply do an "000000" for formatting I don't believe it works for my search anymore as those now become Special format. Help please?
Sub (First Code)
Dim lngLastRow As Long
lngLastRow = Cells(Rows.Count, "A").End(xlUp).Row
Range("O2:P" & lngLastRow).Select 'specify the range which suits your purpose
With Selection
Selection.NumberFormat = "General"
.Value = .Value
End With
Dim SUPLCD As Range
Set SUPLCD = Range("Q2:Q")
With Selection
Selection.NumberFormat = "#"
Selection.Value = Format(Selection, "000000")
End With
End Sub
Sub Worksheet()
Dim i As Long
Dim j As Long
Dim wsCurrent As Worksheet
Set wsCurrent = ActiveSheet
Dim wsData As Worksheet
Dim rngData As Range
Set wsData = ThisWorkbook.Worksheets("Tempinterior")
Dim wsTempinterior As Worksheet
' Note that .Add will activate the new sheet so we'll
' need to reactivate the worksheet that was previously active
Set wsTempinterior = Worksheets.Add
wsTempinterior.Name = "copy"
' Find the used range in columns A to K and copy over starting
' at cell A1 of wsGalreq
Set rngData = Intersect(wsData.UsedRange, wsData.Range("A:M"))
' Copy over the first row containing column headers
j = 1
rngData.Rows(1).Copy Destination:=wsTempinterior.Cells(j, 1)
For i = 2 To rngData.Rows.Count
' Check cell of column 10 of row i and copy if matched
If rngData.Cells(i, 10).Value = "026572" Or rngData.Cells(i, 10).Value = "435740" Or rngData.Cells(i, 10).Value = "622639" Then
' Copy over to wsDalreq from row j
j = j + 1
rngData.Rows(i).Copy Destination:=wsTempinterior.Cells(j, 1)
End If
Next
End Sub
With above code, the search doesn't pull the entries with those numbers I think because they are formatted as Special.
You don't have to format Col Q to add a 0, you can accomplish your task with out formatting by using Like in your If statement. Because you are not clear about where the values are, you are formatting Col Q but searching Col J, I used Col Q.
Dim wsData As Worksheet
Set wsData = ThisWorkbook.Worksheets("Sheet1") '("Tempinterior")
Dim rngData As Range
Set rngData = Intersect(wsData.UsedRange, wsData.Range("A:M"))
Sheets.Add(After:=Sheets(Sheets.Count)).Name = "copy"
j = 1
rngData.Rows(1).Copy Destination:=Sheets("copy").Cells(j, 1) 'copy headers for rngData
For i = 2 To rngData.Rows.Count
If wsData.Cells(i, 17).Value Like "26572" Or Sheet1.Cells(i, 17).Value = "435740" Or _
Sheet1.Cells(i, 17).Value = "622639" Then
j = j + 1
rngData.Rows(i).Copy Destination:=Sheets("Copy").Cells(j, 1)
End If
Next i
End Sub
First avoid .Select and you will need to loop the change:
Sub first()
Dim lngLastRow As Long
With Worksheets("Sheet1") 'Change to your sheet
lngLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
With .Range("O2:P" & lngLastRow) 'specify the range which suits your purpose
.NumberFormat = "General"
.Value = .Value
End With
Dim SUPLCD As Range
Set SUPLCD = .Range("Q2:Q" & lngLastRow)
Dim rng As Range
For Each rng In SUPLCD
rng.NumberFormat = "#"
rng.Value = Format(rng.Value, "000000")
Next rng
End With
End Sub
Screenshot of SourceReport Excel that need to be filtered.I need to develop a Excel VBA code to filter data on a worksheet, based on the filter conditions provided on the same worksheet.
Below is the code written for the same .. But this code filter the data from Row 1 instead of Row 4. Can you suggest an improvement?
Sub colFilter()
Dim ShtSource As Worksheet
Dim shtSrcHead As Range
Dim shtFilterData As Range
Dim filterStr As String
Set ShtSource = Sheets("SourceReport")
Dim lastCol As Long
Dim j As Long
Dim iCntr As Long
'get all of the filters of sheet , assuming in row 2
lastCol = ShtSource.Cells(1, Columns.Count).End(xlToLeft).Column
Set shtSrcHead = ShtSource.Range("A2", ShtSource.Cells(1, lastCol))
Set shtFilterData = ShtSource.Range("A4", ShtSource.Cells(1, lastCol))
j = 0
'actually loop through and find values
For Each srcHead In shtSrcHead
j = j + 1
If j = lastCol Then
j = 0
End If
If srcHead.Value = "INCLUDE" Or srcHead.Value = "EXCLUDE" Then
filterStr = srcHead.Offset(1, 0).Value
If srcHead.Value = "INCLUDE" Then
Debug.Print filterStr
Debug.Print j
shtFilterData.AutoFilter Field:=j, Criteria1:=filterStr
End If
If srcHead.Value = "EXCLUDE" Then
Debug.Print filterStr
Debug.Print j
shtFilterData.AutoFilter Field:=j, Criteria1:="<>" & filterStr
End If
End If
Next srcHead
MsgBox "Done!"
End Sub
As per below screenshot use the following sub to filter for multiple condition.
Sub MyFilter()
Dim include() As String
Dim exclude As String
Dim FiltRng As Range
Dim RngArea, RngArea2 As Range
'Set RngArea = Application.InputBox(prompt:="Select range include criteria.", Type:=8)
'Set RngArea2 = Application.InputBox(prompt:="Select range exclude criteria.", Type:=8)
'include = Split(RngArea, ",")
include = Split(Range("C2"), ",")
exclude = Range("B2")
Set FiltRng = Sheet1.Range("B4:C11")
FiltRng.AutoFilter Field:=2, Criteria1:=include, Operator:=xlFilterValues
FiltRng.AutoFilter Field:=1, Criteria1:="<>" & exclude
End Sub
Data position Screenshot
Adjust code for your data ranges.