I have many worksheets with sequential linear xy data that vary in length. The objective is to delete all rows where x data is not divisible by 50. Below is the generated macro that uses a helper column to search for integers to be deleted.
Sub Divis50()
Sheets("VERT SCALES").Select
Range("C2").Select
ActiveCell.FormulaR1C1 = _
"=IF((OR((RIGHT(RC[-2],2)=""50""),(RIGHT(RC[-2],2)=""00""))),""YES"",""NO"")"
Range("C2").Select
Selection.AutoFill Destination:=Range("C2:C6062")
'sort filtered results
Range("C2").Select
ActiveWorkbook.Worksheets("VERT SCALES").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("VERT SCALES").Sort.SortFields.Add Key:=Range("C2") _
, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("VERT SCALES").Sort
.SetRange Range("A2:C6062")
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
' scroll to first no and delete rows
Rows("123:123").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.ClearContents
'sort "A" back to consecutive numbers
Range("A2").Select
ActiveWorkbook.Worksheets("VERT SCALES").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("VERT SCALES").Sort.SortFields.Add Key:=Range("A2") _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("VERT SCALES").Sort
.SetRange Range("A2:C122")
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'delete filtered column
Columns("C:C").Select
Selection.Delete Shift:=xlToLeft
End Sub
This will delete rows that don't equal a whole number when divided by 50
Sub Button1_Click()
Dim FrstRng As Range, Lrw As Long
Dim UnionRng As Range
Dim c As Range
Lrw = Cells(Rows.Count, "A").End(xlUp).Row
Set FrstRng = Range("A2:A" & Lrw)
For Each c In FrstRng.Cells
If Int(c / 50) / (c / 50) <> 1 Then
If Not UnionRng Is Nothing Then
Set UnionRng = Union(UnionRng, c) 'adds to the range
Else
Set UnionRng = c
End If
End If
Next c
UnionRng.EntireRow.Delete
End Sub
I would recommend a helper column that flags your data appropriately. Either through formula or VB.
Then use an Autofilter to select the the flags and then delete.
try here for sample code that will delete filtered data.
http://www.mrexcel.com/forum/excel-questions/460513-visual-basic-applications-code-delete-only-rows-filtered.html
Related
I'm having a hard time trying to sort my columns. Should seem like an easy fix but I keep getting stuck. My columns are set up so that when it first populates, Column A might have values in row 3 6 9 12, Column B might have values in 1 2 3 4 and C might have values in 10 20 and 30. I'm trying to go from Column A to Column C and recursively sorting it alphabetically. I have hardcoded as a sub but everytime it gets to a column without values it ends the the program entirely. This is what I have so far
ActiveWorkbook.ActiveSheet.AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.ActiveSheet.AutoFilter.Sort.SortFields.Add Key:= _
Range("G1:G3000"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
With ActiveWorkbook.ActiveSheet.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
ActiveWorkbook.ActiveSheet.AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.ActiveSheet.AutoFilter.Sort.SortFields.Add Key:= _
Range("H1:H3000"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
With ActiveWorkbook.ActiveSheet.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
ActiveWorkbook.ActiveSheet.AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.ActiveSheet.AutoFilter.Sort.SortFields.Add Key:= _
Range("I1:I3000"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
With ActiveWorkbook.ActiveSheet.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
ActiveWorkbook.ActiveSheet.AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.ActiveSheet.AutoFilter.Sort.SortFields.Add Key:= _
Range("J1:J3000"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
With ActiveWorkbook.ActiveSheet.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
I'm calling the function on two sheets. On sheet 1 it has values up to J but on sheet 2 it only has values up to I and it gets stuck giving me an error on Sheet 2 because theres nothing on J. How couple I incorporate a for loop and how would my program know if there is/is not a value in the next column?
Column A Column B Column C Column D Column E
Row 1 Bread Fruit
Row 2 Apple OJ Coffee
Row 3 Banana Bread Lotion Water
Row 4 Soda
Row 5 Fruit Coke
Row 6 Coffee Tea
Based on your description, something like this might work for you:
Sub tgr()
Dim wb As Workbook
Dim ws As Worksheet
Dim i As Long
Set wb = ActiveWorkbook
For Each ws In wb.Sheets
Select Case ws.Name
Case "Sheet1", "Sheet2"
For i = ws.Columns("A").Column To ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
With ws.Range(ws.Cells(1, i), ws.Cells(ws.Rows.Count, i).End(xlUp))
If .Cells.Count > 1 Then
.Sort .Cells, xlAscending, Header:=xlYes
End If
End With
Next i
End Select
Next ws
End Sub
EDIT:
If your data doesn't actually have headers, try this instead:
Sub tgr()
Dim wb As Workbook
Dim ws As Worksheet
Dim rLast As Range
Dim i As Long
Set wb = ActiveWorkbook
For Each ws In wb.Sheets
Select Case ws.Name
Case "Sheet1", "Sheet2"
On Error Resume Next
Set rLast = ws.Cells.Find("*", ws.Range("A1"), xlFormulas, , xlByColumns, xlPrevious)
On Error GoTo 0
If Not rLast Is Nothing Then
For i = ws.Columns("A").Column To rLast.Column
With ws.Range(ws.Cells(1, i), ws.Cells(ws.Rows.Count, i).End(xlUp))
If .Cells.Count > 1 Then .Sort .Cells, xlAscending, Header:=xlYes
End With
Next i
End If
End Select
Next ws
End Sub
I am writing a subroutine to dynamically copy 2 columns from one sheet to another. These column lengths might change from one report to another.
Here is the code:
Sub getAnalystsCount()
Dim rng As Range
Dim dict As Object
Set dict = CreateObject("scripting.dictionary")
Dim varray As Variant, element As Variant
Set ws = ThisWorkbook.Worksheets("ReportData")
With ws
Worksheets("ReportData").Activate
Columns("E:E").Select
ActiveWorkbook.Worksheets("ReportData").AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.Worksheets("ReportData").AutoFilter.Sort.SortFields.Add Key:= _
Range("E1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("ReportData").AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
lastrow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Set First row
firstrow = 2
'~~> Set your range
Set rng = .Range("E" & firstrow & ":E" & lastrow)
varray = rng.Value
'Generate unique list and count
For Each element In varray
If dict.Exists(element) Then
dict.Item(element) = dict.Item(element) + 1
Else
dict.Add element, 1
End If
Next
End With
Set ws = ThisWorkbook.Worksheets("Analysts")
With ws
Worksheets("Analysts").Activate
'Paste report somewhere
ws.Range("A3").Resize(dict.Count, 1).Value = _
WorksheetFunction.Transpose(dict.Keys)
ws.Range("B3").Resize(dict.Count, 1).Value = _
WorksheetFunction.Transpose(dict.Items)
......
the error is in this line:
ActiveWorkbook.Worksheets("ReportData").AutoFilter.Sort.SortFields.Clear
Replace your below code
Columns("E:E").Select
ActiveWorkbook.Worksheets("ReportData").AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.Worksheets("ReportData").AutoFilter.Sort.SortFields.Add Key:= _
Range("E1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("ReportData").AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
With the below code
Columns("E:E").Select
lastrow1 = .Range("E" & .Rows.Count).End(xlUp).Row
ActiveWorkbook.Worksheets("ReportData").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("ReportData").Sort.SortFields.Add Key:=Range("E1") _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("ReportData").Sort
.SetRange Range("E2:E" & lastrow1)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
startCell = Range("A1").Address
endCell = Range("E100000").End(xlUp).Address
ActiveWorkbook.Worksheets("ReportData").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("ReportData").Sort.SortFields.Add Key:=Range("E1"), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortTextAsNumbers
With ActiveWorkbook.Worksheets("ReportData").Sort
.SetRange Range(startCell,endCell)
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Obviously this is rough, you will need to make it your own, but it will allow you to sort the E column which is what your initial code looks like it was trying to do.
The Range.Sort method can be used for a quick one column sort and discards much of the verbose code produced when recording a worksheet sort operation. Without an active AutoFilter, this is the better way to go.
Sub getAnalystsCount()
Dim el As Long, ws As Worksheet
Dim dict As Object
Dim varray As Variant
Set dict = CreateObject("scripting.dictionary")
'don't know what is in column E but this might be helpful
'dict.comparemode = vbTextCompare 'non-case-sensitive
Set ws = ThisWorkbook.Worksheets("ReportData")
With ws
'this is not necessary inside a With ... End With block
'Worksheets("ReportData").Activate
With .Range("A1").CurrentRegion
'this quick code line is all you need
.Cells.Sort Key1:=.Columns(5), Order1:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlYes
'resize to # of rows -1 × 1 column and shift 1 row down and over to column E
With .Resize(.Rows.Count - 1, 1).Offset(1, 4)
'store the raw values
varray = .Value2
End With
End With
End With 'done with the ReportData worksheet
'Generate unique list and count
'I prefer to work with LBound and UBound
For el = LBound(varray, 1) To UBound(varray, 1)
If dict.Exists(varray(el, 1)) Then
dict.Item(varray(el, 1)) = dict.Item(varray(el, 1)) + 1
Else
dict.Add Key:=varray(el, 1), Item:=1
End If
Next el
Set ws = ThisWorkbook.Worksheets("Analysts")
With ws
'this is not necessary inside a With ... End With block
'Worksheets("Analysts").Activate
'might want to clear the destination cell contents first if there is something there
if application.counta(.Range("A3:B3") = 2 then _
.Range("A3:B" & .Cells(Rows.Count, "B").End(xlUp).Row).ClearContents
'Paste report somewhere
.Range("A3").Resize(dict.Count, 1).Value = _
WorksheetFunction.Transpose(dict.Keys)
.Range("B3").Resize(dict.Count, 1).Value = _
WorksheetFunction.Transpose(dict.Items)
End With 'done with the Analysts worksheet
End Sub
I prefer to work with the LBound and UBound functions to determine the scope of an array.
When you are inside a With ... End With statement, use the . to note the parent worksheet and discard the Range .Activate method and ws variable.
I am trying to calculate the ratio between the values in 2 columns and put it to a 3rd column of my spreadsheet.
I am unable to figure out how do I write it over a loop in a macro and what function to use there.
I have values in columns A and B. I am trying to pull the ratio of the 2 columns in the column C, it should contain A/B.
This is what I did.
Sub Engagement_Ratio()
Range("Z1").Select
ActiveCell.FormulaR1C1 = "Engaged User Rate"
Range("Z2").Select
ActiveCell.FormulaR1C1 = "=(RC[-12]/RC[-15])"
Range("Z2").Select
Selection.AutoFill Destination:=Range("Z2:Z154")
Range("Z2:Z154").Select
ActiveWindow.SmallScroll Down:=-27
End Sub
How do I make the range of cells dynamic? so that it does it only for the range of cells that have values. How do I put something like a count on it.
Assuming that column A is populated to the bottom of your data:
Sub Test2()
Dim LastRow As Integer
LastRow = ActiveSheet.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious, After:=[A1]).Row
Range("Z1").Value = "Engaged User Rate"
For i = 2 To LastRow
If Cells(i, 14).Value > 0 Then Cells(i, 26).Value = Cells(i, 14).Value / Cells(i, 11).Value
Next i
ActiveSheet.sort.SortFields.Clear
ActiveSheet.sort.SortFields.Add Key:=Range("Z2:Z" + CStr(LastRow)) _
, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal 'sort by sort code
With ActiveSheet.sort
.SetRange Range("A1:Z" + CStr(LastRow))
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
This is what I did.
Sub Engagement_Ratio()
Range("Z1").Select
ActiveCell.FormulaR1C1 = "Engaged User Rate"
Range("Z2").Select
ActiveCell.FormulaR1C1 = "=(RC[-12]/RC[-15])"
Range("Z2").Select
Selection.AutoFill Destination:=Range("Z2:Z154")
Range("Z2:Z154").Select
ActiveWindow.SmallScroll Down:=-27
End Sub
How do I make the range of cells dynamic? so that it does it only for the range of cells that have values. How do I put something like a count on it.
I'm trying to combine two functions. I have a VBA script which goes through a set range and sorts all the text column by column alphabetically.
Sub SortIndividualRows()
' Sorts rows within a list from A-Z
' Run Clean all first to avoid sorting blanks
' Set maximum range to avoid sorting too many rows
Dim rngFirstRow As Range
Dim rng As Range
Dim ws As Worksheet
Application.ScreenUpdating = False
Set ws = ActiveSheet
Set rngFirstRow = ws.Range("A1:NS1")
For Each rng In rngFirstRow
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=rng, Order:=xlAscending
'assuming there are no blank cells..
.SetRange ws.Range(rng, rng.Range("A87").End(xlUp))
.Header = xlYes
.MatchCase = False
.Apply
End With
Next rng
Application.ScreenUpdating = True
End Sub
I'd like to combine this with a script to then sort each column by color. I recorded a macro when I sorted manually and looked at the code the recording generated. I'm trying to figure out how I could take the generated code and combine it with the above function.
Sub sortColor()
'
' sortColor Macro
' Goes through a range of selected cells and sorts by color, setting green cells (matches) above those with no match (red text)
'
'
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range("F4:F88"), _
xlSortOnCellColor, xlAscending, , xlSortNormal).SortOnValue.Color = RGB(198, _
239, 206)
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("F3:F88")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Just to clarify, you want to run one module then the other straight away afterwards? or do you want the action of the second module to run each time the for loop completes?
To run one directly after the other:
Sub SortIndividualRows()
' Sorts rows within a list from A-Z
' Run Clean all first to avoid sorting blanks
' Set maximum range to avoid sorting too many rows
Dim rngFirstRow As Range
Dim rng As Range
Dim ws As Worksheet
Application.ScreenUpdating = False
Set ws = ActiveSheet
Set rngFirstRow = ws.Range("A1:NS1")
For Each rng In rngFirstRow
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=rng, Order:=xlAscending
'assuming there are no blank cells..
.SetRange ws.Range(rng, rng.Range("A87").End(xlUp))
.Header = xlYes
.MatchCase = False
.Apply
End With
Next rng
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range("F4:F88"), _
xlSortOnCellColor, xlAscending, , xlSortNormal).SortOnValue.Color = RGB(198, _
239, 206)
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("F3:F88")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Application.ScreenUpdating = True
End Sub
To run the second module each time the for loop completes:
Sub SortIndividualRows()
' Sorts rows within a list from A-Z
' Run Clean all first to avoid sorting blanks
' Set maximum range to avoid sorting too many rows
Dim rngFirstRow As Range
Dim rng As Range
Dim ws As Worksheet
Application.ScreenUpdating = False
Set ws = ActiveSheet
Set rngFirstRow = ws.Range("A1:NS1")
For Each rng In rngFirstRow
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=rng, Order:=xlAscending
'assuming there are no blank cells..
.SetRange ws.Range(rng, rng.Range("A87").End(xlUp))
.Header = xlYes
.MatchCase = False
.Apply
End With
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range("F4:F88"), _
xlSortOnCellColor, xlAscending, , xlSortNormal).SortOnValue.Color = RGB(198, _
239, 206)
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("F3:F88")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Next rng
Application.ScreenUpdating = True
End Sub
It's been a while since I have used VBA on Excel.
I want to alphabetize the contents of each column on the sheet.
This is what I have:
Range("A1").Select
Range("A1:A19").Select
ActiveWorkbook.Worksheets("Sheet2").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet2").Sort.SortFields.Add Key:=Range("A1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet2").Sort
.SetRange Range("A1:A19")
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Range("B1").Select
End Sub
How can I make this into a for loop that keeps going as long as the range is active?
Like this?
Option Explicit
Sub sample()
Dim i As Long
With Sheets("Sheet1")
For i = 1 To .UsedRange.Columns.Count
.Columns(i).Sort Key1:=.Cells(1, i), Order1:=xlAscending, _
Header:=xlGuess, OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
Next i
End With
End Sub
Here you go. This code assumes your data is laid out in some type of table format. Also, it assumes you want the entire column sorted (including blanks and such). If you want to make the range more specific or just set it with a hard reference adjust the code where I commented.
Sub sortRange()
Dim wks As Worksheet
Dim loopRange As Range, sortRange As Range
Set wks = Worksheets("Sheet1")
With wks
'can change the range to be looped, but if you do, only include 1 row of the range
Set loopRange = Intersect(.UsedRange, .UsedRange.Rows(1))
For Each cel In loopRange
Set sortRange = Intersect(cel.EntireColumn, .UsedRange)
With .Sort
.SortFields.Clear
.SortFields.Add Key:=sortRange
.SetRange sortRange
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Next
End With
End Sub