VBA to keep certain columns and remove all others - excel

As topic says I have a vba code which does the job: remove all columns of sheet "incidents" and keep only the columns with names "Status", "Name" and "Age"
But for some reason, after a few thousand rows, it does not work properly and removes the data/cells of that columns that is keeping , and also works quite slow.
There is any other way to do this? More efective? At least to not remove any cell of that columns which must remain in the sheet.
Thanks in advance (code below).
Sub Cleanup_report2()
Dim currentColumn As Integer
Dim columnHeading As String
For currentColumn = Worksheets("Incidents").UsedRange.Columns.CounT To 1 Step -1
columnHeading = Worksheets("Incidents).UsedRange.Cells(1, currentColumn).Value
'CHECK WHETHER TO KEEP THE COLUMN
Select Case columnHeading
Case "Status", "Name", "Age"
'Do nothing
Case Else
If InStr(1, _
Worksheets("Incidents").UsedRange.Cells(1, currentColumn).Value, _
"DLP", vbBinaryCompare) = 0 Then
Worksheets("Incidents").Columns(currentColumn).Delete
End If
End Select
Next
End Sub

It should be quicker to only do one delete operation:
Sub Cleanup_report2()
Dim currentColumn As Integer
Dim columnHeading As String
Dim rDelete As Excel.Range
With Worksheets("Incidents_data")
For currentColumn = .UsedRange.Columns.Count To 1 Step -1
columnHeading = .UsedRange.Cells(1, currentColumn).Value
'CHECK WHETHER TO KEEP THE COLUMN
Select Case columnHeading
Case "Status", "Name", "Age"
'Do nothing
Case Else
If InStr(1, columnHeading, "DLP", vbBinaryCompare) = 0 Then
If rDelete Is Nothing Then
Set rDelete = .UsedRange.Cells(1, currentColumn)
Else
Set rDelete = Union(rDelete, .UsedRange.Cells(1, currentColumn))
End If
End If
End Select
Next
End With
If Not rDelete Is Nothing Then rDelete.EntireColumn.Delete
End Sub

Here is my anser... hope this helps...
Sub removeColumns()
Dim rng As Range 'store the range you want to delete
Dim c 'total count of columns
Dim i 'an index
Dim j 'another index
Dim headName As String 'The text on the header
Dim Status As String 'This vars is just to get the code cleaner
Dim Name As String
Dim Age As String
Dim sht As Worksheet
Status = "Status"
Name = "Name"
Age = "Age"
Set sht = Sheets("Incidents")
sht.Activate 'all the work in the sheet "Incidents"
c = Range("A1").End(xlToRight).Column
'From A1 to the left at the end, and then store the number
'of the column, that is, the last column
j = 0 'initialize the var
For i = 1 To c 'all the numbers (heres is the columns) from 1 to c
headName = Cells(1, i).Value
If (headName <> Status) And (headName <> Name) And (headName <> Age) Then
'if the header of the column is differente of any of the options
j = j + 1 ' ini the counter
If j = 1 Then 'if is the first then
Set rng = Columns(i)
Else
Set rng = Union(rng, Columns(i))
End If
End If
Next i
rng.Delete 'then brutally erased from leaf
End Sub

Related

Loop through and copy paste values without repetition if conditions are met

Im trying to create a table that pulls data from my raw data if certain conditions are met. The code I currently have does not seem to be working.
Public Sub insert_rows()
Dim datasheet As Worksheet
Dim datasheet2 As Worksheet
Dim r As Long
Dim tableA As ListObject
Set tableA = Worksheets(Sheet7).ListObject(Preventable)
Set datasheet = Worksheets(Sheet7)
Set datasheet2 = Worksheets("Data")
With datasheet2
nr = Cells(Rows.Count, 1).End(x1up).Row
For r = 1 To nr
If Cells(r, 17) = "Y" Then
Cells(r, 16).Copy Destination:=Sheets("Sheet7").Range("B4")
End If
Next
End With
End Sub
Basically I have several worksheets and need to pull data from one of them to add to this table in another worksheet. My condition is if the Column in the raw data worksheet contains "Y", then pull cell values into the table of the other worksheet. An image below is an example of the data I want to copy and paste over:
As you can see, they are string values separated by "," and can contain duplicates.
I only want to add just the unique entries into the new table; with no repetition of cells. Anyway I could modify this code to suit those conditions?
You could try something like this:
Public Sub insert_rows()
Dim datasheet As Worksheet
Dim datasheet2 As Worksheet
Dim r As Long, i As Long, nr As Long
Dim tableStartingRow As Long, currenttableitem As Long
Dim stringvalues As Variant
Dim stringseparator As String
Dim valueexists As Boolean
tableStartingRow = 4
stringseparator = ","
Set datasheet = Worksheets("Sheet7")
Set datasheet2 = Worksheets("Data")
With datasheet
currenttableitem = .Cells(.Rows.Count, 2).End(xlUp).Row
End With
With datasheet2
nr = .Cells(.Rows.Count, 16).End(xlUp).Row
For r = 1 To nr
If .Cells(r, 17) = "Y" Then
If InStr(.Cells(r, 16), stringseparator) > 0 Then 'If value contains comma
stringvalues = Split(.Cells(r, 16), stringseparator)
For i = LBound(stringvalues) To UBound(stringvalues)
valueexists = False 'Reset boolean
For x = tableStartingRow To currenttableitem
If datasheet.Range("B" & x).Value = Trim(stringvalues(i)) Then
valueexists = True
Exit For
End If
Next x
If Not valueexists Then
currenttableitem = currenttableitem + 1
datasheet.Range("B" & currenttableitem).Value = Trim(stringvalues(i))
End If
Next i
Else
valueexists = False 'Reset boolean
For x = tableStartingRow To currenttableitem
If datasheet.Range("B" & x).Value = .Cells(r, 16).Value Then
valueexists = True
Exit For
End If
Next x
If Not valueexists Then
currenttableitem = currenttableitem + 1
datasheet.Range("B" & currenttableitem).Value = .Cells(r, 16).Value
End If
End If
End If
Next
End With
End Sub
This code will check each value of the cells and will split the contents by ",". Then compare with the content of the table to see if this value is already in there. In case it is not, it will be added, otherwise omitted.
Also, I notice the use of the Cells inside of a With statement. That was making a reference to the active worksheet. To make reference to the item in the With statement, you need to use .Cells
I hope this will help.

VBA Remove Columns and Strings in excel

I am working in a VBA Code that will remove unnecesary columns upon certain conditions
Dim keepColumn As Boolean
Dim currentColumn As Integer
Dim columnHeading As String
currentColumn = 1
While currentColumn <= ActiveSheet.UsedRange.Columns.Count
columnHeading = ActiveSheet.UsedRange.Cells(1, currentColumn).Value
'CHECK WHETHER TO KEEP THE COLUMN
keepColumn = False
If columnHeading = "Agent" Then keepColumn = True
If columnHeading = "Interval" Then keepColumn = True
If columnHeading = "Break Time" Then keepColumn = True
If columnHeading = "Staffed Time" Then keepColumn = True
If columnHeading = "Lunch Time" Then keepColumn = True
If columnHeading = "Email Time" Then keepColumn = True
If columnHeading = "System Time" Then keepColumn = True
If columnHeading = "Personal Time" Then keepColumn = True
If keepColumn Then
'IF YES THEN SKIP TO THE NEXT COLUMN,
currentColumn = currentColumn + 1
Else
'IF NO DELETE THE COLUMN
ActiveSheet.Columns(currentColumn).Delete
End If
'LASTLY AN ESCAPE IN CASE THE SHEET HAS NO COLUMNS LEFT
If (ActiveSheet.UsedRange.Address = "$A$1") And (ActiveSheet.Range("$A$1").Text = "") Then Exit Sub
Wend
The second part of the codes requires to do 2 things, removes from column A, all characters but the letters, and also in column B changes 05/04/2021 00:00 -0600 - 05/05/2021 00:00 -0601 to just 05/04/21 (meaning, removes evrything after first space), this second part does take a while and I will like to make it faster. Any suggestions?
Function
`Function cleanString(str As String) As String
Dim ch, bytes() As Byte: bytes = str
For Each ch In bytes
If Chr(ch) Like "[A-Za-z]" Then cleanString = cleanString & Chr(ch)
Next ch
End Function`
And here is when i want to run it
Dim rng As Range
For Each rng In Sheets("Sheet2").Range("A1:A5000").Cells 'adjust sheetname and range accordingly
rng.Value = cleanString(rng.Value)
Next
Dim r As Range
For Each r In Range("B2:B" & Cells(Rows.Count, "B").End(xlUp).Row).Cells.SpecialCells(xlCellTypeConstants)
r.Value = Split(r.Value, " ")(0)
Next r
Finally I will like to run the code automatically when the info is updated
I will like to make it faster. Any suggestions?
Like I mentioned, read the range into an array and then perform the cleanup. It will be superfast!
LOGIC
Find last row in the relevant column
Store the range values in array
Perform the actions on the array rather than doing it directly on the range. For example extract alpha chars or getting part of a string. Remember to prefix the date part with ' to prevent Excel from auto formatting.
CODE
Here is an example. I have commented the code so if you get stuck then simply ask.
Option Explicit
Sub Sample()
Dim wsInput As Worksheet, wsOutput As Worksheet
Dim lRow As Long, i As Long
Dim MyAr As Variant
'~~> Change this to the relevant sheet which has data
Set wsInput = Sheet1
'~~> This is where the output will be dumped.
Set wsOutput = Sheet2
With wsInput
'~~> Find last row in Col A
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Store the range values in array
MyAr = .Range("A1:B" & lRow).Value2
'~~> perform the actions on the array
For i = LBound(MyAr) To UBound(MyAr)
'~~> Extract alpha chars
MyAr(i, 1) = GetAlphaChars(MyAr(i, 1))
'~~> Get the part before string. and prefix with ' to
'~~> prevent Excel from auto formatting
If InStr(1, MyAr(i, 2), " ") Then MyAr(i, 2) = "'" & Split(MyAr(i, 2), " ")(0)
Next i
End With
'~~> Send the output
wsOutput.Range("A1").Resize(UBound(MyAr), 2).Value = MyAr
End Sub
'~~> Function to extract Alpha characters from the string
Private Function GetAlphaChars(cellVal As Variant) As String
Dim regX As Object
Set regX = CreateObject("VBScript.Regexp")
With regX
.Pattern = "[^a-zA-Z]+"
.Global = True
GetAlphaChars = .Replace(cellVal, vbNullString)
End With
End Function
IN ACTION

Check for a specific column name given a string then highlight values in the column that doesn't match given value in VBA

I need to look for a given column name for example in the picture look if the column name "FileNumber" exists. If it does exist, I want to look in the column to see if the numbers all are a given number (for example it has to be "101"); if incorrect I want to highlight that number (here, highlight "102")
How can I achieve this in VBA?
Sub FindColumns()
Dim rngToSearch As Range
Dim lookToFind As Variant
Dim iCtr As Long
Set rngToSearch = ThisWorkbook.Worksheets("Sheet").Range("A1:C1")
lookToFind = Array("Filename", "FileNumber", "Author") 'add all Column header that you want to check
With rngToSearch
For iCtr = LBound(lookToFind) To UBound(lookToFind)
If WorksheetFunction.CountIf(rngToSearch, lookToFind(iCtr)) > 0 Then ' Check if column is preset or not
MsgBox lookToFind(iCtr) & " Column Found" ' Pop-up msg if column is exist
Else
MsgBox lookToFind(iCtr) & " Column Not Found" ' Pop-up msg if column is Not Found
End If
Next
End With
End Sub
Use Application.WorksheetFunction.Match to find the column number of the name you are looking for. Then do your checkings for the columns.
Here is an example:
Option Explicit
Public Sub ValidateData()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet")
Dim ColumnNames() As Variant
ColumnNames = Array("Filename", "FileNumber", "Author") 'add all Column header that you want to check
Dim Headers As Variant 'read all headers into an array
Headers = ws.Range("A1", ws.Cells(1, ws.Columns.Count).End(xlToLeft)).Value
Dim HeaderColumn As Long 'this is the column number where the header was found
Dim ColName As Variant
For Each ColName In ColumnNames 'loop through your list of names
HeaderColumn = 0 'initialize
On Error Resume Next 'next line throws error if it does not match
HeaderColumn = Application.WorksheetFunction.Match(ColName, Headers, 0)
On Error GoTo 0 're-activate error reporting
If HeaderColumn <> 0 Then
'header name was found
MsgBox ColName & " Column found"
'perform different checks on each column
Select Case ColName
Case "FileNumber"
CheckFileNumberColumn ws.Range(ws.Cells(2, HeaderColumn), ws.Cells(ws.Rows.Count, HeaderColumn).End(xlUp))
'Case "Author" 'add other cases as needed
'CheckAuthorColumn ws.Range(ws.Cells(2, HeaderColumn), ws.Cells(ws.Rows.Count, HeaderColumn).End(xlUp))
End Select
Else
'header name was not found
MsgBox ColName & " Column not found"
End If
Next ColName
End Sub
'this is the procedure to check the FileNumber column
Private Sub CheckFileNumberColumn(DataToValidate As Range)
Dim iRow As Long
For iRow = 1 To DataToValidate.Rows.Count
If DataToValidate.Cells(iRow, 1).Value <> 101 Then
DataToValidate.Cells(iRow, 1).Interior.Color = RGB(255, 0, 0)
End If
Next iRow
End Sub

Add value from combobox onto multiple columns

I have created a combobox that has different cases seen below. The current formula works except that I would like to add a additional column that replicates the same value given to columns C and want to add it column R.
Ex. ComboBox
Select Current Month
I want to add 500 units to Column C and Column R based on the part that was searched for.
Private Sub cmdAdd_Click()
Dim irow As Long
Dim lastRow As Long
Dim iCol As String
Dim C As Range
Dim ws As Worksheet
Dim value As Long
Dim NewPart As Boolean
Set ws = Worksheets("Summary")
Set C = ws.Range("A7:A1048576").Find(What:=Me.PartTextBox.value, SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, LookIn:=xlValues, LookAt:=xlWhole)
If C Is Nothing Then
'find first empty row in database
lastRow = ActiveSheet.UsedRange.Row - 1 + ActiveSheet.UsedRange.Rows.Count
irow = lastRow + 1
NewPart = True
Else
'find row where the part is
irow = ws.Cells.Find(What:=Me.PartTextBox.value, SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, LookIn:=xlValues).Row
NewPart = False
End If
'check for a part number
If Trim(Me.PartTextBox.value) = "" Then
Me.PartTextBox.SetFocus
MsgBox "Please Enter A Part Number"
Exit Sub
End If
If Trim(Me.MonthComboBox.value) = "" Then
Me.MonthComboBox.SetFocus
MsgBox "Please Enter A Month"
Exit Sub
End If
If Trim(Me.AddTextBox.value) = "" Then
Me.AddTextBox.SetFocus
MsgBox "Please Enter A Value To Add Or Substract"
Exit Sub
End If
Select Case MonthComboBox.value
Case "Current Month"
iCol = "C" And "R"
Case "Current Month +1"
iCol = "N"
Case "Current Month +2"
iCol = "O"
Case "Current Month +3"
iCol = "P"
Case "Current Month +4"
iCol = "Q"
End Select
value = Cells(irow, iCol).value
With ws
.Cells(irow, iCol).value = value + CLng(Me.AddTextBox.value)
End With
If NewPart = True Then
ws.Cells(irow, "A").value = Me.PartTextBox.value
End If
If NewPart = True Then
ws.Cells(irow, "C").value = Me.AddTextBox.value
End If
I may recommend using an Array to store the columns.
Sub t()
Dim iCol()
Dim testStr$, myValue$
Dim iRow&
Dim ws As Worksheet
testStr = "Current Month"
Select Case testStr
Case "Current Month"
iCol() = Array("C", "R")
Case "Current Month +1"
iCol() = Array("N")
End Select
Dim i&
For i = LBound(iCol) To UBound(iCol)
myValue = Cells(iRow, iCol(i)).value ' WHAT SHEET IS THIS ON??
With ws
.Cells(iRow, iCol(i)).value = myValue + CLng(Me.AddTextbox.value)
End With
Next i
End Sub
You can add to the Case as needed. Note that you need to wrap the Next i after you're done working with a column, so it can see if there's a second one to run on.
Also, since you didn't include all the code, you may have to adjust the ranges. (note the myValue doesn't have a Sheet specified for what Cells() to use).

How to use range of column found using array as input and compare the range to a number to get output as "true" or "false" in a different column?

In the below code I found the column number of the values in the array. How to use that range to compare values to a with a variable?
Public Sub JpFee()
Dim rng As Range, rws As Long, w As Long, Str As Variant, Count As Integer, x(20) As Integer, Lt() As Variant, ht As Variant, Wdt As Variant, W8t As Variant
Dim row1, i, y As Integer
row1 = ActiveSheet.UsedRange.Rows.Count
MsgBox row1
Str = Array("length (cm)", "width (cm)", "height (cm)", "unit weight(kg)", "surface area L+W+H", "size")
For w = LBound(Str) To UBound(Str)
Set rng = Rows("1:1").Find(What:=Str(w), LookAt:=xlWhole, MatchCase:=False)
x(i) = rng.Column
i = i + 1
MsgBox rng.Column
Next w
End Sub
I would use a collection for something like this. You could also use a dictionary. (Whichever you prefer).
Here's an example of using a collection with what you're trying to do:
Sub tgr()
Dim ws As Worksheet
Dim HeaderCell As Range
Dim cHeaders As Collection
Set ws = ActiveWorkbook.ActiveSheet
Set cHeaders = New Collection
On Error Resume Next 'Collections will error if there are duplicates, this prevents that error
'Loop through each headercell
For Each HeaderCell In ws.Range("A1").CurrentRegion.Resize(1).Cells
'If the headercell contains text, add its column number to the collection and set the key to the headertext
If Len(HeaderCell.Text) > 0 Then cHeaders.Add HeaderCell.Column, CStr(HeaderCell.Text)
Next HeaderCell 'Advance the loop
On Error GoTo 0 'Clear the On Error Resume Next condition
'Now you can get the column number of a known header by referencing the header in your collection
'This will show the column number of the header "size"
'Note that the header does not need to be case sensitive, but must be the exact text
MsgBox cHeaders("size")
'So if you want to put in a value in the bottom row of a column:
ws.Cells(ws.Rows.Count, cHeaders("size")).End(xlUp).Offset(1).Value = 2
End Sub

Resources