Loop through each column and delete columns with "0" - vba

I'm not getting any errors but it's not deleting the columns with "0's". I just want to delete columns that have lots of 0's as you can read from my code. I'm not sure what could be wrong so any suggestions are welcome.
Sub Finalize()
Dim finalform As Worksheet
Dim deletename As String
Dim finalworkbook As Workbook
Dim ws As Worksheet
Dim copyrange As Range
Dim columnloop As Range
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Set finalform = Workbooks(ActiveWorkbook.Name).ActiveSheet
For a = 3 To 18
If Range("B" & a).Value <> "" Then
Workbooks.Open finalform.Range("B" & a).Value
Set finalworkbook = Workbooks(ActiveWorkbook.Name)
'Delete sheets
For b = 3 To 12
deletename = finalform.Range("D" & b).Value
If deletename <> "" Then
finalworkbook.Worksheets(deletename).Delete
End If
Next b
'Find, replace, remove
For Each ws In ActiveWorkbook.Worksheets
'Copy paste values
Set copyrange = ws.Cells
copyrange.Copy
copyrange.PasteSpecial xlPasteValues
Application.CutCopyMode = False
'Delete columns with 0
For Each columnloop In copyrange.Columns
d = 0
For c = 1 To 35
If Cells(c, columnloop.Column).Value = "0" Then
d = d + 1
End If
Next c
If d > 5 Then
columnloop.Delete
End If
Next columnloop
Next ws
End If
Next a
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub

Your loop can be replaced with more efficient methods of counting. You should always start at the extents when deleting rows or columns and work toward A1 in order that you do not skip over a column during the next incrementation.
Dim c As Long, ws As Worksheet
'Find, replace, remove
For Each ws In ActiveWorkbook.Worksheets
With ws
.UsedRange.Cells = .UsedRange.Cells.Value
'Delete columns with 0
For c = .UsedRange.Columns.Count To 1 Step -1
If Application.CountIf(.Columns(c), 0) > 5 Then
.Columns(c).EntireColumn.Delete
End If
Next c
End With
Next ws
There are several other areas that could be tweaked. Once this is running to an operational standard, consider posting it on Code Review (Excel) for further improvements.

Related

Ignoring Hidden Sheets In Arrays

I am currently producing a workbook that allows the users to print different reports for different departments.
The workbook has multiple copies of the same sheet for different phases of with the user may only need to use 1 or 2 phases out of a potential of 8 phases.
I have added a form that appears once the print has been pressed that allows users to select a report they would like to print which selects the relevant sheet before printing.
This is the code I have be trying to get to work it ignores the hidden sheets but only prints the current sheet and not the sheets visible within the array.
Sub SelectSheets()
Dim myArray() As Variant
Dim i As Integer
Dim j As Integer
j = 0
For i = 1 To Sheets.Count
If Sheets(i).Visible = True And IsInArray(Sheets(i).Name, Array("Sheet1", "Sheet2", "Sheet3")) Then
ReDim Preserve myArray(j)
myArray(j) = Sheets(i).Name
j = j + 1
End If
Next i
Sheets(myArray).Select
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant)
IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
End Function
Thank you in advance for any help.
Matt
Please take a look at this code.
Sub SelectSheets()
Const ExcludedSheets As String = "Sheet1,Sheet2,Sheet3"
Dim SelectedSheets() As String
Dim Ws As Worksheet
Dim i As Integer
With ActiveWorkbook
ReDim SelectedSheets(.Worksheets.Count)
i = -1
For Each Ws In .Worksheets
If InStr(1, ExcludedSheets, Ws.Name, vbTextCompare) = 0 Then
If Ws.Visible = xlSheetVisible Then
i = i + 1
SelectedSheets(i) = Ws.Name
End If
End If
Next Ws
If i > -1 Then
ReDim Preserve SelectedSheets(i)
.Worksheets(SelectedSheets).Select
End If
End With
End Sub
The code below would print the sheets rather than select them.
Sub PrintSelectedSheets()
' 24 Jan 2018
Const ExcludedSheets As String = "Sheet1,Sheet2,Sheet3"
Dim Ws As Worksheet
With ActiveWorkbook
For Each Ws In .Worksheets
If InStr(1, ExcludedSheets, Ws.Name, vbTextCompare) = 0 Then
With Ws
If .Visible = xlSheetVisible Then .PrintOut
End With
End If
Next Ws
End With
End Sub

Copy corresponding row VBA

I'm using a VBA to copy all the unique values from one sheet to another sheet. My VBA looks like this:
Sub UniqueListSample()
Application.ScreenUpdating = False
Dim lastrow As Long
Dim i As Long
Dim dictionary As Object
Set dictionary = CreateObject("scripting.dictionary")
Set shee = ThisWorkbook.Sheets("Sheet1")
lastrow = shee.Cells(Rows.Count, "B").End(xlUp).Row
On Error Resume Next
For i = 1 To lastrow
If Len(Sheet1.Cells(i, "B")) <> 0 Then
dictionary.Add shee.Cells(i, "B").Value, 1
End If
Next
Sheet3.Range("A3").Resize(dictionary.Count).Value = _
Application.Transpose(dictionary.keys)
Application.ScreenUpdating = True
End Sub
This takes all the unique values from Sheet 1 column B and moves them to sheet 3 column A. What I'm now trying to add is a function that takes the same rows from column C in sheet 1 and paste them into sheet 3 column B.
Is there an easy way to add this to the existing VBA?
please check this:
Option Explicit
Sub UniqueListSample()
Application.ScreenUpdating = False
Dim lastrow As Long
Dim i As Long
Dim dictionary As Object
Dim shee As Worksheet
Set dictionary = CreateObject("scripting.dictionary")
Set shee = ThisWorkbook.Sheets("Sheet1")
lastrow = shee.Cells(Rows.Count, "B").End(xlUp).Row
On Error Resume Next
For i = 1 To lastrow
If Len(Sheet1.Cells(i, "B")) <> 0 Then
dictionary.Add shee.Cells(i, "B").Value, shee.Cells(i, "c").Value
End If
Next
With Sheet3
.Range("A3").Resize(dictionary.Count).Value = _
Application.Transpose(dictionary.keys)
For i = 1 To dictionary.Count
.Cells(i + 2, 2) = dictionary(Sheet3.Cells(i + 2, 1).Value)
Next
End With
Application.ScreenUpdating = True
End Sub
If you just want one column you can utilise the Item. I prefer to avoid the "On Error" statement - the method below will not error if the same key is used (it will just overwrite).
Sub UniqueListSample()
Application.ScreenUpdating = False
Dim lastrow As Long
Dim i As Long
Dim dictionary As Object
Dim shee As Worksheet
Set dictionary = CreateObject("scripting.dictionary")
Set shee = ThisWorkbook.Sheets("Sheet1")
lastrow = shee.Cells(Rows.Count, "B").End(xlUp).Row
With dictionary
For i = 1 To lastrow
If Len(Sheet1.Cells(i, "B")) <> 0 Then
If Not (.Exists(shee.Cells(i, "B").Value)) Then
.Item(shee.Cells(i, "B").Value) = shee.Cells(i, "C").Value
End If
End If
Next
Sheet3.Range("A3").Resize(.Count).Value = Application.Transpose(.keys)
Sheet3.Range("B3").Resize(.Count).Value = Application.Transpose(.items)
End With
Application.ScreenUpdating = True
End Sub

VBA - Moving Rows to different row based on criteria is only working one at a time

I have created an excel VBA script to move rows to different sheets based on the status of the item in that row. However, when I run the code it does not always move all the items at once if there is more than one status update. I would like to make it so that if multiple rows have status updates, when I run the script they all move at once. I'm assuming it has something to do with the "if statements" but I am drawing a blank on any other ways to do it. Any help is greatly appreciated. Thanks!
Below is my code:
Sub MoveRows()
Dim xRg As Range
Dim xCell As Range
Dim A As Long
Dim B As Long
Dim C As Long
Dim D As Long
A = Worksheets("Tracking").UsedRange.Rows.Count
B = Worksheets("In Progress").UsedRange.Rows.Count
C = Worksheets("Completed").UsedRange.Rows.Count
D = Worksheets("Removed").UsedRange.Rows.Count
If B = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("In Progress").UsedRange) = 0 Then B = 0
ElseIf C = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("Completed").UsedRange) = 0 Then C = 0
ElseIf D = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("Removed").UsedRange) = 0 Then D = 0
End If
Set xRg = Worksheets("Tracking").Range("S1:S" & A)
On Error Resume Next
Application.ScreenUpdating = False
For Each xCell In xRg
If CStr(xCell.Value) = "In Progress" Then
xCell.EntireRow.Copy Destination:=Worksheets("In Progress").Range("A" & B + 1)
xCell.EntireRow.Delete
B = B + 1
ElseIf CStr(xCell.Value) = "Completed" Then
xCell.EntireRow.Copy Destination:=Worksheets("Completed").Range("A" & C + 1)
xCell.EntireRow.Delete
C = C + 1
ElseIf CStr(xCell.Value) = "Remove" Then
xCell.EntireRow.Copy Destination:=Worksheets("Removed").Range("A" & D + 1)
xCell.EntireRow.Delete
D = D + 1
End If
Next
Application.ScreenUpdating = True
End Sub
edited to add selected rows deletion
just be sure to have a header row in your "Tracking" worksheet and then AutoFilter() will make your life as easy as the following code:
Option Explicit
Sub MoveRows()
Application.ScreenUpdating = False
With Worksheets("Tracking")
With .Range("S1", .Cells(.Rows.count, "S").End(xlUp))
FilterAndCopy .Cells, "In Progress"
FilterAndCopy .Cells, "Completed"
FilterAndCopy .Cells, "Remove"
End With
End With
Application.ScreenUpdating = True
End Sub
Sub FilterAndCopy(rng As Range, filterStrng As String)
With rng '<--| reference passed 'rng' range
.AutoFilter Field:=1, Criteria1:=filterStrng '<--| filter its 1st column with passed 'filterStrng'
If Application.WorksheetFunction.Subtotal(103, .Resize(, 1)) > 1 Then '<--| if any cell filtered other than header
With .Resize(.Rows.count).Offset(1).SpecialCells(xlCellTypeVisible).EntireRow
.Copy Destination:=Worksheets(filterStrng).Cells(Rows.count, "A").End(xlUp).Offset(1) '<--|copy filtered cells (skipping headers row) to passed 'filterStrng' named worksheet 1st column from its column A first empty row after last not empty one
.Delete
End With
End If
.Parent.AutoFilterMode = False
End With
End Sub

Faster way of hiding rows in vba

Is there a faster, or more practical way of hiding rows in all sheets that have a zero value in column A? I have set up multiple macros to hide the rows, but this takes about 50-70 secs to complete any faster way?
Sub Macro14()
Dim c As Range
For Each c In Sheets("Main").Range("A200:A500")
If c.value = 0 Then
Sheets("Main").Rows(c.Row).Hidden = True
Else
Sheets("Main").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro15()
Dim c As Range
For Each c In Sheets("Elkhart East").Range("A50:A300")
If c.value = 0 Then
Sheets("Elkhart East").Rows(c.Row).Hidden = True
Else
Sheets("Elkhart East").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro16()
Dim c As Range
For Each c In Sheets("Tennessee").Range("A50:A300")
If c.value = 0 Then
Sheets("Tennessee").Rows(c.Row).Hidden = True
Else
Sheets("Tennessee").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro17()
Dim c As Range
For Each c In Sheets("Alabama").Range("A50:A300")
If c.value = 0 Then
Sheets("Alabama").Rows(c.Row).Hidden = True
Else
Sheets("Alabama").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro18()
Dim c As Range
For Each c In Sheets("North Carolina").Range("A50:A300")
If c.value = 0 Then
Sheets("North Carolina").Rows(c.Row).Hidden = True
Else
Sheets("North Carolina").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro19()
Dim c As Range
For Each c In Sheets("Pennsylvania").Range("A50:A300")
If c.value = 0 Then
Sheets("Pennsylvania").Rows(c.Row).Hidden = True
Else
Sheets("Pennsylvania").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro20()
Dim c As Range
For Each c In Sheets("Texas").Range("A50:A300")
If c.value = 0 Then
Sheets("Texas").Rows(c.Row).Hidden = True
Else
Sheets("Texas").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro21()
Dim c As Range
For Each c In Sheets("West Coast").Range("A50:A300")
If c.value = 0 Then
Sheets("West Coast").Rows(c.Row).Hidden = True
Else
Sheets("West Coast").Rows(c.Row).Hidden = False
End If
Next
End Sub
This should do it in a pretty fast way:
Sub test()
Dim x As Variant, i As Long, j(1) As Long, rngVal As Variant, rnghide As Range, rngshow As Range, sht As Object
For Each sht In ActiveWorkbook.Sheets(Array("Main", "Elkhart East", "Tennessee", "Alabama", "North Carolina", "Pennsylvania", "Texas", "West Coast"))
Set rnghide = Nothing
Set rngshow = Nothing
If sht.Name = "Main" Then
j(0) = 200
j(1) = 500
Else
j(0) = 50
j(1) = 300
End If
x = sht.Range("A1:A" & j(1)).Value
For i = j(0) To j(1)
If x(i, 1) = 0 Then
If rnghide Is Nothing Then Set rnghide = sht.Rows(i) Else Set rnghide = Union(rnghide, sht.Rows(i))
Else
If rngshow Is Nothing Then Set rngshow = sht.Rows(i) Else Set rngshow = Union(rngshow, sht.Rows(i))
End If
Next
rnghide.EntireRow.Hidden = True
rngshow.EntireRow.Hidden = False
Next
End Sub
It simply runs each sheet for the whole range and stores the rows to show/hide in seperate ranges and then change there status in one step (1 for show and 1 for hide for each sheet)
If you have any questions or get any errors just tell me (can't test it right now)
Use an array:
Sub t()
Dim sheetArray() As Variant
Dim ws&, finalRow&, startRow&
Dim c As Range
sheetArray = Array("Alabama", "North Carolina", "West Coast")
For ws = LBound(sheetArray) To UBound(sheetArray)
If sheetArray(ws) = "Main" Then
startRow = 200
finalRow = 500
Else
startRow = 50
finalRow = 300
End If
For Each c In Sheets(sheetArray(ws)).Range("A" & startRow & ":A" & finalRow)
If c.Value = 0 And Not IsEmpty(c) Then
Sheets(sheetArray(ws)).Rows(c.Row).Hidden = True
Else
Sheets(sheetArray(ws)).Rows(c.Row).Hidden = False
End If
Next c
Next ws
End Sub
Just add to that array and it should work a little faster for you. If you have a ton of sheets, and don't want to manually type them into the VBA code, you can always set the array to the range of sheet names, then just go from there. Let me know if you need help doing so.
This also assumes you don't want to just loop through the workbook. If so, you can just do For each ws in ActiveWorkbook instead of lBound()...
Edit: I added some code to check the sheet, so it'll correctly adjust your ranges.
use this :
For Each ws In ActiveWorkbook.Worksheets
For Each c In ws.Range(IIf(ws.Name = "Main", "A200:A500", "A50:A300"))
ws.Rows(c.Row).Hidden = c.Value = 0
Next
Next
if you want exclude sheet Raw,Main and Calendar :
Dim untreatedSheet As Variant
untreatedSheet = Array("Raw", "Main", "Calendar")
For Each ws In ActiveWorkbook.Worksheets
If Not (UBound(Filter(untreatedSheet, ws.Name)) > -1) Then
For Each c In ws.Range("A50:A300")
ws.Rows(c.Row).Hidden = c.Value = 0
Next
End If
Next
This will work if you select all the sheets you want filtered FIRST:
Sub HideRows()
Dim ws As Worksheet
sAddress = "A:A"
For Each ws In ActiveWindow.SelectedSheets
ws.Range(sAddress).AutoFilter Field:=1, Criteria1:="<>0"
Next ws
End Sub

Read cell for cell and create sheets

How can I read in Visual Basic from column B, sheet "control" in Excel cell for cell till an empty cell?
After that I would like to generate for every cell a new sheet with the name from cells. In this:
:
you see the content of this column, which could be different from time to time. After reading it I want to generate empty sheets with names: RW_BONDS, ... .
You can do something like this.
Private Sub CommandButton1_Click()
Dim ws As Excel.Worksheet
Dim lRow As Long
Dim lastRow As Long
'Set the sheet to read from
Set ws = Application.Sheets("control")
'Set the row to start reading at
lRow = 3
lastRow = wsOwners.Cells(wsOwners.Rows.Count, "B").End(xlUp).Row
'Loop through the rows
Do While lRow <= lastRow
If ws.Range("B" & lRow).Value <> "" then
'Add a new sheet
ActiveWorkbook.Sheets.Add Before:=Worksheets(Worksheets.Count)
'Change the name to the value of column B in the current row
ActiveWorkbook.ActiveSheet.Name = ws.Range("B" & lRow).Value
End If
'Increment your row to the next one
lRow = lRow + 1
Loop
End Sub
Sub test()
Dim i As Long
i = 1
While Len(Sheets("Control").Cells(i, 2))
Worksheets.Add.Name = Sheets("Control").Cells(i, 2): i = i + 1
Wend
End Sub
EDIT answer for the comment:
Sub test()
Dim i As Long
i = 1
With Sheets("Control")
On Error Resume Next
Application.DisplayAlerts = False
While Len(.Cells(i, 2))
If Len(Sheets(.Cells(i, 2).Value).Name) = 0 Then Else Sheets(.Cells(i, 2).Value).Delete
Worksheets.Add.Name = .Cells(i, 2): i = i + 1
Wend
Application.DisplayAlerts = True
On Error GoTo 0
End With
End Sub
set ws = worksheets("Source")
row = 1
col = "B"
Do
row = row + 1
if ws.range(col & row).text = "" then exit do
worksheets.add.name = ws.range(col & row).text
Loop
End Sub
Sub createSheets()
With Worksheets("control")
iRow = 1 'Start on the first row
While Len(.Cells(iRow, 2)) > 0 'While there isn't a blank cell
Worksheets.Add.Name = .Cells(iRow,2) 'Create/rename sheet
iRow = iRow + 1
Wend
End With
End Sub