How to do a 3-part IF statement in VBA? - vba

'8
If Not IsEmpty(Range("A7")) And Range("C7") = "\" Then
Range("W7") = "\"
ElseIf Not IsEmpty(Range("A7")) And Range("C7") <> "\" Then
Range("W7") = "\L"
ElseIf IsEmpty(Range("A7")) Then
Range("W7") = ""
End If
With Sheets("DL Data")
.Range("W7:W" & .Cells(.Rows.Count, "A").End(xlUp).Row).Formula = "\L"
End With
I cannot seem to figure out the WITH part, or maybe I am off on the IF statement all together. What I am trying to do here is this:
IF A7 is not empty AND it equals "\" THEN W7 equals "\", also
IF A7 is not empty AND it does not equal "\" THEN W7 equals "\L", also
IF A7 is empty THEN W7 equals blank
Then I would like it to do this to search through the Column and give me the appropriate answer, inserting blanks where necessary, inserting "\" where necessary and inserting "\L" where necessary.
Hope I am making myself clear here, thanks for all of the help in advance!
Regards,
Yazz

The With is simply an abbreviation.
For example
With Sheets("DL Data")
.Range("W7:W" & .Cells(.Rows.Count, "A").End(xlUp).Row).Formula = "\L"
End With
Is equivalent to
Sheets("DL Data").Range("W7:W" & Sheets("DL Data").Cells(Sheets("DL Data").Rows.Count, "A").End(xlUp).Row).Formula = "\L"
You need a loop in order to apply this condition to all of the rows, for example:
Dim i as Integer
For i = 7 To Sheets("DL Data").Range("A7").End(xlDown).Row
If Not IsEmpty(Range("A" & i)) And Range("C" & i) = "\" Then
Range("W" & i) = "\"
ElseIf Not IsEmpty(Range("A" & i)) And Range("C" & i) <> "\" Then
Range("W" & i) = "\L"
ElseIf IsEmpty(Range("A" & i)) Then
Range("W" & i) = ""
End If
Next i

If you want to run it through the whole column, you need to nest the same If-block into a loop:
With Sheets("DL Data")
For j = 7 To .Range("A7").End(xlDown).Row
If .Range("A" & j) <> "" And .Range("C" & j) = "\" Then
.Range("W" & j) = "\"
ElseIf .Range("A" & j) <> "" And .Range("C" & j) <> "\" Then
.Range("W" & j) = "\L"
ElseIf .Range("A" & j) = "" Then
.Range("W" & j) = ""
End If
Next j
End With
WARNING I have followed your current implementation; however, if your column "A" might have some empty cells in between (which would explain the presence of a ElseIf .Range("A" & j) = ""), pay attention to the fact that the counter .Range("A7").End(xlDown).Row would stop at the first empty cell. You might want to index your counter into an always filled-up column (such as a record-ID of your data set).

This update to your code will update the W column according to your formula. I optimized the If statements a bit to make them less redundant.
Additionally, I have included a couple of With blocks for illustration purposes.
With Sheets("DL Data")
Dim row As Long
For row = 7 To .Cells(.Rows.Count, "A").End(xlUp).Row)
With .Range("A" & row)
' IF A is empty THEN W equals blank
If .Value = "" Then
Range("W" & row).Value = ""
' IF A is not empty AND it equals "\" THEN W equals "\"
If .Value = "\" Then
Range("W" & row).Value = "\"
' IF A is not empty AND it does not equal "\" THEN W equals "\L"
' A is not empty (first condition checked above).
ElseIf .Value <> "\"
Range("W" & row).Value = "\L"
End If
End With
Next
End With

Related

Concatenate two ranges without looping

I want to concatenate two ranges into one WIHTOUT using a loop.
Below is the code. The lines with comment's is basically the solution I want to avoid.
With ws_AUoM
lCountEntriesInAUoMFile = .Cells(Rows.Count, "B").End(xlUp).Row
.Range("O2:O" & lCountEntriesInAUoMFile).Value = .Range("B2:B" & lCountEntriesInAUoMFile).Value & .Range("F2:F" & lCountEntriesInAUoMFile).Value
' For lLoopCounterAUoM = 2 To lCountEntriesInAUoMFile
'
' .Cells(lLoopCounterAUoM, "O").Value = .Cells(lLoopCounterAUoM, "B").Value & .Cells(lLoopCounterAUoM, "F").Value
'
' Next lLoopCounterAUoM
End With
This line:
.Range("O2:O" & lCountEntriesInAUoMFile).Value = .Range("B2:B" & lCountEntriesInAUoMFile).Value & .Range("F2:F" & lCountEntriesInAUoMFile).Value
returns the error "Type Mismatch". I have double checked the sizes and location of each range. Yet it does not work. What am I missing here?
You can do this:
Dim r As Long
With ws_AUoM
r = .Cells(.Rows.Count, "B").End(xlUp).Row
.Range("O2:O" & r).Value = .Evaluate("B2:B" & r & " & F2:F" & r)
End With
Evaluate knows you're giving it an array formula, and will return the resulting array, which you can assign directly to the sheet.

Excel VBA Runtime error 1004: Application defined or object defined error

I've scoured the internet for an answer to my problem. I am writing some code to input a formula into certain cells on a worksheet and despite very similar code working perfectly earlier in the macro, this section of code will not work with giving me the runtime error 1004: application-defined or object-defined error.
I have tried moving my code into a new workbook but the problem was not solved and I just can't see why it won't work.
The code below is where I define the sheets I am using
Sub InputFormulae()
Dim wksht As Worksheet
Dim wksht1 As Worksheet
Dim wksht2 As Worksheet
Dim wksht3 As Worksheet
Dim wksht4 As Worksheet
Dim wksht5 As Worksheet
Set wksht = ThisWorkbook.Worksheets("Coils same day remove & insert")
Set wksht1 = ThisWorkbook.Worksheets("Implants same day remove&insert")
Set wksht2 = ThisWorkbook.Worksheets("Implant inserted NO Removal")
Set wksht3 = ThisWorkbook.Worksheets("Implant inserted AND removed")
Set wksht4 = ThisWorkbook.Worksheets("Coil inserted NO removal")
Set wksht5 = ThisWorkbook.Worksheets("Coil inserted AND removed")
The code below is a part of the macro that is working
wksht.Activate
With wksht
i = Range("A" & Cells.Rows.Count).End(xlUp).Row
Do Until i = 1
If .Cells(i, 1) <> "" Then
Cells(i, 9).Formula = "=IF(A" & i & "=A" & i + 1 & ",IF(C" & i & "=C" & i + 1 & ",(H" & i & "-C" & i & "),(F" & i + 1 & "-C" & i & ")),IF(A" & i & "=A" & i - 1 & ",IF(C" & i & "=C" & i - 1 & ",(H" & i & "-C" & i & "),(H" & i & "-C" & i & ")),(H" & i & "-C" & i & ")))"
End If
i = i - 1
Loop
End With
And the code below here is the part that is not working
wksht3.Activate
With wksht3
i = Range("A" & Cells.Rows.Count).End(xlUp).Row
Do Until i = 1
If .Cells(i, 1) <> "" And .Cells(i, 3) <> "" And .Cells(i, 6) <> "" Then
Cells(i, 9).Formula = "=F" & i & "-C" & i & ")"
Else: Cells(i, 9).Value = "0"
End If
i = i - 1
Loop
End With
When I debug the code it highlights the Cells(i, 9).Formula = "=F" & i & "-C" & i & ")" line
Thanks for your time
=F10-C10)
is not a valid formula so you get a 1004
The error you get is because VBA does not understand "=F" & i & "-C" & i & ")". As far as it is a string, the easiest way to debug is to write either:
debug.print "=F" & i & "-C" & i & ")" on the line above and to see the immediate window for the value
or
MsgBox "=F" & i & "-C" & i & ")" on the line above and to see the string in a MsgBox.
Based on the result you would know how to continue.
Start with putting a period in front of every Range and Cells within a With ... End With.
Brackets come in pairs.
Don't turn real numbers into text-that-looks-like-a-number.
wksht3.Activate '<~~ totally unnecessary to use a With ... End With
With wksht3
i = .Range("A" & .Cells.Rows.Count).End(xlUp).Row
Do Until i = 1
If .Cells(i, 1) <> "" And .Cells(i, 3) <> "" And .Cells(i, 6) <> "" Then
.Cells(i, 9).Formula = "=F" & i & "-C" & i
Else
.Cells(i, 9).Value = 0
End If
i = i - 1
Loop
End With
FWIW, you could also just have your formula do the tests too:
With wksht3
i = Range("A" & Cells.Rows.Count).End(xlUp).Row
.Range("I1:I" & i).FormulaR1C1 = "=IF(OR(RC1="""",RC3="""",RC6=""""),0,RC6-RC3)"
End With

Delete empty rows using VBA - MS Excel

I am looking to see if there is a more efficient way to achieve the result below, so it can be extended if needed.
I'm using this to clean up large spreadsheets that have the rows C-Z blank. I imagine there should be a way to clean it up so that it doesn't have to double in size if I need to clean up a spreadsheet with data from C to AZ.
It's been a while since I used VBA, I found the code below online. (counting ROW B as the spreadsheet in question had an empty ROW A)
Sub delem()
Dim lr As Long, r As Long
lr = Cells(Rows.Count, "B").End(xlUp).Row
For r = lr To 1 Step -1
If Range("C" & r).Value = "" And Range("D" & r).Value = "" And Range("E" & r).Value = "" And Range("F" & r).Value = "" And Range("G" & r).Value = "" And Range("H" & r).Value = "" And Range("I" & r).Value = "" And Range("J" & r).Value = "" And Range("K" & r).Value = "" And Range("L" & r).Value = "" And Range("M" & r).Value = "" And Range("N" & r).Value = "" And Range("O" & r).Value = "" And Range("P" & r).Value = "" And Range("Q" & r).Value = "" And Range("R" & r).Value = "" And Range("S" & r).Value = "" And Range("T" & r).Value = "" And Range("U" & r).Value = "" And Range("V" & r).Value = "" And Range("W" & r).Value = "" And Range("X" & r).Value = "" And Range("Y" & r).Value = "" And Range("Z" & r).Value = "" Then Rows(r).Delete
Next r
End Sub
Thanks!
Just add an inner loop to go through the columns you care about. This will actually run much faster, as VBA doesn't short-circuit the If statement (all of the conditionals are evaluated). But with the loop, you can exit early if you find a value anywhere:
Sub delem()
Dim last As Long
Dim current As Long
Dim col As Long
Dim retain As Boolean
last = Cells(Rows.Count, "B").End(xlUp).Row
For current = last To 1 Step -1
retain = False
For col = 3 To 26
If Cells(current, col).Value <> vbNullString Then
retain = True
Exit For
End If
Next col
If Not retain Then Rows(current).Delete
Next current
End Sub
The Excel worksheet function COUNTA is a clean way to test if a range is empty.
Sub delem()
Dim lr As Long, r As Long
lr = Cells(Rows.Count, "B").End(xlUp).Row
For r = lr To 1 Step -1
'This function Counts the number of cells that are not empty
If WorksheetFunction.CountA(Range(Cells(r, 3), Cells(r, 26)) = 0 Then
Rows(r).Delete
End If
Next r
End Sub

VBA Text Array - Scan two columns for array string match rather than one

I have some code which is designed to scan Columns F & G for occurrences of words found in an array, the array containing text found in Column J. If it finds occurrences in either Column F or Column G, it will copy and paste the terms into the corresponding columns.
Column J contains free text from a field in SAP. The field is free text so it could be "Kerry John Pub Expenses" or "CATS O/H Kerry John", or even "CATS John Kerry O/H". There is no data entry standard for this field; this is what makes this task difficult .
Column F and Column G contains first names and last names. The code makes an assumption, if it finds an entry in column F or G that matches an entry in the txt array, it will copy and paste that entry.
During testing, the code proved not sufficient to match the outcomes which I was looking for, and the solution to this problem would be to match text in Columns F and G concurrently for two matching words rather than doing them in separate intervals.
I would like some suggestions as to how this code could be re-written to achieve this result.
Example of successful code run
Here we have 4 rows of data, John Citizen is located in Row 3, therefore the blank cells in Columns F and G, Row 2 can be populated with his first and last name.
The problem
Because I have two rows that contain Kerry Citizen and John Kerry, the row is populated with Kerry Kerry as a result, where the entry should be "John" in Column F and "Kerry" in Column G
Code starts here
Sub arraycolumnmatch()
Dim txtArray As Variant, T As Variant
Dim I As Long, J As Long
For I = 2 To Range("E50000").End(xlUp).row
typ = Range("F" & I).Value
If typ = "" Then
txt = Range("J" & I).Value
txtArray = Split(txt, " ")
For Each T In txtArray
For J = 2 To Range("F50000").End(xlUp).row
If Range("F" & J).Value = T Then
match_txt = T
Range("F" & I).Value = match_txt
End If
Next J
Next T
For Each T In txtArray
For J = 2 To Range("G50000").End(xlUp).row
If Range("G" & J).Value = T Then
match_txt = T
Range("G" & I).Value = match_txt
End If
Next J
Next T
End If
Next I
End Sub
You can simplify your code greatly, and make it work, like this:
typ = Range("F" & I).Value
If typ = "" Then
txt = Range("J" & I).Value
matchFound = False
For J = 2 To Range("G50000").End(xlUp).Row
If InStr(txt, Range("F" & J).Value) <> 0 _
And InStr(txt, Range("G" & J).Value) _
And Not (IsEmpty(Range("F" & J).Value)) _
And Not (IsEmpty(Range("G" & J).Value)) Then
'Both names match. Copy them.
Range("F" & I).Value = Range("F" & J).Value
Range("G" & I).Value = Range("G" & J).Value
matchFound = True
Exit For ' look no further.
End If
Next J
If Not matchFound Then MsgBox "No match found for: " & txt
End If
Tested, works for me.
The Code below runs for every first name on the list but only adds the name if both names match.
Sub arraycolumnmatch()
Dim txtArray As Variant, t As Variant
Dim I As Long, J As Long
For I = 2 To Range("G50000").End(xlUp).Row
typ = Range("F" & I).Value
If typ = "" And Not Range("J" & I).Value = Empty Then
txt = Range("J" & I).Value
txtArray = Split(txt, " ")
For Each word In txtArray
If Not word = "" Then
Set findtext = Range("F:F").Find _
(what:=(word), LookIn:=xlValues)
stoploop = False
loopcnt = 0
Do While Not findtext Is Nothing And stoploop = False And loopcnt < 21
loopcnt = loopcnt + 1
If InStr(txt, Range("F" & findtext.Row).Value) <> 0 _
And InStr(txt, Range("G" & findtext.Row).Value) Then
'Both names match. Copy them.
Range("F" & I).Value = Range("F" & findtext.Row).Value
Range("G" & I).Value = Range("G" & findtext.Row).Value
stoploop = True
Exit For ' look no further.
Else
Set findtext = Range("F" & findtext.Row & ":F" & 50000).Find _
(what:=(word), LookIn:=xlValues)
End If
Loop
End If
Next word
If Not stoploop Then MsgBox "No match found for: " & txt
End If
Next I
End Sub
Edit: Did an integration of #Jean InStr and a Find in Range which would allow for less loop time and a double match find.
I have had to stick with my original syntax, answer is below. Not the most efficient way of reaching the result, but it works
Sub arraycolumnmatch()
Dim txtArray As Variant, T As Variant
Dim I As Long, J As Long
For I = 2 To Range("E50000").End(xlUp).row
typ = Range("F" & I).Value
If typ = "" Then
txt = Range("J" & I).Value
txtArray = Split(txt, " ")
For Each T In txtArray
For J = 2 To Range("G50000").End(xlUp).row
If Range("G" & J).Value = T Then
match_txt = T
Range("G" & I).Value = match_txt
Exit For
End If
Next J
Next T
For Each T In txtArray
For J = 2 To Range("F50000").End(xlUp).row
If Range("F" & J).Value = T Then
match_txt = T
If Not Range("G" & I).Value = T Then
Range("F" & I).Value = match_txt
Exit For
End If
End If
Next J
Next T
End If
Next I

Copy data to new workbook and add specific text to each row´s value in a specific column

I am exporting data from one workbook to another workbook to T13:Tlastrow
This data, from column F in my workbook where I run this macro, I want to be put into {nyckel="TEXT HERE";} in column T in the "new" workbook, starting from row 13 (T13).
I am stuck here. So would really appreciate some help/solution. Thanks!
Sub CopyData()
Dim wkbCurrent As Workbook, wkbNew As Workbook
Set wkbCurrent = ActiveWorkbook
Dim valg, c, LastCell As Range
Set valg = Selection
Dim wkbPath, wkbFileName, lastrow As String
Dim LastRowInput As Long
Dim lrow, rwCount, lastrow2, LastRowInput2 As Long
Application.ScreenUpdating = False
' If nothing is selected in column A
If Selection.Columns(1).Column = 1 Then
wkbPath = ActiveWorkbook.Path & "\"
wkbFileName = Dir(wkbPath & "CIF LISTEN.xlsm")
Set wkbNew = Workbooks.Open(wkbPath & "CIF LISTEN.xlsm")
'Application.Run ("'C:\Users\niclas.madsen\Desktop\TEST\CIF LISTEN.xlsm'!DelLastRowData")
LastRowInput = Cells(Rows.count, "A").End(xlDown).Row
For Each c In valg.Cells
lrow = wkbNew.Worksheets(1).Range("B1").Offset(wkbNew.Worksheets(1).Rows.count - 1, 0).End(xlUp).Row + 1
lastrow2 = Range("A" & Rows.count).End(xlUp).Row
lastrow3 = Range("T" & Rows.count).End(xlUp).Row
wkbCurrent.ActiveSheet.Range("E" & c.Row).Copy Destination:=wkbNew.Worksheets(1).Range("A" & lrow)
wkbCurrent.ActiveSheet.Range("A" & c.Row).Copy Destination:=wkbNew.Worksheets(1).Range("B" & lrow)
wkbCurrent.ActiveSheet.Range("F" & c.Row).Copy Destination:=wkbNew.Worksheets(1).Range("T" & lrow)
' Standard inputs
wkbNew.Worksheets(1).Range("D13:D" & lastrow2).Value = "Ange referens och period"
wkbNew.Worksheets(1).Range("E13:E" & lastrow2).Value = "99999002"
wkbNew.Worksheets(1).Range("G13:G" & lastrow2).Value = "EA"
wkbNew.Worksheets(1).Range("H13:H" & lastrow2).Value = "2"
wkbNew.Worksheets(1).Range("M13:M" & lastrow2).Value = "SEK"
wkbNew.Worksheets(1).Range("N13:N" & lastrow2).Value = "sv_SE"
wkbNew.Worksheets(1).Range("P13:P" & lastrow2).Value = "TRUE"
wkbNew.Worksheets(1).Range("Q13:Q" & lastrow2).Value = "TRUE"
wkbNew.Worksheets(1).Range("S13:S" & lastrow2).Value = "Catalog_extensions"
'wkbNew.Worksheets(1).Range("T" & lastrow3).Value = "{Nyckelord=" & wkbNew.Worksheets(1).Range("T" & lastrow3).Value & ";}"
Next
' Trying to get this to work
LastRowInput2 = wkbNew.Worksheets(1).Range("T" & wkbNew.Sheets("Sheet1").UsedRange.Rows.count + 1).End(xlUp).Row
For i = 0 To LastRowInput2 - 13
wkbNew.Worksheets(1).Range("T" & 13 + i).Value = "{Nyckelord=" & wkbNew.Worksheets(1).Range("T" & 13 + i).Value & ";}"
Next i
' END HERE
' wkbNew.Close False
' Find the number of rows that is copied over
wkbCurrent.ActiveSheet.Activate
areaCount = Selection.Areas.count
If areaCount <= 1 Then
MsgBox "The selection contains " & Selection.Rows.count & " suppliers."
' Write it in A10 in CIF LISTEN
wkbNew.Worksheets(1).Range("A10").Value = "COMMENTS: " & Selection.Rows.count & " Suppliers Added"
Else
i = 1
For Each A In Selection.Areas
'MsgBox "Area " & I & " of the selection contains " & _
a.Rows.count & " rows."
i = i + 1
rwCount = rwCount + A.Rows.count
Next A
MsgBox "The selection contains " & rwCount & " suppliers."
' Write it in A10 in CIF LISTEN
wkbNew.Worksheets(1).Range("A10").Value = "COMMENTS: " & rwCount & " Suppliers Added"
End If
wkbNew.Worksheets(1).Activate
Application.ScreenUpdating = True
Else
MsgBox "Please select cell(s) in column A", vbCritical, "Error"
Exit Sub
End If
End Sub
OK Try
wkbNew.Worksheets(1).Range("T" & lrow).Value = "{Nyckelord=" & wkbCurrent.ActiveSheet.Range("F" & c.Row).Value & "}"
Instead of your line:
wkbCurrent.ActiveSheet.Range("F" & c.Row).Copy Destination:=wkbNew.Worksheets(1).Range("T" & lrow)
And remove the whole block marked 'Trying to get this to work
If the code is doing the right action but on the wrong cells, then the problem is in the start and end of the For loop. Your For Loop is going from row '13 + i' where i = 0 (so row 13), to row 13 + LastRowInput2 - 13 (so LastRowInput2). This seems right to me, so the problem must be with the value in LastRowInput2.
You need to correct this line:
LastRowInput2 = wkbNew.Worksheets(1).Range("T" & wkbNew.Sheets("Sheet1").UsedRange.Rows.count + 1).End(xlUp).Row
So that is gives you the correct last row input in your data. There are several approaches to finding the end of data depending on whether there may be blank cells in the middle and other factors. This may be one option:
LastRowInput2 = wkbNew.Worksheets(1).Range("T65000").End(xlUp).Row
Be sure to step through the code and verify that LastRowInput2 is set to the value you expect and then this should work.