Compare values in Excel VBA - excel

I am trying to compare cell A1 with B1 and if it is true populate cell F1 with the A1 value. But irrespective of my input values the if condition becomes true.
Sub Macro3()
Dim i As Integer
i = 1
For i = 1 To 10
If (Range("A" & i).Select = Range("B" & i).Select) Then
Range("A" & i).Select
Selection.Copy
Range("F" & i).Select
ActiveSheet.Paste
End If
Next i
End Sub

Instead of selecting, copying, and pasting, you can compare the Value property of the cells, then set the F column Value accordingly:
Dim i As Integer
For i = 1 To 10
If Range("A" & i).Value = Range("B" & i).Value Then
Range("F" & i).Value = Range("A" & i).Value
End If
Next

Consider this a compliment to Nick's answer (accept his if you find it to work, which you should). I wanted to help explain some of the things that are wrong in your code.
Before FIX:
Sub Macro3()
Dim i As Integer
i = 1
For i = 1 To 10
If (Range("A" & i).Select = Range("B" & i).Select) Then
Range("A" & i).Select
Selection.Copy
Range("F" & i).Select
ActiveSheet.Paste
End If
Next i
End Sub
AFTER FIX
Sub Macro4()
Dim i As Long
For i = 1 To 10
If Range("A" & i).Value = Range("B" & i).Value Then
Range("F" & i).Value = Range("A" & i).Value
End If
Next
End Sub
POINTS:
Use Long instead of Integer (small optimization since VBA will convert the int to a long anyway)
No need to declare i = 1 twice in a row
You should be comparing values, not simply selecting cells. There is rarely, if ever, a need to use the .Select keyword. You can access all object's properties directly.
Copy and paste is a heavy operation. Since you are in VBA, may as well just assign the value that is in A to the cell in column B. It's faster, and more effecient.
I hope this helps. BTW, you can simple enter:
=IF(A1=B1,A1,"")
in F1 and drag the formula down to get a similar result.

You can use a variant array to address your performance issue that you raise above. This code will run the same as Nicks except it will skip blanks cell, ie it will
update the F value if A and B are the same
skip updates if the A cell is blank
leave the existing F values in place if A<>B
It wasn't clear to me how you are comparing rows accross two sheets, can you expand on this?
Sub MyArray()
Dim X As Variant
Dim Y As Variant
Dim lngrow As Long
X = Range([a1], Cells(Rows.Count, "B").End(xlUp))
Y = Range([f1], [f1].Offset(UBound(X, 1) - 1, 0))
For lngrow = 1 To UBound(X, 1)
If Len(X(lngrow, 1)) > 0 Then
If X(lngrow, 1) = X(lngrow, 2) Then Y(lngrow, 1) = X(lngrow, 1)
End If
Next
Range([f1], [f1].Offset(UBound(X, 1) - 1, 0)) = Y
End Sub

Related

Excel VBA to copy rows with a specific criteria [duplicate]

any help with this would be appreciated.
I am trying to copy a cell from column (G) into another worksheet, if cells from the same row in column (R) = "Y" and column (B) = "Month"
I had it working for just "Y" criteria but as soon as I added the "Month" this button has stopped working?
this is the code I have;
Private Sub CommandButton1_Click()
Dim LR As Long, i As Long
With Sheets("Savings Q4")
LR = .Range("R" & Rows.Count).End(xlUp).Row
For i = 1 To LR
With .Range("R" & i)
If .Value = "Y" Then
With .Range("B" & i)
If .Value = "January" Then
Sheets("Savings Q4").Range("G:G").Copy Destination:=Sheets("Cifas Loadings").Range("A:A")
End If
End With
Next i
End With
End Sub
Any help would be appreciated.
Thanks
Too Much 'Withing' and 'Ifing'
Rules
The number of With statements must be equal to the number of End With statements.
The number of If statements must be equal to the number of End If statements, except when there is a 'one-line' If Statement.
Insights
Alexey C's solution gets those With-s and If-s in line, but problems still remain.
When you write With .Range("R" & i) it refers to Sheets("Savings Q4") from the previous With statement and you are actually shortening the line
With Sheets("Savings Q4").Range("R" & i)
which is OK.
When you later write With .Range("B" & i) it doesn't refer to Sheets("Savings Q4"), it refers to .Range("R" & i) i.e. your not shortening the line With Sheets("Savings Q4").Range("B" & i) but
With Sheets("Savings Q4").Range("R" & i).Range("B" & i)
which is WRONG.
Matteo NNZ correctly commented that the If statements could be shortened to one If statement using the And operator.
When you write
Sheets("Savings Q4").Range("G:G").Copy_
Destination:=Sheets("Cifas Loadings").Range("A:A")
you are copying the entire G column to the entire A column. Since this is in a loop (For i = 1 to LR), each time the code 'encounters' "January" and "Yes", it copies the entire column. It is highly unlikely that you are trying to achieve that functionality.
Plan of Changes
Get rid of the 'inner' With's.
Reduce the If's using And.
Change the COLUMN ranges G:G and A:A to the corresponding CELL ranges.
Get rid of Destination:=.
The Code
Sub WithIf()
Dim LR As Long, i As Long
With Sheets("Savings Q4")
LR = .Range("R" & Rows.Count).End(xlUp).Row
For i = 1 To LR
If .Range("R" & i).Value = "Y" And _
.Range("B" & i).Value = "January" Then
.Range("G" & i).Copy Sheets("Cifas Loadings").Range("A" & i)
End If
Next i
End With
End Sub
Remaining Issues
A further problem might be that you didn't want the A column data copied in the same row as the G column data. If this is the case you should apply the same LR = .Range("R" & Rows.Count).End(xlUp).Row logic and integrate it into the code referring to the A column of sheet "Cifas Loadings".
At least, you forgot one End With and one End If. But anyway it's not correct with logical part.
Dim LR As Long, i As Long
With Sheets("Savings Q4")
LR = .Range("R" & Rows.count).End(xlUp).Row
For i = 1 To LR
With .Range("R" & i)
If .Value = "Y" Then
With .Range("B" & i)
If .Value = "January" Then
Sheets("Savings Q4").Range("G:G").Copy Destination:=Sheets("Cifas Loadings").Range("A:A")
End If
End With
End If
End With
Next i
End With
It's easier to make it w/o With, like
if Range("R"& i).value="Y" and Range("B" & i).value = "Month"
COPE CELLS
end if

VBA loop, repeat formula through column

I am trying to replicate in VBA the simple function in excel which allows you to repeat a function through an entire column, and stops when the columns on the side are empty. Specifically, I want to repeat an if - else if function for the entire relevant part of the column
Here's an attempt which does not really work
Sub RepeatIfElseif
Range("A1").Select
If selection > 0 Then
Range("B1").Select
ActiveCell.FormulaR1C1 = "X"
Range("A1").Select
ElseIf selection <= 0 Then
Range("B1").Select
ActiveCell.FormulaR1C1 = "Y"
End If
Range("B1").Select
selection.AutoFill Destination:=Range("B1:B134")
Is there any way I can do it with a loop?
You do not need to loop to drop formulas in. You just need to know where the last row is!
Pick a column that is most likely to represent your last row (I am using Column A in my example) and then you can dynamically drop-down your equation in one line without the loop.
The below will fill in the equation A2 + 1 in Column B starting from 2nd row (assuming you have a header row) down to the last used row in Column A
Option Explicit
Sub Formula_Spill()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1") '<-- Update sheet!
Dim LR As Long
LR = ws.Range("A" & ws.Rows.Count).End(xlUp).Row '<-- Update column!
ws.Range("B2:B" & LR).Formula = "=A2+1" '<-- Update formula!
End Sub
If you want to use a loop, you can use something like the code below:
For i = 1 To 134
If Range("A" & i).Value > 0 Then
Range("B" & i).FormulaR1C1 = "X"
Else
Range("B" & i").FormulaR1C1 = "Y"
End If
Next I
It can be done without a loop, something like:
Range("B1:B134").Formula = "=IF(A1>0," & Chr(34) & "X" & Chr(34) & "," & Chr(34) & "Y" & Chr(34) & ")"
Not sure what formula you are trying to achieve with .FormulaR1C1 = "Y" ?
I'm trying to improve my English, I swear...
I would do something like this:
dim row as long
dim last_row as Long
last_row = ActiveSheet.Range("A1048576").End(xlUp).Row
For row = 1 to last_row
If Range("A" & row).Value > 0 Then
ActiveSheet.Range("B" & row).Value = "X"
Else
ActiveSheet.Range("B" & row).Value = "Y"
End If
Next row
Hope this helps.

Why are there inconsistent and broken cell formulas for some rows and not others?

Goal: Populate F and G columns with proper formulas depending on total PROD-TIME for a block
This is another issue that has come up after one of my previous questions:
How to loop through "blocks" of rows in excel dataset instead of each row individually (VBA)?
I have been able to loop through blocks of rows and can now get the sum of the PROD-TIME for that particular block. This sum is necessary to determine which formula needs to be used in the F and G columns.
This is best illustrated in this workbook,
https://www.dropbox.com/s/vgnqi00h8xosja3/wip%20Gantt%20Template.xlsx?dl=0 , where I have shown how I want the formulas to end up in the F and G columns. But for some reason when I run the macro, it just completely breaks. Some of the formulas don't even use reference cells and use the cell value instead, or reference cells don't even appear. Are the blank F and G columns confusing the macro? How can I make sure that every F and G cell gets filled with something? Errors are fine
Sub getStartEndDate()
Dim WrkSht As Excel.Worksheet
Dim RngColumn As Range, RngBlock As Range
Dim totalHrs As Integer 'total PROD-TIME for the given RngBlock
Dim lastRow As Long
lastRow = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
Set WrkSht = ActiveWorkbook.Worksheets(1)
' Populate the last row by itself first since the With-statement below needs to reference rows below current row
Range("E" & lastRow).Formula = "=ROUNDUP(D" & lastRow & "/12,0)"
Range("G" & lastRow).Value = Range("C" & lastRow).Value
Range("F" & lastRow).Formula = "=WORKDAY(G" & lastRow & ", -E" & lastRow & ")"
Columns("F:F").NumberFormat = "yyyy-mm-dd"
With WrkSht
Set RngColumn = .Range("B2:B" & lastRow)
'Starts the first block with the first cell in a column.
Set RngBlock = RngColumn.Cells(1)
'Checks every cell in a column.
For Each rngcell In RngColumn
If rngcell.Offset(0,1).Value <> "" Then
'Checks whether a cell's value equals the cell below it.
If rngcell.Value = rngcell.Offset(1, 0).Value Then
'If equal, includes the cell below in the block.
Set RngBlock = Union(RngBlock, rngcell.Offset(1, 0))
Else
'If not equal, that means the block RngBlock ends
' totalHrs is the sum of the "PROD-TIME" for that particular block
totalHrs = WorksheetFunction.Sum(Range(CStr(Trim(Chr(64 + RngBlock.Column + 2))) _
& CStr(Trim(Str(RngBlock.Row))) & ":" _
& CStr(Trim(Chr(64 + 2 + RngBlock.Column + RngBlock.Columns.Count - 1))) _
& CStr(Trim(Str(RngBlock.Row + RngBlock.Rows.Count - 1)))))
If totalHrs < 12 Then
' If total production time (PROD-TIME) is less than 12 hours, then the start and end date should be the same for all rows in that block
rngcell.Offset(0, 4).Value = rngcell.Offset(0, 1).Value
rngcell.Offset(0, 5).Value = rngcell.Offset(0, 1).Value
Else
' If total production time is greater than 12 hours, then start and end dates are based on a different formula
' e.g. Given row 11, F column formula looks like: =WORKDAY(G11, -E11), G column looks like: =IF(B11=B12,F12,C11)
rngcell.Offset(0, 4).Formula = "=WORKDAY(" & rngcell.Offset(0, 5) & ", -" & rngcell.Offset(0, 3) & ")"
rngcell.Offset(0, 5).Formula = "=IF(" & rngcell & "=" & rngcell.Offset(1, 0) & "," & rngcell.Offset(1, 4) & "," & rngcell.Offset(0, 1) & ")"
End If
'Starts the next block with the cell below.
Set RngBlock = rngcell.Offset(1, 0)
End If
End If
Next rngcell
End With
End Sub

Making the column variable in a Nested loop

I'm having an issue with trying to expand on the code that I have written. The code I have pasted below is currently working as intended. The issue I have is that I am trying to make the "P2" cell variable. Essentially, I am trying to compare the ("K" & i) cell in the loop to all the dates in the range P2 to AA2 on my sheet. Then if the month and year matches, paste the data in the corresponding column that matched. I have tried replacing the column reference P with another integer, but could not get the nested loop to function correctly. Is there a different way to establish a column as a variable? Thank you for your help.
Sub Test()
Dim i As Integer
Sheets("Sheet1").Select
For i = 3 To 6
If Month(Range("K" & i)) = Month(Range("P2")) And Year(Range("K" & i)) = Year(Range("P2")) And Range("J" & i).Value > "0" Then
Range("J" & i).Copy
Range("P" & i).PasteSpecial xlPasteValues
End If
Next i
End Sub
Just loop through the columns 16 through 27 inside your existing loop:
Sub Test()
Dim i As Integer
Sheets("Sheet1").Select
For i = 3 To 6
'loop columns p through aa
For k = 16 to 27
'Instead of Range() we are using Cell() to refer to the column variabl-y... Cells(<rownum>,<columnnum>)
If Month(Range("K" & i)) = Month(Cells(2,k)) And Year(Range("K" & i)) = Year(Cells(2,k)) And Range("J" & i).Value > "0" Then
Range("J" & i).Copy
Cells(i,k).PasteSpecial xlPasteValues
End If
Next k
Next i
End Sub

VBA code to select a cell when specific letters appears and sort

I need some help to understand and modify some code I found in this answer:
Sub Main()
Dim cell As Range
Dim nextRow As Long
For Each cell In Range("K50:K200")
If StrComp(cell, "Late", vbTextCompare) = 0 Then
nextRow = Range("J" & Rows.Count).End(xlUp).Row + 1
Range("J" & nextRow) = Range("B" & cell.Row)
Range("K" & nextRow) = Range("C" & cell.Row)
Range("N" & nextRow) = Range("G" & cell.Row)
Range("O" & nextRow) = Range("H" & cell.Row)
End If
Next
End Sub
What I'd like is:
If late is along with some other words, say late submit, copy values in B and paste in J
if row K has progress along with say in progress, copy values in C to K
If sick is with say on sick leave, copy values in G to N
I tried so hard, but I still didn't succeed in modifying this code to suit my needs.
If late is along with some other words, say late submit
In that case, instead of StrComp, use Instr
If Instr(1, cell, "Late", vbTextCompare) > 0 Then
Similarly for the rest.
If you check Excel's help you will notice that Instr returns a Variant (Long) specifying the position of the first occurrence of one string within another.
Syntax
InStr([start, ]string1, string2[, compare])

Resources