Removing blank columns/rows in VBA as part of csv save - vba

I am using the following VBA code to save each individual sheet in a .xlsx workbook into a .csv file.
Whilst the code is working well I would like to adapt the VBA code so blank columns & rows are removed from the .csv files which are being created.
Existing VBA Code:
Public Sub SaveWorksheetsAsCsv()
Dim xWs As Worksheet
Dim xDir As String
Dim folder As FileDialog
Set folder = Application.FileDialog(msoFileDialogFolderPicker)
If folder.Show <> -1 Then Exit Sub
xDir = folder.SelectedItems(1)
For Each xWs In Application.ActiveWorkbook.Worksheets
xWs.SaveAs xDir & "\" & xWs.Name, xlCSV
Next
End Sub
To remove blank rows & columns I was able to get the below JavaScript working in a .hta application, but would like to integrate this same functionality into the above VBA code.
//Remove all blank rows
for(var i = usedRng.Rows.Count; i > 0; i--){
if( xlApp.CountA(usedRng.Rows(i)) == 0 ) usedRng.Rows(i).Delete();
}
//Remove all blank columns
for(var i = usedRng.Columns.Count; i > 0; i--){
if( xlApp.CountA(usedRng.Columns(i)) == 0 ) usedRng.Columns(i).Delete();
}
How can I integrate this row/column removal code into VBA?

Use below sub-routine to delete empty row/column in the spreadsheet
Sub RemoveEmptyRowColumn()
Dim Firstrow As Long
Dim Lastrow As Long
Dim Lrow As Long
Dim CalcMode As Long
Dim ViewMode As Long
CalcMode = Application.Calculation
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
ActiveSheet.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
ActiveSheet.DisplayPageBreaks = False
Firstrow = ActiveSheet.UsedRange.Cells(1).Row
Lastrow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
FirstColumn = ActiveSheet.UsedRange.Cells(1).Column
LastColumn = ActiveSheet.UsedRange.Columns(ActiveSheet.UsedRange.Columns.Count).Column
'------------------
' Delete Empty Rows
'------------------
For Lrow = Lastrow To Firstrow Step -1
For LColumn = LastColumn To FirstColumn Step -1
With ActiveSheet.Cells(Lrow, LColumn)
If Not IsError(.Value) Then
If .Value = "" Then
DeleteRow = "Yes"
Else
DeleteRow = "No"
Exit For
End If
End If
End With
Next LColumn
If DeleteRow = "Yes" Then
ActiveSheet.Cells(Lrow, LColumn + 1).EntireRow.Delete
End If
Next Lrow
'---------------------
' Delete Empty Columns
'---------------------
For LColumn = LastColumn To FirstColumn Step -1
For Lrow = Lastrow To Firstrow Step -1
With ActiveSheet.Cells(Lrow, LColumn)
If Not IsError(.Value) Then
If .Value = "" Then
DeleteColumn = "Yes"
Else
DeleteColumn = "No"
Exit For
End If
End If
End With
Next Lrow
If DeleteColumn = "Yes" Then
ActiveSheet.Cells(Lrow + 1, LColumn).EntireColumn.Delete
End If
Next LColumn
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
End Sub

Related

Some modification regarding macro VBA code to delete row if a specific value exist

I found on this website a macro to delete row if a specific value exists:
https://www.rondebruin.nl/win/s4/win001.htm
I am trying to modify a bit this code in order to be able to enter not only manually:
• the column on which I want to do the modification (for example A)
• but also the string I want to delete.
That´s why I added manually the following datas in the code:
Dim Columnname As String
Dim DeleteStr As String
Columnname = Application.InputBox("Select Column", xTitleId, Type:=2)
DeleteStr = Application.InputBox("Delete Text", xTitleId, Type:=2)
With .Cells(Lrow, " & Columnname & ")
If .Value = " & DeleteStr & " Then .EntireRow.Delete
The problem that I have when I run the code: I come across a windows which comes up “Run-time error 13” Type mismatch…Indeed it seems there is mismatch error on the line :
With .Cells(Lrow, " & Columnname & ")
Unfortunately, I do not manage to identify where the mistake comes from. That would be fantastic if someone could help me.
Thank you so much in advance.
Xavi
Here below, please find my Code:
Sub Loop_Example()
Dim Firstrow As Long
Dim Lastrow As Long
Dim Lrow As Long
Dim CalcMode As Long
Dim ViewMode As Long
Dim Columnname As String
Dim DeleteStr As String
Columnname = Application.InputBox("Select Column", xTitleId, Type:=2)
DeleteStr = Application.InputBox("Delete Text", xTitleId, Type:=2)
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
'We use the ActiveSheet but you can replace this with
'Sheets("MySheet")if you want
With ActiveSheet
'We select the sheet so we can change the window view
.Select
'If you are in Page Break Preview Or Page Layout view go
'back to normal view, we do this for speed
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
'Turn off Page Breaks, we do this for speed
.DisplayPageBreaks = False
'Set the first and last row to loop through
Firstrow = .UsedRange.Cells(1).Row
Lastrow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
'We loop from Lastrow to Firstrow (bottom to top)
For Lrow = Lastrow To Firstrow Step -1
'We check the values in the selected column in this example
With .Cells(Lrow, " & Columnname & ")
If Not IsError(.Value) Then
If .Value = " & DeleteStr & " Then .EntireRow.Delete
'This will delete each row with the Value "DeleteStr"
'in the seleted Column, case sensitive.
End If
End With
Next Lrow
End With
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
End Sub
It's much easier to delete the rows with autofilter rather than using loops.
Sub test()
Dim Columnname As String
Dim DeleteStr As String
Columnname = Application.InputBox("Select Column", xTitleId, Type:=2)
DeleteStr = Application.InputBox("Delete Text", xTitleId, Type:=2)
With ActiveSheet
.AutoFilterMode = False
With .Range(Columnname & "1", .Range(Columnname & Rows.Count).End(xlUp))
.AutoFilter 1, DeleteStr
On Error Resume Next
.Offset(1).SpecialCells(12).EntireRow.Delete
End With
.AutoFilterMode = False
End With
End Sub
You don't need quotes around your variables:
'...
With .Cells(Lrow, Columnname)
If Not IsError(.Value) Then
If .Value = DeleteStr Then .EntireRow.Delete
'This will delete each row with the Value "DeleteStr"
'in the seleted Column, case sensitive.
End If
End With
'...
It is more efficient to delete in one go with Union of the qualifying ranges. And to loop only the necessary number of rows use the chosen column to determine the last row to determinate looping at. You can also re-write to use an efficient For Each Loop over the collection by setting a variable to hold your cells to loop over and using a For Each on that.
Option Explicit
Public Sub Loop_Example()
Dim Firstrow As Long, Lastrow As Long, Lrow As Long, CalcMode As Long, ViewMode As Long, Columnname As String
Dim DeleteStr As String, unionRng As Range, rng As Range
Columnname = Application.InputBox("Select Column", , Type:=2)
DeleteStr = Application.InputBox("Delete Text", , Type:=2)
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
With ActiveSheet
.Activate
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = .UsedRange.Cells(1).Row
Lastrow = .Cells(.Rows.Count, Columnname).End(xlUp).Row
Dim loopRange As Range: Set loopRange = .Range("C" & Firstrow & ":" & "C" & Lastrow)
For Each rng In loopRange
If rng.Value = DeleteStr Then
If Not unionRng Is Nothing Then
Set unionRng = Union(unionRng, rng)
Else
Set unionRng = rng
End If
End If
Next
End With
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
If Not unionRng Is Nothing Then unionRng.EntireRow.Delete
End Sub

Editing code to stop user from jumping from sheet to sheet

I have some code that copies data from one sheet on to another and then deletes empty rows. The code kind of works, but i sends the user from sheet to sheet while doing it. I am still new to VBA and im now sure how to achieve the result without using the select property. What I need to code to do, is move data from one sheet to another and delete empty rows when a button is clicked. I want the user to stay on the front page while the code executes. My code is below:
Sub MarkSold()
Dim LSearchRow As Integer
Dim LCopyToRow As Integer
On Error GoTo Err_Execute
'Start search in row 6
LSearchRow = 6
'Start copying data to row 6 in Sheet3 (row counter variable)
LCopyToRow = 6
While Len(Sheets("on stock").Range("B" & CStr(LSearchRow)).Value) > 0
'If value in column B = "D5", copy entire row to Sheet3
If Sheets("On stock").Range("B" & CStr(LSearchRow)).Value = Sheets("Data Entry").Range("D5") Then
'Select row in Sheet1 to copy
Sheets("On stock").Select
Rows(CStr(LSearchRow) & ":" & CStr(LSearchRow)).Select
Selection.Cut
'Paste row into Sheet2 in next row
Sheets("Turbines sold").Select
Rows(CStr(LCopyToRow) & ":" & CStr(LCopyToRow)).Select
ActiveSheet.Paste
'Move counter to next row
LCopyToRow = LCopyToRow + 1
'Go back to Sheet1 to continue searching
Sheets("On stock").Select
End If
LSearchRow = LSearchRow + 1
Wend
Dim sh As Worksheet
Dim lr As Long, i As Long
Set sh = Sheets("On stock")
With Application
.ScreenUpdating = False
.DisplayStatusBar = False
.Calculation = xlCalculationManual
.EnableEvents = False
lr = sh.Cells(Rows.Count, 1).End(xlUp).Row
For i = lr To 6 Step -1
If WorksheetFunction.CountA(Rows(i)) = 0 Then
Rows(i).EntireRow.Delete
End If
Next i
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.DisplayStatusBar = True
.ScreenUpdating = True
End With
Call setupDV
'Position on cell A3
Application.CutCopyMode = False
Sheets("Data Entry").Range("A1").Select
MsgBox "Now marked as sold!"
Exit Sub
Err_Execute:
'MsgBox "An error occurred."
End Sub
Any help is appreciated!
Just remove the .Select statement from your code and set refer your code directly to each sheet. Just like The code below:
Sub MarkSold()
Dim LSearchRow As Integer
Dim LCopyToRow As Integer
Set stock = Sheets("On stock")
Set tSold = Sheets("Turbines sold")
Set dEntry = Sheets("Data Entry")
On Error GoTo Err_Execute
'Start search in row 6
LSearchRow = 6
'Start copying data to row 6 in Sheet3 (row counter variable)
LCopyToRow = 6
While Len(Sheets("on stock").Range("B" & CStr(LSearchRow)).Value) > 0
'If value in column B = "D5", copy entire row to Sheet3
If Sheets("On stock").Range("B" & CStr(LSearchRow)).Value = Sheets("Data Entry").Range("D5") Then
'Select row in Sheet1 to copy
Sheets("On stock").Rows(CStr(LSearchRow) & ":" & CStr(LSearchRow)).Cut
'Paste row into Sheet2 in next row
Sheets("Turbines sold").Rows(CStr(LCopyToRow) & ":" & CStr(LCopyToRow)).Paste
'Move counter to next row
LCopyToRow = LCopyToRow + 1
End If
LSearchRow = LSearchRow + 1
Wend
Dim sh As Worksheet
Dim lr As Long, i As Long
Set sh = Sheets("On stock")
With Application
.ScreenUpdating = False
.DisplayStatusBar = False
.Calculation = xlCalculationManual
.EnableEvents = False
lr = sh.Cells(Rows.Count, 1).End(xlUp).Row
For i = lr To 6 Step -1
If WorksheetFunction.CountA(Rows(i)) = 0 Then
Rows(i).EntireRow.Delete
End If
Next i
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.DisplayStatusBar = True
.ScreenUpdating = True
End With
Call setupDV
Application.CutCopyMode = False
MsgBox "Now marked as sold!"
Exit Sub
Err_Execute:
'MsgBox "An error occurred."
End Sub
I've cleaned up your code a little and commented on it, so you can follow the reasoning for the changes:
Sub MarkSold()
Dim sh As Worksheet
Dim lr As Long
Dim i As Long
Dim LSearchRow As Long
Dim LCopyToRow As Long
'the variables above ought to be declared as Long instead of Integer, as there
'are more cells in Excel than there are Integer values
On Error GoTo Err_Execute
'Start search in row 6
LSearchRow = 6
'Start copying data to row 6 in Sheet3 (row counter variable)
LCopyToRow = 6
While Len(Sheets("On stock").Range("B" & LSearchRow).Value) > 0
'If value in column B = "D5", copy entire row to Sheet3
If Sheets("On stock").Range("B" & LSearchRow).Value = Sheets("Data Entry").Range("D5") Then
'Select row in Sheet1 to copy
Sheets("On stock").Rows(LSearchRow).Cut
'Paste row into Sheet2 in next row
Sheets("Turbines sold").Rows(LCopyToRow).Paste
'Move counter to next row
LCopyToRow = LCopyToRow + 1
'Go back to Sheet1 to continue searching
End If
LSearchRow = LSearchRow + 1
Wend
Set sh = Sheets("On stock")
With Application
.ScreenUpdating = False
.DisplayStatusBar = False
.Calculation = xlCalculationManual
.EnableEvents = False
lr = sh.Cells(Rows.Count, 1).End(xlUp).Row
For i = lr To 6 Step -1
If WorksheetFunction.CountA(Rows(i)) = 0 Then
Rows(i).EntireRow.Delete
End If
Next i
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.DisplayStatusBar = True
.ScreenUpdating = True
End With
Call setupDV
'Position on cell A3
Application.CutCopyMode = False
Sheets("Data Entry").Range("A1").Select
'Do you really need the select command above?
MsgBox "Now marked as sold!"
Exit Sub
Err_Execute:
'MsgBox "An error occurred."
End Sub

Loop cell in range and loop in each worksheet

Why code doesn't pick cell in next worksheet? My copy workbook contain 12 worksheets.
Sheet.Name = ("cat","rabbit","cow","sheep"...+8).
Each sheet have same headers. Col(B1:AK1)= year(1979,1980,...2014).
In another folder that I repeatedly open for pasting; File.Name = (1979.xlsx, 1980.xlsx,..,2014.xlsx).
In each sheet got 12 columns . Col(B1:M1)= ("cat","rabbit","cow","sheep"...+8).
Each cell in range loop nicely but worksheet doesn't seem so. When my code finish run, I check paste workbook having the same data from worksheet("cat"). I'm not competent with coding so please advise whenever my code can be improve.
Sub transferPict()
Dim wsC As Integer
Dim cell As Range
Dim Rng As Range
Dim j, i As Long
Dim x As String
Dim Folderpath
Dim file As String
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
wsC = ThisWorkbook.Sheets.Count
For j = 1 To wsC
i = j + 1
Set Rng = Range("B1:AK1")
For Each cell In Rng
x = cell.Value
cell.Offset(1, 0).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.CopyPicture Appearance:=xlScreen, Format:=xlPicture
Folderpath = "F:\Sony Pendrive\Data Baru\Tahun\PasteTahun\"
file = Folderpath & x & ".xlsx"
Workbooks.Open (file)
ActiveWorkbook.Worksheets("sheet1").Select
ActiveSheet.Cells(2, i).Select
ActiveSheet.Paste
ActiveWorkbook.Close saveChanges:=True
Next cell
Next j
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
At no point in your code were you specifying which worksheet you want to copy from, so it will always use the "active" sheet.
Hopefully this code will correct your issue:
Sub transferPict()
Dim wsC As Integer
Dim cell As Range
Dim Rng As Range
'Dim j, i As Long ' <--- This is equivalent to Dim j As Variant, i As Long
Dim j As Long, i As Long
Dim x As String
Dim Folderpath
Dim file As String
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
wsC = ThisWorkbook.Sheets.Count
For j = 1 To wsC
i = j + 1
Set Rng = ThisWorkbook.Sheets(j).Range("B1:AK1")
For Each cell In Rng
x = cell.Value
ThisWorkbook.Sheets(j).Range(cell.Offset(1, 0), cell.Offset(1, 0).End(xlDown)).CopyPicture Appearance:=xlScreen, Format:=xlPicture
Folderpath = "F:\Sony Pendrive\Data Baru\Tahun\PasteTahun\"
file = Folderpath & x & ".xlsx"
Workbooks.Open file
ActiveWorkbook.Worksheets("sheet1").Cells(2, i).PasteSpecial
ActiveWorkbook.Close saveChanges:=True
Next cell
Next j
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub

Splitting multi value cells in Excel into rows

I encountered a problem in excel, I'm planning to split a multi-valued cell into rows through VBA.
This is my current table
Then I'm trying to make it like this
Thank you
This will do what you want. I'm assuming your 'Emails' column is column B and you start on row 1.
Option Explicit
Const ANALYSIS_ROW As String = "B"
Const DATA_START_ROW As Long = 1
Sub ReplicateData()
Dim iRow As Long
Dim LastRow As Long
Dim ws As Worksheet
Dim iSplit() As String
Dim iIndex As Long
Dim iSize As Long
'Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
With ThisWorkbook
.Worksheets("Sheet1").Copy After:=.Worksheets("Sheet1")
Set ws = ActiveSheet
End With
With ws
LastRow = .Cells(.Rows.Count, ANALYSIS_ROW).End(xlUp).Row
End With
For iRow = LastRow To DATA_START_ROW Step -1
iSplit = Split(ws.Cells(iRow, ANALYSIS_ROW).Value2, ",")
iSize = UBound(iSplit) - LBound(iSplit) + 1
If iSize = 1 Then GoTo Continue
ws.Rows(iRow).Copy
ws.Rows(iRow).Resize(iSize - 1).Insert
For iIndex = LBound(iSplit) To UBound(iSplit)
ws.Cells(iRow, ANALYSIS_ROW).Offset(iIndex).Value2 = iSplit(iIndex)
Next iIndex
Continue:
Next iRow
Application.CutCopyMode = False
Application.Calculation = xlCalculationAutomatic
'Application.ScreenUpdating = True
End Sub

VBA - Delete either row above or row below

I have an Excel sheet with the following structure:
What I need to do is delete an entire record if either it's Type A or Type B are = 0. As an example, for record 1, I need to delete A & B because B = 0.
I have the following code:
Sub Loop_Example()
Dim Firstrow As Long
Dim Lastrow As Long
Dim Lrow As Long
Dim CalcMode As Long
Dim ViewMode As Long
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
With ActiveSheet
.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = .UsedRange.Cells(1).Row
Lastrow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
For Lrow = Lastrow To Firstrow Step -1
With .Cells(Lrow, "B")
If Not IsError(.Value) Then
If .Value = "0" Then .EntireRow.Delete
End If
End With
Next Lrow
End With
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
End Sub
Therefore, what I would like to do is add the logic to delete the entire row if the value is 0 and either the row above or below depending on its 'type'.
Thanks.
this should work.
Sub pDeleteRow()
Dim wksData As Worksheet
Dim rngCell As Range
Dim lngCounter As Long
Dim lngTotalCount As Long
Set wksData = Worksheets("Sheet1")
lngTotalCount = wksData.Range("A1").CurrentRegion.Rows.Count
lngCounter = 1
With wksData
While lngCounter <= lngTotalCount
If (UCase(Trim(.Cells(lngCounter, 2))) = "A" Or UCase(Trim(.Cells(lngCounter, 2))) = "B") And UCase(Trim(.Cells(lngCounter, 3))) = "0" Then
.Cells(lngCounter, 1).EntireRow.Delete
lngCounter = lngCounter - 1
lngTotalCount = lngTotalCount - 1
End If
lngCounter = lngCounter + 1
Wend
End With
End Sub
You can Try This:
Sub ConditionalRowDelete()
Set colA = Range("C1", Cells(Rows.Count, "C").End(xlUp))
Set colB = Range("D1", Cells(Rows.Count, "D").End(xlUp))
MsgBox colA.Rows.Count
For i = 1 To colA.Rows.Count
If colB(i) = 0 Then
If colA(i) = "A" Then
'colB(i).Select
With colB(i) 'Selection
Application.Union(.EntireRow, .Offset(1, 0).EntireRow).Delete 'Select
End With
'Selection.EntireRow.Select
'MsgBox "found A"
End If
If colA(i) = "B" Then
'colB(i).Select
With colB(i) 'Selection
Application.Union(.EntireRow, .Offset(-1, 0).EntireRow).Delete 'Select
End With
'MsgBox "found B"
End If
End If
Next
End Sub