I have big data file on excel, the file has 6930 rows and 8 columns,
the 8 column has percents (0%, 4%, 16%, 18%, 19% and etc..)
I tried to do a macro that paint all the rows that the percent in them are bigger then 18%, and it doesn't work.
The file start from row 3, so rows 1 and 2 are empty
The macro:
Sub Test_4
Dim i As Long
Dim countErr As Long
countErr = 0
i = 2
Do While Cells(i, 1) = ""
If Cells(i, 8).Value > 0.18 And IsNumeric(Cells(i, 8)) Then
Range(Cells(i, 1), Cells(i, 8)).Interior.ColorIndex = 3
countErr = countErr + 1
End If
i = i + 1
Loop
If countErr > 0 Then
Sheets("test").Select
Range("E8").Select
Selection.Interior.ColorIndex = 3
Range("D8").Select
Selection.FormulaR1C1 = countErr
Else
Sheets("test").Select
Range("E8").Select
Selection.Interior.ColorIndex = 4
Sheets("test").Range("d8") = "0"
End If
End Sub
A Do While loop might be a bad idea if Column H ever has a blank value part way down, instead you could do this (This will add conditional formatting to each line):
Given this input:
Sub testit()
Dim LastRow As Long, CurRow As Long, countErr As Long
LastRow = Range("H" & Rows.Count).End(xlUp).Row
Cells.FormatConditions.Delete
With Range("A3:H" & LastRow)
.FormatConditions.Add Type:=xlExpression, Formula1:="=$H3>0.18"
.FormatConditions(.FormatConditions.Count).SetFirstPriority
.FormatConditions(1).Interior.ColorIndex = 3
.FormatConditions(1).StopIfTrue = False
End With
countErr = 0
Dim cel As Range
For Each cel In Sheets("NAME OF SHEET").Range("H3:H" & LastRow)
If cel.Value > 0.18 Then
countErr = countErr + 1
End If
Next cel
MsgBox "There are " & countErr & " rows greater than 18%"
End Sub
Running the code gives:
Error Testing:
Sub ErrorTesting()
Dim cel As Range, countErr As Long
countErr = 0
LastRow = Range("H" & Rows.Count).End(xlUp).Row
For Each cel In Range("H3:H" & LastRow)
On Error GoTo ErrHandle
If Not IsNumeric(cel.Value) Then
MsgBox cel.Address & " is the address of the non-numeric Cell"
End If
If cel.Value > 0.18 And IsNumeric(cel.Value) Then
countErr = countErr + 1
End If
Next cel
ErrHandle:
If Not cel Is Nothing Then
MsgBox cel.Address & " is the address and " & cel.Value & " is the value of the Error Cell"
End If
MsgBox countErr
End Sub
Try this (updated for error count):
Sub test()
Count = 0
i = 2
While Not IsEmpty(Cells(i, 8))
If Cells(i, 8).Value > 0.18 Then
Range(Cells(i, 1), Cells(i, 8)).Interior.ColorIndex = 3
Count = Count + 1
End If
i = i + 1
Wend
//rows count bigger than 18% in worksheet "test"
Worksheets("test").Cells(1, 1).Value = "Rows count bigger than 18%"
Worksheets("test").Cells(1, 2).Value = Count
End Sub
Related
On the first 'For' loop line of the second chunk:
I get
Run-time error '1004'
Because this part of the code is at the end of the whole code, I moved the Dimensions and object Sets prior to the problematic lines.
I have the same 'For' loop higher in the code in Chunk 1 below.
The only difference is that in Chunk 2 the 'For'loop is for 'í' and in Chunk 2 is for 'k'.
Chunk 1:
Dim ExposureDataInput As Worksheet
Dim ManualSimulation As Worksheet
Set EDI = Sheets("ExposureDataInput")
Set MS = Sheets("ManualSimulation")
Dim i As Integer
Dim n As Integer
Dim j As Integer
For i = 2 To EDI.Range("B" & Rows.Count).End(xlUp).Row
If EDI.Range("B" & i).Value > 0 Then
n = MS.Range("A" & Rows.Count).End(xlUp).Row + 1
MS.Range("A" & n).Value = EDI.Cells(i, 1).Value
n = MS.Range("B" & Rows.Count).End(xlUp).Row + 1
MS.Range("B" & n).Value = EDI.Cells(i, 2).Value
n = MS.Range("C" & Rows.Count).End(xlUp).Row + 1
MS.Range("C" & n).Value = EDI.Cells(i, 4).Value
n = MS.Range("D" & Rows.Count).End(xlUp).Row + 1
MS.Range("D" & n).Value = EDI.Cells(i, 6).Value
n = MS.Range("E" & Rows.Count).End(xlUp).Row + 1
MS.Range("E" & n).Value = EDI.Cells(i, 8).Value
n = MS.Range("F" & Rows.Count).End(xlUp).Row + 1
MS.Range("F" & n).Value = EDI.Cells(i, 10).Value
n = MS.Range("G" & Rows.Count).End(xlUp).Row + 1
MS.Range("G" & n).Value = EDI.Cells(i, 12).Value
End If
Next i
Chunk 2:
error 424: Object Required or error 1004: Dimension Not Set.
Same Dimensions are set for 'í', 'n' & 'j' in Chunk 1.
Dim HistoricalDataandExcessReturns As Worksheet
Set HDaER = ThisWorkbook.Worksheets("HistoricalDataandExcessReturns")
Dim k As Integer
Dim y As Integer
For k = 2 To EDI.Range("B" & Rows.Count).End(xlUp).Row
If EDI.Range("B" & k).Value > 0 Then
y = HDaER.Range(Columns.Count & 1).End(xlToLeft).Column + 1
HDaER.Range(y & 1).Value = EDI.Cells(1, k).Value
y = HDaER.Range(Columns.Count & 2).End(xlToLeft).Column + 1
HDaER.Range(y & 2).Value = EDI.Cells(2, k).Value
End If
Next k
Chunk 3 with similar For loop:
For j = 2 To MS.Range("$A" & Rows.Count).End(xlUp).Row
With MS.Range("$J" & j).Borders
.LineStyle = xlContinous
.Color = vbWhite
.Weight = xlThin
End With
With MS.Range("$K" & j).Borders
.LineStyle = xlContinous
.Color = vbWhite
.Weight = xlThin
End With
With MS.Range("$L" & j).Borders
.LineStyle = xlContinous
.Color = vbWhite
.Weight = xlThin
End With
Next j
Generally I would prefer a direct link between the cells in 'MS' ws and the cells in the 'HDaER' ws row that I want to transpose to. I like the '=' approach.
I replaced 'MS' sheet with 'EDI' sheet in Chunk 1 to make it almost identical with the Rows.Count for 'i' in Chunk 2.
How can I tweak the 'For' loop to work with the '='?
You cannot use Range like that (it's column then row), use Cells instead. Plus it's xltoleft.
'For k = 2 To MS.Range("A" & Rows.Count).End(xlUp).Row
' y = HDaER.Cells(1, Columns.Count).End(xltoLeft).Column + 1
' HDaER.Cells(1, y).Value = MS.Cells(k, 1).Value
'Next k
'Avoiding a loop, think this will work
'ms.Range("A2", ms.Range("A" & ms.Rows.Count).End(xlUp)).Copy
'HDaER.Cells(1, HDaER.Columns.Count).End(xltoLeft).Offset(, 1).PasteSpecial Transpose:=True
Sub x()
Dim HDaER As Worksheet, MS As Worksheet
Set HDaER = ThisWorkbook.Worksheets("HistoricalDataandExcessReturns")
Set MS = ThisWorkbook.Worksheets("ManualSimulation")
MS.Range("A2", MS.Range("A" & MS.Rows.Count).End(xlUp)).Copy
HDaER.Cells(1, HDaER.Columns.Count).End(xlToLeft).Offset(, 1).PasteSpecial Transpose:=True
End Sub
I have three columns, one of them having all the staff list IDs, the second is having Front-Line staff IDs, The third is having the Back-office staff IDs, sometimes we change the task to some of them, to work in the different field, So His Staff ID has to disappear from Front-Line col and appear in Back-Office col instead. and Vice-Versa, and this will be done by selecting some of Column A staff, then it will loop through Col B and remove selection value(If found), then add these selected cells to Col B.
The same when we normalize, we select some staff from Col A, It should remove the staff IDs from Col B and add it to col C
All Staff | Front-line | Back-Office
15348 | 15348 | 15344
15347 | 15347 | 15345
15345 |
15344 |
What I've achieved so far.
Excuse me if my codes looks a little bit complex, that's the only way I know.
Dedicate Button (Dedicating 1st Col staffs to work as Back-office)
Dim found As Boolean
Dim i, j, mycount, dedlist As Integer
Dim firstempty As Long
With Sheets("StaffList")
firstempty = .Range("H" & .Rows.Count).End(xlUp).Row + 1
dedlist = .Range("L" & .Rows.Count).End(xlUp).Row
End With
mycount = firstempty - 1
found = False
Selection.Copy
With Sheets("StaffList")
firstempty = .Range("H" & .Rows.Count).End(xlUp).Row + 1
Cells(firstempty, 8).Select
Cells(firstempty, 8).PasteSpecial Paste:=xlPasteValues
End With
With Sheets("StaffList")
firstempty = .Range("H" & .Rows.Count).End(xlUp).Row + 1
dedlist = .Range("L" & .Rows.Count).End(xlUp).Row
End With
mycount = firstempty - 1
For i = 2 To mycount
For j = 2 To dedlist
With Sheets("StaffList")
If .Range("H" & i).Value = .Range("L" & j).Value Then
found = True
End If
End With
Next j
If found = False Then
dedlist = dedlist + 1
With Sheets("StaffList")
.Range("L" & dedlist).Value = .Range("H" & i).Value
End With
End If
found = False
Next i
' ActiveSheet.Range("$H$1:$H$500").RemoveDuplicates Columns:=1, Header:=xlYes
Range("A1").Select
Normalize Button (Normalizing 2nd Col staffs to get back working as Front-Line)
Dim CompareRange As Variant, x As Variant, y As Variant
Dim rng As Range
Dim found As Boolean
Dim i, j, mycount, dedlist As Integer
Dim firstempty As Long
With Sheets("StaffList")
firstempty = .Range("M" & .Rows.Count).End(xlUp).Row + 1
dedlist = .Range("H" & .Rows.Count).End(xlUp).Row
End With
mycount = firstempty - 1
found = False
Selection.Copy
With Sheets("StaffList")
firstempty = .Range("M" & .Rows.Count).End(xlUp).Row + 1
Cells(firstempty, 13).Select
Cells(firstempty, 13).PasteSpecial Paste:=xlPasteValues
End With
With Sheets("StaffList")
firstempty = .Range("M" & .Rows.Count).End(xlUp).Row + 1
dedlist = .Range("H" & .Rows.Count).End(xlUp).Row
End With
mycount = firstempty - 1
For i = 2 To mycount
For j = 2 To dedlist
With Sheets("StaffList")
If .Range("M" & i).Value = .Range("L" & j).Value Then
.Range("H" & j).Value = ""
End If
End With
Next j
Next i
Range("A1").Select
This is the VBA implementation of the suggestion in comment:
Option Explicit
Public Sub UpdateStaffTasks()
Const FRNT = "Front-line", BACK = "Back-Office"
Dim selRow As Variant, lrSelRow As Long, ws As Worksheet, i As Long, j As Long
Dim usdRng As Variant, lrUsdRng As Long, red As Long, blu As Long
If Selection.Cells.Count = 1 And Selection.Row = 1 Then Exit Sub
Set ws = Selection.Parent
selRow = GetSelRows(Selection): lrSelRow = UBound(selRow): red = RGB(256, 222, 222)
usdRng = ws.UsedRange: lrUsdRng = UBound(usdRng): blu = RGB(222, 222, 256)
For i = 0 To lrSelRow
For j = i + 2 To lrUsdRng
If j = Val(selRow(i)) Then
If Len(usdRng(j, 1)) > 0 And Len(usdRng(j, 2)) > 0 Then
usdRng(j, 2) = IIf(usdRng(j, 2) = FRNT, BACK, FRNT)
With ws.Cells(j, 1).Resize(, 2).Interior
.Color = IIf(usdRng(j, 2) = FRNT, red, blu)
End With
Exit For
End If
End If
Next
Next
Selection.Parent.UsedRange = usdRng
End Sub
Public Function GetSelRows(ByRef selectedRange As Range) As Variant
Dim s As Variant, a As Range, r As Range, result As Variant
If selectedRange.Cells.Count > 1 Then
For Each a In selectedRange.Areas
For Each r In a.Rows
If r.Row > 1 And InStr(s, r.Row) = 0 Then s = s & r.Row & " "
Next
Next
GetSelRows = Split(RTrim$(s)): Exit Function
Else
GetSelRows = Array(selectedRange.Row): Exit Function
End If
End Function
Before and After:
I have been trying to write a piece of vba code, so that I can find all of the duplicates in a column, highlight them in red and bring up a message box listing all those duplicated;
and I want the code to do this for column C across multiple sheets. This is essentially to replace conditional formatting, as it was slowing down the workbook about 8 seconds.
This is what I have so far, but it isn't really working.
Sub FindDuplicates()
Sheetcounter = 0
Set MyData = Worksheets("Sheet1").Range("C1:C" & Cells(Rows.Count, "C").End(xlUp).Row)
Do Until Sheetcounter = 3
Set MyUniqueList = CreateObject("Scripting.Dictionary")
MyUniqueList.RemoveAll
Range(Cells(1, 1), Cells(5000, 1)).Interior.Color = xlNone
Application.ScreenUpdating = False
MyDupList = "": MyCounter = 0
For Each Cell In MyData
If Evaluate("COUNTIF(" & MyData.Address & "," & Cell.Address & ")") > 1 Then
If Cell.Value <> "" Then
Cell.Interior.Color = RGB(255, 80, 80)
If MyUniqueList.exists(CStr(Cell)) = False Then
MyCounter = MyCounter + 1
MyUniqueList.Add CStr(Cell), MyCounter
If MyDupList = "" Then
MyDupList = Cell
Else
MyDupList = MyDupList & vbNewLine & Cell
End If
End If
End If
Else
Cell.Interior.ColorIndex = xlNone
End If
Next Cell
Application.ScreenUpdating = True
If MyDupList <> "" Then
MsgBox "The following entries have been used more than once:" & vbNewLine & MyDupList
Else
MsgBox "There were no duplicates found in " & MyData.Address
End If
Sheetcounter = Sheetcounter + 1
If Sheetcounter = 1 Then
Set MyData = Worksheets("Sheet2").Range("C1:C" & Cells(Rows.Count, "C").End(xlUp).Row)
End If
If Sheetcounter = 2 Then
Set MyData = Worksheets("Sheet3").Range("C1:C" & Cells(Rows.Count, "C").End(xlUp).Row)
End If
Loop
End Sub
you can simplify your sub like follows:
Option Explicit
Sub FindDuplicates()
Dim sheetCounter As Long
Dim myData As Range, cell As Range
Dim myUniqueList As Scripting.Dictionary
Set myUniqueList = CreateObject("Scripting.Dictionary")
For sheetCounter = 1 To 3
myUniqueList.RemoveAll
With Worksheets("Sheet00" & sheetCounter)
Set myData = .Range("C1", .Cells(.Rows.Count, "C").End(xlUp))
End With
myData.Interior.Color = xlNone
For Each cell In myData.SpecialCells(xlCellTypeConstants)
If WorksheetFunction.CountIf(myData, cell) > 1 Then
cell.Interior.Color = RGB(255, 80, 80)
If Not myUniqueList.Exists(CStr(cell)) Then myUniqueList.Add CStr(cell), myUniqueList.Count + 1
End If
Next cell
If myUniqueList.Count > 0 Then
MsgBox "The following entries have been used more than once:" & vbNewLine & Join(myUniqueList.Keys, vbNewLine)
Else
MsgBox "There were no duplicates found in " & myData.Address
End If
Next sheetCounter
End Sub
Why does the following VBA script not show any message boxes when row 4, 5 and 6 are all empty...
Sub Test()
LastRow = 40
For i = LastRow To 3 Step -1
Set myRange = Range("B" & i & ":T" & i)
If WorksheetFunction.CountA(myRange) = 0 Then
MsgBox "Empty " & Cells(i, 1).Row
Else
x = x
End If
Next
End Sub
Just test both column ranges:
Sub Test()
LastRow = 40
For i = LastRow To 3 Step -1
count = WorksheetFunction.CountA(Range("B"&i & ":D"&i))
count = count + WorksheetFunction.CountA(Range("F"&i & ":T"&i))
If count = 0 Then
MsgBox "Empty " & i
End If
Next
End Sub
edit: or build a range object which contains the two column ranges, intersect that with the last row, and move this range object in the loop. This way, you don't build the range object anew in each iteration:
Sub Test()
Dim rng As Range, colrng As Range
Dim LastRow As Long
Dim i As Long
LastRow = 40
Set colrng = Application.Union(Range("B:D"), Range("F:T"))
Set rng = Application.Intersect(colrng, Rows(LastRow))
For i = LastRow To 3 Step -1
If WorksheetFunction.CountA(rng) = 0 Then
MsgBox "Empty row: " & i
End If
Set rng = rng.Offset(-1, 0)
Next
End Sub
As good practice, always declare your variables, and use long integers for row or column indices.
Sub Test()
LastRow = 40
For i = LastRow To 3 Step -1
Set myRange = Range("B" & i & ":T" & i)
If WorksheetFunction.CountIf(myRange,"<>") = 0 Then 'count where it's not a null or empty string
MsgBox "Empty " & Cells(i, 1).Row
Else
x = x
End If
Next
End Sub
The only way I can seem to do it is a slow way:
LastRow = Range("B:Z").Find(What:="*", LookIn:=xlValues, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
LastColumn = Cells.Find(What:="*", LookIn:=xlFormulas, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
For i = LastRow To 3 Step -1
BlankRow = False
For j = 2 To LastColumn
If Cells(i, j).Value <> "" Then
Blank = False
Exit For
End If
BlankRow = True
Next j
If BlankRow = True Then
x = x
End If
Next i
I'm using this script to insert fill with rows where non-sequential is produced in a column of an excel file.
Sub InsertValueBetween()
Dim lastrow As Long
Dim gap As Long
Dim i As Long, ii As Long
Application.ScreenUpdating = False
With ActiveSheet
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = lastrow To 3 Step -1
gap = .Cells(i, "A").Value - .Cells(i - 1, "A").Value
If gap > 1 Then
.Rows(i).Resize(gap - 1).Insert
End If
Next i
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
.Cells(3, "A").Value = .Cells(2, "A").Value + 1
.Cells(2, "A").Resize(2).AutoFill .Cells(2, "A").Resize(lastrow - 1)
End With
End Sub
In addition to adding these new rows I want them to also have a specific value in column B. I'm trying to implement this but with no result.
Anybody could help me?
One way you could tackle this challenge is with a Range variable. Here is some heavily-commented code that walks through the process:
Sub InsertValueBetweenRev2()
Dim Target As Range '<~ declare the range variable
'... declare your other variables
'... do other stuff
For i = lastrow To 3 Step -1
gap = .Cells(i, "A").Value - .Cells(i - 1, "A").Value
If gap > 1 Then
.Rows(i).Resize(gap - 1).Insert
'the next line sets the range variable to the recently
'added cells in column B
Set Target = .Range(.Cells(i, 2), .Cells(i + gap - 2, 2))
Target.Value = "Cool" '<~ this line writes text "Cool" into those cells
End If
Next i
'... the rest of your code
End Sub
So, to sum it up, we know that gap - 1 rows are going to be added, and we know that the new rows are added starting at row i. Using that knowledge, we assign the just-added cells in column B to a Range then set the .value of that Range to whatever is needed.
a Better way of doing it with less variables and faster:
Sub InsRowWithText()
Dim LR As Long, i As Long
LR = Range("D" & Rows.Count).End(xlUp).row
For i = LR To 3 Step -1
If Range("D" & i).Value <> Range("D" & i - 1).Value Then
Rows(i).Resize(1).Insert
Range("D" & i).Value = "Test"
End If
Next i
End Sub
This is how i utilized it:
Sub InsRowWithText()
Dim strMsg As String, strTitle As String
Dim LR As Long, i As Long
Text = "ADD"
strMsg = "Warning: This is a Advanced Function, Continue? "
strTitle = "Warning: Activated Advanced Function "
If MsgBox(strMsg, vbQuestion + vbYesNo, strTitle) = vbNo Then
Exit Sub
Else
Sheets("SAP Output DATA").Select
If Range("D3").Value = Text Then
MsgBox "Detected That This Step Was Already Completed, Exiting."
Exit Sub
End If
application.ScreenUpdating = False
LR = Range("D" & Rows.Count).End(xlUp).row
For i = LR To 3 Step -1
If Range("D" & i).Value <> Range("D" & i - 1).Value Then
Rows(i).Resize(1).Insert
Range("D" & i).EntireRow.Interior.ColorIndex = xlColorIndexNone
Range(("A" & i), ("D" & i)).Value = Text
End If
Next i
End If
Range("D2").Select
Selection.End(xlDown).Select
ActiveCell.Offset(1).Select
Range(("A" & ActiveCell.row), ("D" & ActiveCell.row)).Value = Text 'last row doesnt get text for some reason.
ActiveCell.EntireRow.Interior.ColorIndex = xlColorIndexNone
ActiveCell.Offset(1).Select
Range(("D" & ActiveCell.row), ("E" & ActiveCell.row)).Interior.ColorIndex = 17 'purple
application.ScreenUpdating = True
Range("D3").Select
End Sub