Clear Contents of Rows Depending on Cell Range - vba

Data layout: A3 onwards to A(no specific last row) is referred to as under Name Manager as =PeriodPrev.
=PeriodPrev is a label that I have used to mark the data. =PeriodCurr label starts after the last populated row for PeriodPrev.
The remaining data for PeriodPrev and PeriodCurr lay under column E to W.
Code: How to I create a clear contents of data in Columns A and E to W for data belonging to =PeriodPrev in Column A?
I've tried the following code but it does not completely serves the purpose above. "If c.Value = "PeriodPrev" Then" returns error 13. "If c.Value = Range("PeriodPrev") Then" return error 1004.
Sub BYe()
'The following code is attached to the "Clear" button which deletes Previous Period data
Dim c As Range
Dim LastRow As Long
Dim ws As Worksheet
ws = ThisWorkbook.Worksheets("Sheet1")
LastRow = Range("A" & Rows.count).End(xlUp).Row
For Each c In Range("A3:A" & LastRow)
If c.Value = "PeriodPrev" Then
' If c.Value = Range("PeriodPrev") Then
c.EntireRow.ClearContents
End If
Next c
End Sub

Use Intersect
If Not Application.Intersect(c, Range(yourLabel)) Is Nothing Then
Let me know if it doesn't work

There were a few thing wrong with that code. I've tried to address some of the problems with comments
Sub BYe()
'The following code is attached to the "Clear" button which deletes Previous Period data
Dim c As Range, lastRow As Long, ws As Worksheet
'you need to SET a range or worksheet object
Set ws = ThisWorkbook.Worksheets("Sheet1")
'you've Set ws, might as well use it
With ws
lastRow = .Range("A" & Rows.Count).End(xlUp).Row
For Each c In .Range("A3:A" & lastRow)
'the Intersect determines if c is within PeriodPrev
If Not Intersect(c, .Range("PeriodPrev")) Is Nothing Then
'this clears columns A and E:W on the same row as c.
.Range(.Cells(c.Row, "A"), .Cells(c.Row, "E").Resize(1, 19)).ClearContents
End If
Next c
End With
End Sub
The following should perform the same action without the loop.
Sub BYe2()
'The following code is attached to the "Clear" button which deletes Previous Period data
Dim lastRow As Long, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
With ws
lastRow = .Range("PeriodPrev").Rows(.Range("PeriodPrev").Rows.Count).Row
.Range("A3:A" & lastRow & ",E3:W" & lastRow).ClearContents
End With
End Sub

Related

Looping through worksheets and check cell value

I am trying to loop through all sheets and check them one by one and do the following: If in the checked cell the value of E18 = N/A then on the first sheet (named Summary) I'd change the value of G23 to N/A as well (and then do that for each cell, and on Summary change G23 then G24 then G25 and so forth) I wrote the following loop, it runs but it doesn't do anything whatsoever
Sub MyTestSub()
Dim ws As Worksheet
LastRow = Cells(Rows.Count, "G").End(xlUp).Row
For X = 22 To LastRow
For Each ws In Worksheets
If ws.Range("E18").Value="N/A" then ThisWorkbook.Sheets("Summary").Range("G"&x).Value="N/A"
Next ws
Next x
End Sub
Any help would be appreciated!
It needs to be a 2-Step procedure:
Check if IsError in the cell.
Check if the type of error is #N/A, with If .Range("E18").Value = CVErr(xlErrNA) Then.
Otherwise, if you have a regular String, like "Pass" you will get an error.
Code
Dim lRow As Long
LastRow = Sheets("Summary").Cells(Sheets("Summary").Rows.Count, "G").End(xlUp).Row
lRow = 23 ' start from row 23
For Each ws In Worksheets
With ws
If .Name <> "Summary" Then
If IsError(.Range("E18").Value) Then
If .Range("E18").Value = CVErr(xlErrNA) Then
Sheets("Summary").Range("G" & lRow).Value = CVErr(xlErrNA)
End If
End If
End If
End With
lRow = lRow + 1
Next ws
Try to reverse the nested loops. Something like this should be working:
Sub MyTestSub()
Dim ws As Worksheet
For Each ws In Worksheets
LastRow = ws.Cells(ws.Rows.Count, "G").End(xlUp).Row
If IsError(ws.Range("E18")) then
For X = 22 To LastRow
Sheets("Summary").Range("G" & LastRow) = ws.Range("E18")
next x
end if
Next ws
End Sub
Furthermore, I assume that the LastRow is different per worksheet, thus you have to reset it quite often - every time there is a new worksheet.
Last but not least - make sure that you refer the worksheet, when you are refering to Cells, like this:
LastRow = ws.Cells(ws.Rows.Count, "G").End(xlUp).Row
If you do not do it you will be taking into account the ActiveSheet.
Here is more about the errors in Excel and returning them - http://www.cpearson.com/excel/ReturningErrors.aspx
The solution will work with any error, not only with #N/A

Excel VBA - Update column A with a value if column B contains any value. If column B contains no values then do not run the macro

In my scenario I have four columns, columns A-D. If column B contains any value whatsoever then the matching row in column A must be updated to contain a predetermined value. The same macro is applied for columns C and D. I have code right now that achieves that result:
Sub Update_Column_Based_On_Column_Value1()
On Error Resume Next
Dim ws As Worksheet
Dim lRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lRow = .Range("B" & .Rows.Count).End(xlUp).Row
.Range("A1:A" & lRow).SpecialCells(xlCellTypeBlanks).Formula = "=If(B1<>"""",""PREDETERMINED VALUE"","""")"
.Range("A1:A" & lRow).Value = .Range("A1:A" & lRow).Value
End With
End Sub
When column B contains a value the macro will write "PREDETERMINED VALUE" in the corresponding cell in column A.
An issue occurs when a column does not contain any values at all. What happens is the macro will write my new value to nearly all of the blank cells in the entire data-set.
Thank you in advance for your time! I apologize if my question is noobish, I am still very new to VBA.
The use of If WorksheetFunction.CountA(ws.Range("B:B")) = 1 in the comment section to avoid the problem is a good attempt but there can be exceptions as discussed below. Test it several times using various scenarios (especially using blank range) to see if you are getting the desired result every single time.
.SpecialCells attempts to simplify the codes, however sometime the .SpecialCells(xlCellTypeBlanks) VBA function does not work as expected in Excel.
Also, the statement On Error Resume Next shouldn't be used as far as practicable. But if you must, be sure to insert the On Error GoTo 0 statement ASAP as you don't want to mask other errors.
Instead of .SpecialCells, you may use For Each loop to avoid this problem. So let's see how it looks:
Sub Update_Column_Based_On_Column_Value1()
Dim ws As Worksheet, lRow As Long, r As Range
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lRow = .Range("B" & .Rows.Count).End(xlUp).Row
For Each r In .Range("A1:A" & lRow)
If IsEmpty(r) Then
r.Formula = "=If(B" & r.Row & "<>"""",""PREDETERMINED VALUE"","""")"
r = r.Value
End If
Next
End With
End Sub
Here is the answer everyone!
Sub Update_Column_Based_On_Column_Value_1()
On Error Resume Next
Dim ws As Worksheet
Dim lRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
If WorksheetFunction.CountA(ws.Range("B:B")) = 1 Then
Else
With ws
lRow = .Range("B" & .Rows.Count).End(xlUp).Row
.Range("A1:A" & lRow).SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=If(LEN(RC2),""NEW TEXT HERE"", TEXT(,))"
.Range("A1:A" & lRow).Value = .Range("A1:A" & lRow).Value
End With
End If
End Sub

How to pick value based on condition in macros

I want to compare the data so I have to pick a value based on a condition. The example data that I have is like:
The condition is:
I want to pick the value of PO NO. that always placed 2 column after text "PO NO."
How do I get that value? After that copy and paste it in another column (example:column A)
It depends on how do you want to use those values, if you just want to put them into some continued ranges in current workbook, then I think the Filter function is sufficient, if you want to do some further calculation, you may want to write some VBA code:
Press ALT + F11 in your current worksheet.
Press ALT + I then press M.
Press Ctrl + G to open the "Immediate" window
Then write the following lines:
Sub myValues()
Dim rCount As Long
Dim i As Long
Let rCount = ThisWorkbook.ActiveSheet.Cells(Rows.Count, 6).End(xlUp).Row
For i = 1 to rCount
If WorksheetFunction.Trim(ThisWorkbook.ActiveSheet.Cells(i,6).Text) = "PO No." Then
Debug.Print ThisWorkbook.ActiveSheet.Cells(i,8).Text
End If
Next
End Sub
Now you could get all the PO NO values in the "Immediate" window.
You can extract the value you want using this formula.
=INDEX(F44:H49,MATCH("PO No.",F44:F49,0),3)
The problem which remains to be solved is how to define the range F44:F49. Your question delivers no hint as to how that should be done. Perhaps knowing where you want to value to appear would offer a clue.
You can iterate over each cell in the column and gather your post numbers, offsetted by 2 columns, like I mentioned in comments
Sub Test()
Dim WS As Worksheet
Dim ParamRange As Range
Dim LastRow As Long
Dim Cell As Range
Dim i As Long
Set WS = ActiveSheet 'or whatever sheet your want
With WS
LastRow = .Cells(.Rows.Count, "F").End(xlUp).Row
Set ParamRange = .Range("F1:F" & LastRow)
End With
For Each Cell In ParamRange 'iterate over column
If Cell.Value2 = "PO NO." Then
i = i + 1
'Debug.Print to Immediate
Debug.Print i, CurrentSearch.Offset(ColumnOffset:=2).Value2
'Paste in "A" column
CurrentSearch.Offset(ColumnOffset:=-5).Value2 = CurrentSearch.Offset(ColumnOffset:=2).Value2
End If
Next
End Sub
So you just need to collect all Cell.Offset(ColumnOffset:=2).Value2 values.
Alternatively, without iteration over cells (and faster), but little bit complicated:
Sub Test()
Dim WS As Worksheet
Dim ParamRange As Range
Dim CurrentSearch As Range
Dim FirstSearch As Range
Dim LastRow As Long
Dim Cell As Range
Dim i As Long
Set WS = ActiveSheet 'or whatever sheet your want
With WS
LastRow = .Cells(.Rows.Count, "F").End(xlUp).Row
Set ParamRange = .Range("F1:F" & LastRow)
End With
'Get first search
Set CurrentSearch = ParamRange.Find(What:="PO NO.", LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not CurrentSearch Is Nothing Then
i = i + 1
'Debug.Print to Immediate
Debug.Print i, CurrentSearch.Offset(ColumnOffset:=2).Value2
'Paste in "A" column
CurrentSearch.Offset(ColumnOffset:=-5).Value2 = CurrentSearch.Offset(ColumnOffset:=2).Value2
Set FirstSearch = CurrentSearch
Do
'Get next search
Set CurrentSearch = ParamRange.FindNext(After:=CurrentSearch)
If Not CurrentSearch Is Nothing Then
If CurrentSearch.Address = FirstSearch.Address Then Exit Do
i = i + 1
'Debug.Print to Immediate
Debug.Print i, CurrentSearch.Offset(ColumnOffset:=2).Value2
'Paste in "A" column
CurrentSearch.Offset(ColumnOffset:=-5).Value2 = CurrentSearch.Offset(ColumnOffset:=2).Value2
Else
Exit Do
End If
Loop
End If
End Sub
Links:
Range.Offset
Find last row, column or last cell
.Find and .FindNext in Excel VBA

How to match customer name column with worksheet name and return Table total

My main sheet is named as "Main Summary". This sheet has three columns.
Serial #
Customer Name
Outstanding Balance
The other sheets are named as "Salman", "Rehman", and "Islam".
Each sheet has one table in them. The table has 5 columns and a total row at the end of it.
I'm trying to match the names in "Customer Name" column with the sheets and then link the last cell of table's total row to the outstanding balance column against the customer name.
Here is what I've tried so far:
Sub CopyRows()
Dim bottomD As Integer
bottomD = Range("D" & Rows.Count).End(xlUp).Row
Dim c As Range
Dim ws As Worksheet
For Each c In Sheets("all").Range("D2:D" & bottomD)
For Each ws In Sheets ws.Activate
If ws.Name = c Then
c.EntireRow.Copy Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
End If
Next ws
Next c
End Sub
If I've understood you correctly, your solution is incredibly iterative where it doesn't need to be. Also your explanation doesn't entirely match your code. You reference Column B in your question and your code looks at Column D. You also talk about a sheet named Main Summary and your code references all
You loop through all the cells, and then the sheets as well where in fact you could just declare the sheet and use one loop
Option Explicit
Sub CopyRows()
Dim ws As Worksheet
Dim all As Worksheet
Dim rng As Range
Dim c As Range
Set all = ThisWorkbook.Sheets("Main Summary")
With all
Set rng = Range("D2:D" & .Range("D" & Rows.Count).End(xlUp).Row)
End With
For Each c In rng
' By using error handling you can avoid using a second loop
On Error GoTo ContinueLoop
Set ws = Sheets(c.Value)
On Error GoTo 0
c.Offset(0, 1).Formula = "=" & ws.ListObjects(1).Name & "[[#Totals],[Balance]]"
ContinueLoop:
Next c
End Sub

Copy/Paste multiple rows in VBA

I am attempting to do a simple copy row, paste row within a workbook. I've searched threads and tried changing my code multiple times to no avail.
The one that comes closest to working is this but it only copies a single instance of matching criteria.
I am trying to create a loop that will copy all of the rows that has a match in one of the columns.
So, if 8 columns, each row with matching value in column 7 should copy to a named sheet.
Sub test()
Set MR = Sheets("Main").Range("H1:H1000")
Dim WOLastRow As Long, Iter As Long
For Each cell In MR
If cell.Value = "X" Then
cell.EntireRow.Copy
Sheets("X").Range("A" & Rows.Count).End(xlUp).PasteSpecial
End If
If cell.Value = "Y" Then
cell.EntireRow.Copy
Sheets("Y").Range("A" & Rows.Count).End(xlUp).PasteSpecial
End If
If cell.Value = "Z" Then
cell.EntireRow.Copy
Sheets("Z").Range("A" & Rows.Count).End(xlUp).PasteSpecial
End If
If cell.Value = "AB" Then
cell.EntireRow.Copy
Sheets("AB").Range("A" & Rows.Count).End(xlUp).PasteSpecial
End If
Application.CutCopyMode = False
Next
End Sub
I like this because I need to target multiple destination sheets with different criteria but I need all rows that match criteria to copy over.
EDITED CODE IN RESPONSE TO NEW REQUEST:
The code below will copy all of the rows in Sheet Main and paste them into the corresponding worksheets based on the value in Column 7.
Do note: If there is a value in Column 7 that does NOT match to an existing sheet name, the code will throw an error. Modify the code to handle that exception.
Let me know of any additional needed help.
Sub CopyStuff()
Dim wsMain As Worksheet
Dim wsPaste As Worksheet
Dim rngCopy As Range
Dim nLastRow As Long
Dim nPasteRow As Long
Dim rngCell As Range
Dim ws As Worksheet
Const COLUMN_TO_LOOP As Integer = 7
Application.ScreenUpdating = False
Set wsMain = Worksheets("Main")
nLastRow = wsMain.Cells(Rows.Count, 1).End(xlUp).Row
Set rngCopy = wsMain.Range("A2:H" & nLastRow)
For Each ws In ActiveWorkbook.Worksheets
If UCase(ws.Name) = "MAIN" Then
'Do Nothing for now
Else
Intersect(ws.UsedRange, ws.Columns("A:H")).ClearContents
End If
Next ws
For Each rngCell In Intersect(rngCopy, Columns(COLUMN_TO_LOOP))
On Error Resume Next
Set wsPaste = Worksheets(rngCell.Value)
On Error GoTo 0
If wsPaste Is Nothing Then
MsgBox ("Sheet name: " & rngCell.Value & " does not exist")
Else
nPasteRow = wsPaste.Cells(Rows.Count, 1).End(xlUp).Row + 1
wsMain.Range("A" & rngCell.Row).Resize(, 8).Copy wsPaste.Cells(nPasteRow, 1)
End If
Set wsPaste = Nothing
Next rngCell
Application.ScreenUpdating = True
End Sub
Your current code is pasting to the same row in each sheet over and over, to the last row with a value in column A. Range("A" & Rows.Count).End(xlUp) says, roughly "go to the very bottom of the spreadsheet in column A, and then jump up from there to the next lowest cell in column A with contents," which gets you back to the same cell each time.
Instead, you could use lines of the pattern:
Sheets("X").Range("A" & Sheets("X").UsedRange.Rows.Count + 1).PasteSpecial
Where UsedRange is a range containing all of the cells on the sheet with data in them. The + 1 puts you on the following row.
You could make this a little prettier using With:
With Sheets("X")
.Range("A" & .UsedRange.Rows.Count + 1).PasteSpecial
End With