Can anyone help me with this macro to create multiple sub totals in one column? Any help would be great. I have a group of numbers in column Y. which begins at row 16.
The data is listed on every three lines until the end of that section then there is a gap of around thirty lines then it beings again. I want to create a macro to count how many numbers >45 in each section. Put the total 2 rows below the last data point of each section. In column X on the same row place Number>45
Sub Sample()
Dim result As Long, firstrow As Long, lastrow As Long
Dim ws As Worksheet
Dim rng As Range
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
'~~> Find Lastrow in Col Y
lastrow = .Range("Y" & .Rows.Count).End(xlUp).Row
'~~> Set First row
firstrow = 16
'~~> Set your range
Set rng = .Range("Y" & firstrow & ":Y" & lastrow)
'~~> Put relevant values
.Range("x" & lastrow + 2).Value = "Total>45"
.Range("y" & lastrow + 2).Value = _
Application.WorksheetFunction.CountIf(rng, ">45")
End With
End Sub
try the below procedure
and loop backwards to ROW=1 like this:
Sub setTotals()
Dim iRow As Integer
Dim iLastRow As Integer
Dim sFormulaTargetAddress As String
iLastRow = ActiveSheet.Range("Y" & ActiveSheet.Rows.Count).End(xlUp).Row
iRow = iLastRow
Do Until iRow = 1
If Range("Y" & iRow).Value <> "" Then
'
' define the section
sFormulaTargetAddress = "Y" & Range("Y" & iRow).End(xlUp).Row & ":Y" & iRow & ""
'
' Put in the COUNTIF > 45 of the current section...
'
Range("Y" & iRow + 2).Formula = "=COUNTIF(" & sFormulaTargetAddress & ","">45"")"
' '
'Range("X" & iRow + 2).Formula = "=COUNTIF(" & sFormulaTargetAddress & ","">45"")"
Range("X" & iRow + 2).value="Numbers > 45"
'
' find the next section
iRow = Range("Y" & iRow).End(xlUp).Row
If Range("Y" & iRow) <> "" Then iRow = Range("Y" & iRow).End(xlUp).Row
Else
iRow = Range("Y" & iRow).End(xlUp).Row
End If
Loop
End Sub
HTH
Philip
Related
I have a list of about 2000 values in column A in Excel, and then a list of the start and end of value ranges in the next two columns. The range values don't correspond to the values in the first column. I want to check, for every value in column A, whether the value falls within ANY of the ranges listed in columns B and C.
So for example, in the image below, see whether A2 falls within B2-C2, B3-C3, OR B4-C4. Then the same again for A3 and A4. For each of these I want true/false to be entered in column D. The true/false value would correspond to the values in column A.
I've been trying to do this in VBA but I'm not totally confident with getting it to search the ranges. Current code is below.
Sub CheckRg()
Dim wk As Worksheet, frow As Long, i As Long
Set wk = Sheet1
frow = wk.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To frow
If wk.Range("A" & i).Value >= wk.Range("B:B").Value And wk.Range("A" & i).Value <= wk.Range("C:C").Value Then
wk.Range("D" & i).Value = "TRUE"
Else
wk.Range("D" & i).Value = "FALSE"
End If
Next i
End Sub
This formula should do the trick without VBA:
=COUNTIFS($B:$B,"<="&A2,$C:$C,">="&A2)<>0
You can use it in your code like this:
Sub CheckRg()
Dim wk As Worksheet, frow As Long, i As Long
Set wk = Sheet1
frow = wk.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To frow
With Excel.WorksheetFunction
wk.Range("D" & i).Value = .CountIfs(wk.Range("B:B"), Evaluate("""<=""" & "&A" & i), wk.Range("C:C"), Evaluate(""">=""" & "&A" & i)) <> 0
End With
Next i
End Sub
An Inefficient Double Loop
A better way to go is presented in the solution by Evil Blue Monkey.
You need to check each cell in column A against each cell pair of columns B and C which requires a second loop that slows down the operation when thousands of rows are expected.
Here's an example of how you could go about that.
Sub CheckRg()
Dim ws As Worksheet: Set ws = Sheet1
Dim lRow As Long: lRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
Application.ScreenUpdating = False
Dim i As Long
Dim j As Long
Dim MatchFound As Boolean
For i = 2 To lRow
For j = 2 To lRow
If ws.Range("A" & i).Value >= ws.Range("B" & j).Value _
And ws.Range("A" & i).Value <= ws.Range("C" & j).Value Then
MatchFound = True
Exit For
End If
Next j
If MatchFound Then
ws.Range("D" & i).Value = True
MatchFound = False
Else
ws.Range("D" & i).Value = False
End If
Next i
Application.ScreenUpdating = True
MsgBox "Range checked.", vbInformation
End Sub
I'm having an case what i don't know how to deal with that, can someone suggest or give me some idea to solve it ?
Summary: I have an Excel file with 3 columns (Name, user , password), this is an example. As you can see in column A , there are 2 cell with name jack , 1 is his user ID (row 2) , and the other is his password. I wish they can stored in the same row , sth like that cell A2 is jack , cell B2 is his user name (jck), and C2 is his pwd (123).
my code as below
Sub test()
Dim last_row As Long
Dim sh As Worksheet
Dim sh2 As Worksheet
Dim wb As Workbook
Set wb = ThisWorkbook
Set sh = wb.Sheets(1)
Set sh2 = wb.Sheets(2)
Dim rng As Range
last_row = sh.Range("A" & Rows.Count).End(xlUp).Row
last_row2 = sh2.Range("A" & Rows.Count).End(xlUp).Row
MsgBox last_row
For i = 2 To last_row - 1
For j = i + 1 To last_row
If sh.Range("A" & i).Value = sh.Range("A" & j).Value Then
If IsEmpty(Range("B" & i)) Then
sh2.Range("A" & i & ":C" & i).Value = sh.Range("A" & i & ":C" & i).Value
sh2.Range("B" & i).Value = sh.Range("B" & j).Value
End If
If IsEmpty(Range("C" & i)) Then
sh2.Range("A" & i & ":C" & i).Value = sh.Range("A" & i & ":C" & i).Value
sh2.Range("C" & i).Value = sh.Range("C" & j).Value
End If
End If
Next j
Next i
End Sub
Could you please help look ? Any assist will be appreciated.
Your main issue is that you use the same row counter for Sheet2 as you do for Sheet1. Since you will end up with half the number of rows with data in Sheet2, that will result in gaps in Sheet2. You will need a seperate row counter for Sheet2
Another issue is you have several unqualified Range references, so whether this works or not will depend on which sheet is active.
A third issue is you haven't declared all your variables.
You code, refactored
Sub test()
Dim last_row As Long
Dim last_row2 As Long
Dim sh As Worksheet
Dim sh2 As Worksheet
Dim wb As Workbook
Dim rng As Range
Dim i As Long, j As Long
Dim rw2 As Long
Set wb = ThisWorkbook
Set sh = wb.Sheets(1)
Set sh2 = wb.Sheets(2)
last_row = sh.Range("A" & sh.Rows.Count).End(xlUp).Row
last_row2 = sh2.Range("A" & sh2.Rows.Count).End(xlUp).Row
'MsgBox last_row
rw2 = 1
For i = 2 To last_row - 1
For j = i + 1 To last_row
If sh.Range("A" & i).Value = sh.Range("A" & j).Value Then
If IsEmpty(sh.Range("B" & i)) Or IsEmpty(sh.Range("C" & i)) Then
rw2 = rw2 + 1
sh2.Range("A" & rw2 & ":C" & rw2).Value = sh.Range("A" & i & ":C" & i).Value
If IsEmpty(sh.Range("B" & i)) Then
sh2.Range("B" & rw2).Value = sh.Range("B" & j).Value
ElseIf IsEmpty(sh.Range("C" & i)) Then
sh2.Range("C" & rw2).Value = sh.Range("C" & j).Value
End If
End If
End If
Next j
Next i
End Sub
Hey I just found a great code on this site which allows you to dynamically select the n bottom values of columns in a row. with the following code:
Dim LastRow, a As Long
LastRow = Cells(Rows.Count, "K").End(xlUp).Row
Range("K" & LastRow - 2 & ":K" & LastRow).Copy
My code above selects the 2 values at the bottom. Is there any way I can select the two top values of columns in a cell? I tried to do it brainless by modifying my code to
Dim LastRow, a As Long
firstRow = Cells(Rows.Count, "K").End(xlDown).Row
Range("K" & firstRow + 2 & ":K" & firstRow).Copy
However, that doesn't seem to do the job. Furthermore, in my row columns where I want to select the first 10 values there is a string/text above, how do I deal with that?
Dim Firstrow As Long
Dim RowsToCopy As Long
' First row is 2 if there is a header text, else 1.
Firstrow = 2
RowsToCopy = 2
' Copy 2 rows starting at 'Firstrow'
Range("K" & Firstrow & ":K" & Firstrow + (RowsToCopy - 1)).Copy
Please, try the next way:
Sub testFirstTwoRows()
Dim sh As Worksheet, firstR As Long
Set sh = ActiveSheet
firstR = sh.Range("K1").End(xlDown).row
If WorksheetFunction.CountA(sh.Range("K1:K" & firstR - 1)) > 0 Or _
firstR = sh.rows.count Then
firstR = 1
End If
Range("K" & firstR & ":K" & firstR + 1).Copy
End Sub
I'm trying to insert this character "-" at the beginning of each text in column F.
My F column looks like this:
BP850
BP851
BT100
GP160
GP161
I tried this code:
Option Explicit
Sub test()
Dim LastRow As Long, i As Long
Dim str As String
'Change sheet if needed
With ThisWorkbook.Worksheets("Sheet1")
'Find the last row of column F
LastRow = .Cells(.Rows.Count, "F").End(xlUp).Row
'Loop column F
For i = 1 To LastRow
'Replace the first occurance
str = Replace(.Range("F" & i).Value, "", "-", 1, 1)
.Range("F" & i).Value = str
Next i
End With
End Sub
I expect:
-BP850
-BP851
-BT100
-GP160
-GP161
As an alternative, you could try to utilize .Evaluate. This prevents the need for any loop:
Option Explicit
Sub test()
Dim LastRow As Long
Dim rng As Range
'Change sheet if needed
With ThisWorkbook.Worksheets("Sheet1")
'Find the last row of column F
LastRow = .Cells(.Rows.Count, "F").End(xlUp).Row
Set rng = .Range("F1:F" & LastRow)
rng.Value = .Evaluate("""'-""&" & rng.Address)
End With
End Sub
Instead of using replace, just concatenate "-" before str
Sub test()
Dim LastRow As Long, i As Long
Dim str As String
'Change sheet if needed
With ThisWorkbook.Worksheets("Sheet1")
'Find the last row of column F
LastRow = .Cells(.Rows.Count, "F").End(xlUp).Row
'Loop column F
For i = 1 To LastRow
'Replace the first occurance
str = "-" & .Range("F" & i).Value '<== EDIT
.Range("F" & i).Value = str
Next i
End With
End Sub
Your str = Replace(.Range("F" & i).Value, "", "-", 1, 1) has problem. Change it to following:
For i = 1 To LastRow
.Range("F" & i).Value = "-" & .Range("F" & i).Value
Next i
No need to use str variable here.
See if following approach helps.
It will also check
Cell is not blank
Cell doesn't begin with "-"
which should help in case of accidental rerun of the macro!
Option Explicit
Sub test2()
Dim LastRow As Long, i As Long
'Change sheet if needed
Application.ScreenUpdating = False
With ThisWorkbook.Worksheets("Sheet1")
'Find the last row of column F
LastRow = .Cells(.Rows.Count, "F").End(xlUp).Row
'Loop column F
For i = 1 To LastRow
If Len(.Range("F" & i).Value) > 0 And Left(.Range("F" & i).Value, 1) <> "-" Then _
.Range("F" & i).Value = "-" & .Range("F" & i).Value
Next i
End With
Application.ScreenUpdating = True
End Sub
try this, ie. add "'-" in front of the value. Note the single quote before the -
For i = 1 To lastRow
If .Range("F" & i).Value <> "" Then
If Left(.Range("F" & i).Value, 1) <> "-" Then
.Range("F" & i).Value = "'-" & .Range("F" & i).Value
End If
End If
Next i
Option Explicit
Sub test()
Dim LastRow As Long, i As Long
Dim AdditionString As String, CellString As String, CompleteString As String
AdditionString = "'-"
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 1 To LastRow
CellString = .Range("A" & i).Value
CompleteString = AdditionString & CellString
.Range("A" & i).Value = CompleteString
Next i
End With
End Sub
I am having trouble with the below code. "Backend" is the Source Sheet and "Availability" is the Target sheet. Any help is appreciated.
Sub CopyA()
Dim lr As Long, lr2 As Long, r As Long
lr = Sheets("Backend").Cells(Rows.Count, "AB").End(xlUp).Row
lr2 = Sheets("Availability").Cells(Rows.Count, "A").End(xlUp).Row
For r = lr To 2 Step -1
If Range("Backend!AB" & r).Value = "A" Then
Range("Availability!A" & lr2 + 1 & ":C" & lr2 + 1) =
Range("Backend!V" & r & ":X" & r).Value2
lr2 = Sheets("Availability").Cells(Rows.Count, "A").End(xlUp).Row
End If
Next r
End Sub
Based on your code I think you are trying to copy columns V:X from sheet Backend if column AB = A and paste the data into column A of sheet Availability.
This code achieves that:
Sub CopyData()
Dim lastRow As Long, rw As Long
lastRow = Sheets("Backend").Cells(Rows.Count, "AB").End(xlUp).Row
With Worksheets("Backend")
For rw = lastRow To 2 Step -1
If .Range("AB" & rw) = "A" Then
pasteRow = Worksheets("Availability").Cells(Rows.Count, "A").End(xlUp).Row + 1
Range("V" & rw & ":X" & rw).Copy Destination:=Worksheets("Availability").Range("A" & pasteRow & ":C" & pasteRow)
End If
Next rw
End With
End Sub
In your original code you are looping backwards with Step -1. A consequence of this is that the data pasted into Availability will be in reverse order. If you want the pasted data to appear in the order it is found on backend then use this code instead:
Sub CopyData2()
Dim copyRng As Range, cl As Range
Set copyRng = Worksheets("Backend").Range("AB2:AB" & Worksheets("Backend").Cells(Rows.Count, "AB").End(xlUp).Row)
With Worksheets("Availability")
For Each cl In copyRng
If cl = "A" Then
pasteRow = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
Worksheets("Backend").Range("V" & cl.Row & ":X" & cl.Row).Copy Destination:=.Range("A" & pasteRow & ":C" & pasteRow)
End If
Next cl
End With
End Sub