I have a code that searches an excel fill for the word distance, takes the value of the cell next to it, paste it into a new cell, then sums all the cells up. Which works great, but i now need to find a way to only sum ever even row number. Does that make sense?
Sub Distance_Check()
Dim DistanceCheck As String
Dim DistanceNumber As String
Dim DistanceSum As String
Dim DistanceTotal As String
DistanceCheck = MsgBox("Would you like to check the distance?", vbYesNo)
If DistanceCheck = vbYes Then
If IsArray(fname) Then Workbooks.OpenText fname(1)
i = 1
findStr = "Distance"
Set foundCel = Range("A:A").Find(what:=findStr)
If Not foundCel Is Nothing Then
firstAddress = foundCel.Address
Do
Range("J" & i).Value = foundCel.Offset(0, 1).Value
Set foundCel = Range("A:A").FindNext(foundCel)
i = i + 1
Loop While Not foundCel Is Nothing And foundCel.Address <> firstAddress
End If
Set wkbSourceBook = ActiveWorkbook
DistanceNumber = i - 2
DistanceSum = WorksheetFunction.Sum(Range(Cells(2, 15), (Cells(DistanceNumber + 1, 15))))
DistanceTotal = DistanceSum / DistanceNumber
If DistanceNumber = Cells(2, 12) Then
MsgBox ("No error found wihin distance")
Else
MsgBox ("Error found with distance")
End If
Else
End If
Call Save_Data
End Sub
Would the way youd go about this be using a for loop on the
cells(DistanceNumber(j,+1)
Where j = 0,
j = j +2 ,
Until j > DistanceNumber,
Would that work? If so how would you go about it?
Thanks
A quick way to step through a loop in the desired increments is to use the Mod operator which divides two numbers and returns any remainder (e.g. 7 mod 2 = 1, as two sixes fit into seven, leaving one).
You can use the row property of the range you identify with the Find method, and since you want to jump by two the modulo should be zero:
If foundcel.Row Mod 2 = 0 Then Range("J" & i).value = foundcel.Offset(0, 1).Value
That said, there is a 'built in' way to step through a loop if using a For loop like this
For x = 2 to 10 Step 2
' Do stuff
Next x
You can also use this method to step backwards, e.g.
For x = 100 to 0 Step -10
' Do stuff backwards!
Next x
Related
I have two tables. One table is called DRData (Blad3), other table is CheckData (Blad2). EANCODE is Column J for DRData, and Column A for Checkdata.
I want to check whether CheckData.EANCODE is present in DRData.EANCODE. If so; delete that row from CheckData.
I tried several things, but no success yet. The code I have written now is as follows:
Sub FindEAN()
Dim i As Long
Dim x As Long
x = 1 'Start on first row
EANtoFind = Blad2.Range("A" & x).Value
For i = 1 To 99999 '
If Blad3.Cells(i, 1).Value = EANtoFind Then
Blad2.Range("A" & x).EntireRow.Delete
Else: x = x + 1
End If
Next i
End Sub
When the EANCODE is not present, I want to hop over a row to check that code. I want to end with a list in CheckData where all the EANCODE values that are not in DRData are shown.
With the code above, only the first row is getting deleted and now I'm stuck how to get this to loop. Including the x+1 to get to the next row.
First you have to clarify that your problem is a little bit complicated. You have to pay attention to indexes when deleting rows
To do that, you have to point the the maximal number of line to optimize your loop
A simple way to do that, is to use predefined search function, and edit your code a little bit.
My favorite is Application.match(), which takes 3 parameters :
Value to look for
Array where you look (in our case the column J of Blad3 or position 10)
0 : exact match
For more details, see the documentation
https://learn.microsoft.com/fr-fr/office/vba/api/excel.worksheetfunction.match
An example of code which works is like the following
Sub FindEAN()
Dim x As Long
x = 1 'Start on first row
maxline = Blad2.Range("A" & Rows.count).End(xlUp).row
While x <= maxline '
EANtoFind = Blad2.Range("A" & x).Value
If Not IsError(Application.Match(EANtoFind, Blad3.Columns(10), 0)) Then
Blad2.Range("A" & x).EntireRow.Delete
maxline = maxline - 1
Else
x = x + 1
End If
Wend
End Sub
I want to automate a calculation for a measurement data Excel file.
While I made the function work, I could only figure out how to do that for one row at a time. The calculation is specific to the data on every row.
I thought I could change the Range("J3") value to Range("J3:J52") for a capacity of 50 calculations.
How do I make the function calculate for every row, separately, using the data of said specific row?
It doesn't matter if it runs for all 50 rows or if I have to figure out some loop function to find how many rows to calculate for, as long as one button press in the end will make the magic happen.
I have included a screenshot of the sheet for reference, the main calculation is done in Excel, but what this is doing is choosing the correct option out of a few different correction calculations and explaining to the user why.
I think there are some unnecessary Dim lines at the start but if it runs, I wasn't going to remove them.
'The main function, activated by a simple button Sub'
Function ISO16032()
'DeltaL Range'
Dim DeltaL As Range
Set DeltaL = Range("F3")
'Result is the corrected value in G column'
Dim Result As Long
'Note is the calc note in H column'
Dim Note As String
'X is the DeltaL between noise and background noise'
Dim x As Long
x = Range("F3").Value
Select Case Range("F3").Value
'No correction when X = > 10'
Case 10.6 To 200
Result = Range("J3")
Range("G3").Value = Result
Note = "No correction"
Range("H3").Value = Note
'Correction according to ISO16032 when X = between 4 and 10'
Case 3.6 To 10.5
Result = Range("K3")
Range("G3").Value = Result
Note = "Correction per ISO16032"
Range("H3").Value = Note
'Maximal correction value set to 2,2 dB if X < 4'
Case 0.1 To 3.5
Result = Range("L3")
Range("G3").Value = Result
Note = "Correction limit set to 2,2 dB"
Range("H3").Value = Note
'If x = < 0, the measurement is invalid'
Case Else
Note = "Repeat measurement!"
Range("H3").Value = Note
End Select
End Function
Hi and welcome to stackoverflow, I think that a simple loop, with the addition of an argument to your ISO function allows you to solve your problem like this
Sub Looping()
For i = 3 To 52
' Convert i to String because we need to concatenate with the letter F, G, H...
Call ISO16032(CStr(i))
Next
End Sub
Function ISO16032(Cell_X)
'DeltaL Range'
Dim DeltaL As Range
Set DeltaL = Range("F" + Cell_X)
'Result is the corrected value in G column'
Dim Result As Long
'Note is the calc note in H column'
Dim Note As String
'X is the DeltaL between noise and background noise'
Dim x As Long
x = Range("F" + Cell_X).Value
Select Case Range("F" + Cell_X).Value
'No correction when X = > 10'
Case 10.6 To 200
Result = Range("J" + Cell_X)
Range("G" + Cell_X).Value = Result
Note = "No correction"
Range("H" + Cell_X).Value = Note
'Correction according to ISO16032 when X = between 4 and 10'
Case 3.6 To 10.5
Result = Range("K" + Cell_X)
Range("G" + Cell_X).Value = Result
Note = "Correction per ISO16032"
Range("H" + Cell_X).Value = Note
'Maximal correction value set to 2,2 dB if X < 4'
Case 0.1 To 3.5
Result = Range("L" + Cell_X)
Range("G" + Cell_X).Value = Result
Note = "Correction limit set to 2,2 dB"
Range("H" + Cell_X).Value = Note
'If x = < 0, the measurement is invalid'
Case Else
Note = "Repeat measurement!"
Range("H" + Cell_X).Value = Note
End Select
End Function
EDIT: think indented your code like I did to make it more readable too (or like #Darren Bartrup-Cook did when editing your question)
This is more of an example of how to calculate each row.
Just getting your code to work across multiple rows.
Cells
With...End With Statement
'No need for Sub to call function that doesn't return anything.... just write a sub.
Public Sub ISO16032()
Dim LastRow As Long
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, 10).End(xlUp).Row
Dim RowCounter As Long
Dim Result As Long
Dim Note As String
'Only calculate if there is data in rows 3 onwards.
If LastRow >= 3 Then
'Reset results on each pass.
'Assuming -1 is an impossible answer so code knows
'not to put anything on Case Else.
Result = -1
Note = ""
'Cycle through each row and calculate.
For RowCounter = 3 To LastRow
Select Case .Cells(RowCounter, 6) 'Look at column F(column 6) on each row.
Case 10.6 To 200
Result = .Cells(RowCounter, 10)
Note = "No corrections."
Case 3.6 To 10.5
Result = .Cells(RowCounter, 11)
Note = "Correction per ISO16032"
Case 0.1 To 3.5
Result = .Cells(RowCounter, 12)
Note = "Correction limit set to 2,2 dB"
Case Else
Note = "Repeat measurement!"
End Select
'Place results on sheet.
.Cells(RowCounter, 7) = IIf(Result >= 0, Result, "")
.Cells(RowCounter, 8) = Note
Next RowCounter
End If
End With
End Sub
I am trying to print out "OK" value if the statements same value with "NumberPallete" but my code doesn't work right.
I have two conditions to compare from one cell value ["54# / 221"]. The first condition value for "SeriesNumber" is [88] and then the Second condition value for "NumberPallete" is [221#]. I am using looping for "SeriesNumber" and "NumberPallete" to find the value because I have long data in the table sheet.
and then from the different sheets using looping too, I am starting with the First condition checks "SeriesNumber" value if the value is right, then check the second condition from "NumberPallete" value, in this condition, I want a print out "ok" value but "ok" value doesn't print out.
I am sorry, my English is poor. I'm trying my best to explain. Please help me.
Dim NumberPallete As String
Dim SeriesNumber As String
Dim I As Long
Dim j As Long
Dim z As Long
i = Cells(Rows.Count, 15).End(xlUp).Row
For j = 6 To i
'Cells(j, 20).Value = Right(Cells(j, 15).Value, Len(Cells(j, 15)) - InStr(1, Cells(j, 15).Value, "/"))
SeriesNumber = Right(Cells(j, 15).Value, Len(Cells(j, 15)) - InStr(1, Cells(j, 15).Value, "/"))
'Cells(j, 21).Value = Left(Cells(j, 15).Value, Len(Cells(j, 15)) - InStr(1, Cells(j, 15).Value, "/"))
NumberPallete = Left(Cells(j, 15).Value, Len(Cells(j, 15)) - InStr(1, Cells(j, 15).Value, "/"))
If SeriesNumber = 221 Then
For z = 4 To 250
If Worksheets("AAA").Cells(z, 2).Value = NumberPallete Then
Worksheets("AAA").Cells(z, 6).Value = "OK"
End If
Next z
Else
MsgBox ("Not OK")
End If
Next j
I may not have fully understood what you are trying to do but the code below is doing something and, hopefully, it can be fixed to do what you want.
Sub FindPalletNumber()
' 062
' you can find code to enter 2 values with input boxes at this link:-
' https://stackoverflow.com/questions/62651211/vba-excel-search-in-excel-specific-word-and-delete-all-rows-who-does-not-have-t
Dim Snum As Integer ' serial number
Dim Pnum As Integer ' pallet number
Dim Txt As String ' message text
Snum = 221 ' number only
Pnum = 54 ' no # sign, no brackets
If MarkOK(Snum, Pnum) Then
Txt = "Found and marked."
Else
Txt = "No match found."
End If
MsgBox Txt, vbInformation, "Action report"
End Sub
Private Function MarkOK(Snum As Integer, _
Pnum As Integer) As Boolean
' 062
' return True if found and marked
Const Pallet As Long = 0 ' element of array Nums
Const Serial As Long = 1 ' element of array Nums
Dim Nums() As String ' split cell pattern "54# / 221"
Dim Done As Boolean ' True if found
Dim R As Long ' loop counter: Row in ActiveSheet
Dim R2 As Long ' loop counter: Row in Ws("AAA")
For R = 6 To Cells(Rows.Count, 15).End(xlUp).Row
Nums = Split(Cells(R, 15).Value, "/")
' Nums(Pallet) = "54# ", Nums(Serial) = " 221"
If Val(Nums(Serial)) = Snum Then
With Worksheets("AAA")
For R2 = 4 To .Cells(.Rows.Count, 2).End(xlUp).Row
If .Cells(R2, 2).Value = Trim(Nums(Pallet)) Then
.Cells(R2, 6).Value = "OK"
Done = True
Exit For
End If
Next R2
End With
End If
If Done Then Exit For ' stop search if found
Next R
MarkOK = Done
End Function
In the first procedure the Pallet and Serial numbers should be set (Pnum and Snum). Then, when you run that procedure, it will call the other one which reports back whether a match was found or not. I have added a link where you can find code to get the two values from Input boxes, if that is what you need.
The function looks for the serial number in the ActiveSheet. If found, it looks for the pallet number in Sheet("AAA"). This is confusing because it looks for the pallet number found in the ActiveSheet, not the pallet number specified in the search. The pallet number in the search specs ends up not being used at all. Perhaps it's not needed.
Anyway, when the pallet is found the row is marked and the search terminates. If the pallet number isn't found the loop in the ActiveSheet is continued to look for another instance of the serial number. Note that the code is not enabled to find multiple pallets with the same serial number.
My code loops through rows with data on one master-sheet and updates different sheets based on the category of the data on each row. When I run the macro, I can see the information temporarily flash where it should be pasted on the worksheet before disappearing. This does not happen where I have used the same copy/paste command before.
The beggining two loops with WOB and ROP will paste correctly while the custom loop does not. I have also tried making the Select Case into several elseif statements which has the same non-working result.
Sub SortData()
Dim Datasheet As Worksheet
Dim ROPsheet As Worksheet 'Rate of Penetration
Dim Customsheet As Worksheet
Dim WOBsheet As Worksheet 'Weight on Bit
Dim i As Long 'Used as counter to loop through compiled data sheet
Dim j As Long 'Used as counter for each Limiter tested
Dim LastRowCount As Long 'Finds number of rows for ending loop
Dim Limiter As String 'These are WOB, ROP, Custom ect.
Dim DepthCheck As Double 'Checks depth on individual limiter sheet with depth on data sheet
Dim DatetCheck As String 'Checks date on individual limiter sheet with depth on data sheet
Dim Depth As Double 'depth from data sheet
Dim Datet As String 'date from limiter sheet
Dim y As Double 'Used to progress through rows
Set Datasheet = Worksheets("Data")
Set ROPsheet = Worksheets("ROP")
Set Customsheet = Worksheets("Custom")
Set WOBsheet = Worksheets("WOB")
y = 1
i = 1
'_____________________________________Working_Code_Below__________________________________________________________
'Arbitrary Count for testing
For i = 1 To 100
y = y + 1
Limiter = Worksheets("Data").Cells(y, 2).Value
Depth = Worksheets("Data").Cells(y, 5).Value
Datet = Worksheets("Data").Cells(y, 6).Value
'WOB
If Limiter = "WOB" Then
j = 1
LastRowCount = WOBsheet.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Count
For j = 1 To LastRowCount
DepthCheck = Worksheets("WOB").Cells(j + 1, 5).Value
DatetCheck = Worksheets("WOB").Cells(j + 1, 6).Value
If DepthCheck <> Depth Or DatetCheck <> Datet Then
If j = LastRowCount Then
Datasheet.Range(Datasheet.Cells(y, 2), Datasheet.Cells(y, 13)).Copy Sheets("WOB").Cells(j + 1, 2)
GoTo EndLast
End If
Else
GoTo EndLast
End If
Next j
Else
GoTo ROPStart
End If
ROPStart:
If Limiter = "ROP" Then
j = 1
LastRowCount = ROPsheet.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Count
For j = 1 To LastRowCount
DepthCheck = Worksheets("ROP").Cells(j + 1, 5).Value
DatetCheck = Worksheets("ROP").Cells(j + 1, 6).Value
If DepthCheck <> Depth Or DatetCheck <> Datet Then
If j = LastRowCount Then
Datasheet.Range(Datasheet.Cells(y, 2), Datasheet.Cells(y, 13)).Copy Sheets("ROP").Cells(j + 1, 2)
GoTo EndLast
End If
Else
GoTo EndLast
End If
Next j
Else
GoTo CustomStart
End If
CustomStart:
j = 1
LastRowCount = Customsheet.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Count
Select Case Limiter
Case "WOB", "Balling", "RPM", "Vibrations", "Torque", "Buckling", "Differential Pressure", "Flow Rate", "Pump Pressure", "Well Control", "Directional", "Logging", "ROP"
GoTo EndLast
Case Else
For j = 1 To LastRowCount
DepthCheck = Worksheets("Custom").Cells(j + 1, D).Value
DatetCheck = Worksheets("Custom").Cells(j + 1, dt).Value
If DepthCheck <> Depth Or DatetCheck <> Datet Then
If j = LastRowCount Then
Datasheet.Range(Datasheet.Cells(y, 2), Datasheet.Cells(y, 13)).Copy Sheets("Custom").Cells(j + 1, 2)
GoTo EndLast
End If
Else
GoTo EndLast
End If
Next j
End Select
EndLast:
Next i
End Sub
No error messages appear.
PS. This is my first post so sorry if formatting is weird.
Welcome to SO and congratulations on your first post. One of these days I'll be there with you, I'm just looking for the perfect question that's all. Lack of courage has nothing to do with it, really, scout's honor. Pinky promise!
I've tried following your code and struggle quite a bit because of the nonlinear flow. The problem you describe sounds like the data is written and then overwritten. This would typically be caused by a superfluous loop, in your case it may be induced by GoTo.
Touching on the comments about finding the row count; this is a surprisingly nuanced subject with many different answers and the correct one dependent on your circumstances and needs. Most of the time I can use UsedRange, as in Sheet1.UsedRange.Rows.Count; but I predominately work on spreadsheets I maintain and keep things as tight as my knowledge allows at the time. I don't remember how long ago I bookmarked this website but I swear I used it daily for a couple months straight: OZGrid Excel Ranges And of course Chip Pearson is worth a call out CPearson Last Used Cell
Please take this last bit as constructive criticism and have a good laugh. When you try to follow this code and get lost, take a step back, look at your code, and find the same pattern - and stop doing it. Break the habit and break the habit hard. Some people, myself included have a near visceral reaction when trying to debug spaghetti code. Try to write linearly top down. You'll find that you understand your own code better, it's easier to keep track of your thoughts, and transfer those thoughts into code. It's a win, win, win situation. GoTo's are almost entirely unnecessary and really impede the progress of others trying to help; using one here or there can be a handy little shortcut in a 5 line function but are best avoided when your code requires scrolling.
Sub aProcedure()
GoTo T
V:
j = vbCancel
b = "point"
GoTo K
X2:
j = x
b = "before"
GoTo K
A1:
For i = VbMethod To vbCancel
b = DoThingWith(DoThingWith(b, 44), b)
Next
j = j * 3
a = DoThingWith(a, b)
GoTo Z
Z:
b = "times"
GoTo K
U2:
j = j + 1 - x
b = "has"
GoTo K
A2:
MsgBox DoThingWith(a)
Exit Sub
X1:
j = j + 1
b = "made"
GoTo K
T:
a = "this"
GoTo U1
K:
a = DoThingWith(a, b)
DoEvents
Select Case j
Case 0
GoTo A2
Case 1
GoTo U1
Case 2
GoTo U2
Case 3
GoTo W
Case 4
GoTo X1
Case 5
GoTo Y
Case Else
GoTo X2
End Select
W:
j = 2 * (j - 1)
b = "been"
GoTo K
Y:
b = "many"
GoTo A1
U1:
a = Replace(a, Left(a, 1), UCase(Left(a, 1)))
GoTo V
End Sub
Private Function DoThingWith(a, Optional b = 46, Optional c = 32)
If IsNumeric(b) Then
b = CInt(b)
c = CInt(c)
Select Case Asc(Right(a, 1))
Case b
DoThingWith = a & Chr(b - c - 1)
Case Else
DoThingWith = a & Chr(b)
End Select
ElseIf IsNumeric(c) Then
c = CInt(c)
DoThingWith = a & Chr(c) & b
Else
DoThingWith = a & b & c
End If
End Function
The output:
I have an excel spreadsheet. In a column of the spreadsheet I have a list of codes (numbers).These codes (numbers) are sorted from highest to lowest values.(some of these codes has been repeated. For example I have three consecutive line with code 1001200).I want to insert new rows between each codes (in case of having repeated codes i just need one new row (for example i Just need one new row for 1001200 not 3 rows) .
I have written the following code but it does not work.
Sub addspace()
Dim space_1(5000), Space_2(5000)
For n = 1 To 5000
Debug.Print space_1(n) = Worksheets("sheet3").Cells(1 + n, 1).Value
Debug.Print Space_2(n) = Worksheets("sheet3").Cells(2 + n, 1).Value
Next
For n = 1 To 5000
If space_1(n) <> Space_2(n) Then
Range("space_1(n)").EntireRow.Insert
End If
Next
End Sub
How can I fix it? (From the code you can see that I am so beginner :)))
Cheers
To insert one empty row between each unique value try this:
Option Explicit
Public Sub addspace()
Dim i As Long
Application.ScreenUpdating = False
With Worksheets("sheet3")
For i = 5000 To 2 Step -1
While .Range("A" & i - 1) = .Range("A" & i)
i = i - 1
Wend
.Rows(i).Insert Shift:=xlDown
Next
End With
Application.ScreenUpdating = True
End Sub
It starts from the end row and moves up, skipping duplicates
The Range("space_1(n)") is invalid. Arg of range object should be a column name like "A1", you can use Range("A" & n).EntireRow.Insert in your code. But I recommend my code.
Please try,
Sub addspace()
Dim n As Integer
For n = 1 To 5000
If Worksheets("sheet3").Cells(n, 1).Value <> Worksheets("sheet3").Cells(n + 1, 1).Value Then
Worksheets("sheet3").Cells(n + 1, 1).EntireRow.Insert
n = n + 1
End If
Next
End Sub