Copying a union range with a last row value - vba

I have the following code that is sort of working now but I've hit another snag. For some reason it is copying from the same sheet multiple times and pasting to the new workbook. I think this is due to my NumRange + 100 perimeter I set because I couldnt get the LastRow variable to work.
Public Sub extractCol()
'Find FF&E Section, Add 3 rows and Identify relevant columns.
Dim rFind As Range, CRange As String, ERange As String, KRange As String, MRange As String
Dim ws As Worksheet
Dim NewBook As Workbook
Dim NumRange As Long
Dim LastRow As Long
Set NewBook = Workbooks.Add ' Open new Workbook
For Each ws In ThisWorkbook.Worksheets
With ws
Set rFind = .Range("A:A").Find(What:="FF&E", LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not rFind Is Nothing Then
LastRow = .Cells(.Rows.Count, "E").End(xlUp).Row
NumRange = rFind.Row + 3 ' Find FF&E line and add three
CRange = "C" & NumRange & ":" & "C" & NumRange + 100 ' Define First 100 Lines in Column C
ERange = "E" & NumRange & ":" & "E" & NumRange + 100 ' Define First 100 Lines in Column E
KRange = "K" & NumRange & ":" & "K" & NumRange + 100 ' Define First 100 Lines in Column K
MRange = "M" & NumRange & ":" & "M" & NumRange + 100 ' Define First 100 Lines in Column M
Set range1 = Union(.Range(CRange), .Range(ERange), .Range(KRange), .Range(MRange)) ' Combine individual column ranges in to one selection
range1.Copy ' Copy new combined range
NewBook.Sheets(1).Range("B" & Rows.Count).End(xlUp)(2).PasteSpecial Paste:=xlPasteValues ' Paste to new Workbook
NewBook.Sheets(1).Range("A" & Rows.Count).End(xlUp)(2).Resize(range1.Rows.Count).Value = FindRoom(ws)
End If
End With
Next ws
End Sub
Function FindRoom(ws As Worksheet)
shtName = ws.Name
Dim arr() As String
arr = VBA.Split(shtName, " ")
xCount = UBound(arr)
If xCount < 1 Then
FindRoom = "Unknown"
Else
FindRoom = arr(xCount)
End If
End Function
So I tried fixing it by doing the following;
CRange = "C" & NumRange & ":" & "C" & LastRow
ERange = "E" & NumRange & ":" & "E" & LastRow
KRange = "K" & NumRange & ":" & "K" & LastRow
MRange = "M" & NumRange & ":" & "M" & LastRow
But this causes an error on the following line;
range1.Copy
Any help on where I'm going wrong would be appreciated.
Thanks!

Related

VBA code bogging down computer during execution

The code below was designed to run through sheets in a workbook and carry out calculations based on headers found. The issue that I am having is that the workbook contains sometimes up to 50 sheets of data with (at times) 2000 lines. This bogs the computer down during execution of the code.
Is there a way to optimize this code so that the computer would not be bogged down or am I limited by using VBA for this process? Thanks!
Here is the code:
Option Explicit
Sub ReturnMarginal()
Dim ws As Worksheet
Dim lngLowLimCol As Long, strLowLimCol As String
Dim lngHiLimCol As Long, strHiLimCol As String
Dim lngMeasCol As Long, strMeasCol As String
Dim lngLastRow As Long
Dim wsf As WorksheetFunction
' get worksheetfunction references
Set wsf = Application.WorksheetFunction
' iterate worksheets
For Each ws In ThisWorkbook.Worksheets
' validate LowLimit label is on sheet
If Not (ws.Rows(1).Find("LowLimit") Is Nothing) Then
' get location of input data columns and number of rows
lngLowLimCol = wsf.Match("LowLimit", ws.Rows(1), 0)
lngHiLimCol = wsf.Match("HighLimit", ws.Rows(1), 0)
lngMeasCol = wsf.Match("MeasValue", ws.Rows(1), 0)
lngLastRow = ws.Cells(1, lngLowLimCol).End(xlDown).Row
' get column letters for input data columns
strLowLimCol = Split(ws.Cells(1, lngLowLimCol).Address(True, False), "$")(0)
strHiLimCol = Split(ws.Cells(1, lngHiLimCol).Address(True, False), "$")(0)
strMeasCol = Split(ws.Cells(1, lngMeasCol).Address(True, False), "$")(0)
' output headers
ws.Range("P1") = "Meas-LO"
ws.Range("Q1") = "Meas-Hi"
ws.Range("R1") = "Min Value"
ws.Range("S1") = "Marginal"
' assign formulas to outputs
' Meas-LO
'Range("P2:P" & lngLastRow).Select
' With Selection
' Selection.NumberFormat = "General"
' .Value = .Value
' End With
With ws.Range("P2:P" & lngLastRow)
.Formula = "=IF(" & strLowLimCol & "2" = ""---"," &
strMeasCol & "2-" & strLowLimCol & "2," & _
9999)"
End With
' Meas-Hi
With ws.Range("Q2:Q" & lngLastRow)
.Formula = "=IF(ISNUMBER(" & strHiLimCol & "2)," & _
strMeasCol & "2-" & strHiLimCol & "2," & _
9999 & "2)"
'strMeasCol & "2)"
End With
' Min Value
With ws.Range("R2:R" & lngLastRow)
.Formula = "=MIN(P2,Q2)"
End With
' Marginal
With ws.Range("S2:S" & lngLastRow)
.Formula = "=IF(AND(R2>=-3,R2<=3),""Marginal"",R2)"
End With
End If
Next ws
End Sub

Application defined or object defined error - depending on which Worksheet is opened

I'm having an issue that I am struggling to solve as it's a bit specific. I have code that does copy and paste from one sheet to others. Each part of the code basically copies part from the master sheet "current" to the specified sheet.
When I run my code I receive an error "Application defined or object defined error" and the code stops at the work sheet "Dividend yield" after the following line
Worksheets("div. yield").Range("B7").Select
However if I open the sheet "Dividend yield" and run my code from there it will work fine until the last sheet "Reverse PE" where it will again throw and error "Application defined or object defined error" after the line
Worksheets("Reverse_PE").Range("B9").Select
I guess the error is related to the next coming rows with Autofill method but I have not found any useful solutions to this problem. Could somebody please advise me how to solve this error?
Full macros code is below.
Function getYield() As Double
Dim appIE As Object
Set appIE = CreateObject("internetexplorer.application")
With appIE
.Navigate "http://uk.investing.com/rates-bonds/world-government-bonds"
.Visible = False
End With
Do While appIE.Busy
DoEvents
Loop
Set allRowOfData = appIE.document.getElementById("pair_23705")
Dim myValue As Double: myValue = allRowOfData.Cells(2).innerHTML
appIE.Quit
Set appIE = Nothing
Worksheets("Reverse_PE").Range("B7").Value = myValue
Worksheets("Reverse_PE").Range("B7").Value = Worksheets("Reverse_PE").Range("B7").Value / 100
End Function
Sub adjust()
Dim copyAdress As Range
Dim copyRange As Range
Dim lastRow As Long
Dim Median As Range
'''PE'''
Set copyAdress = Worksheets("current").Range("A1:CJ10000").Find("PE_RATIO", lookat:=xlPart)
lastRow = Cells(65536, copyAdress.Column).End(xlUp).Row
Set copyRange = Worksheets("current").Range(Cells(copyAdress.Row + 1, copyAdress.Column), Cells(lastRow, copyAdress.Column))
Worksheets("PE").Range("B1").EntireColumn.Insert
copyRange.Copy Destination:=Sheets("PE").Range("B7", "B" & lastRow)
Worksheets("PE").Range("B2").Value = Worksheets("current").Range("A1").Value
Worksheets("PE").Range("B3").FormulaArray = "=MEDIAN(B7:B" & lastRow + 2 & ")"
Worksheets("PE").Range("B5").Font.Bold = True
Worksheets("PE").Range("B5").FormulaArray = "=IF(ISNUMBER(VLOOKUP($A$5,$A$7:$HI$1750,COLUMN(B4),FALSE)),VLOOKUP($A$5,$A$7:$HI$1750,COLUMN(B4),FALSE)," & Chr(34) & NA & Chr(34) & ")"
Set copyRange = Worksheets("current").Range("A5", "A" & lastRow)
copyRange.Copy Destination:=Sheets("PE").Range("A7", "A" & lastRow + 2)
''Dividend yield'''
Set copyRange = Worksheets("current").Range("A5", "A" & lastRow)
copyRange.Copy Destination:=Sheets("div. yield").Range("A7", "A" & lastRow + 2)
Worksheets("div. yield").Range("B7").FormulaArray = "=IF(ISNUMBER(current!X5),current!X5," & Chr(34) & Chr(34) & ")"
Worksheets("div. yield").Range("B7").Select
Selection.AutoFill Destination:=Sheets("div. yield").Range("B7:B" & lastRow + 2), Type:=xlFillDefault
'''PE Forward'''
Set copyAdress = Worksheets("current").Range("A1:CJ10000").Find("P/E-Ratio 03E", lookat:=xlPart)
lastRow = Cells(65536, copyAdress.Column).End(xlUp).Row
Set copyRange = Worksheets("current").Range(Cells(copyAdress.Row + 3, copyAdress.Column), Cells(lastRow, copyAdress.Column))
Worksheets("PE_forward").Range("B1").EntireColumn.Insert
copyRange.Copy Destination:=Sheets("PE_forward").Range("B7", "B" & lastRow + 2)
Worksheets("PE_forward").Range("B2").Value = Worksheets("current").Range("A1").Value
Worksheets("PE_forward").Range("B3").FormulaArray = "=MEDIAN(B7:B" & lastRow + 2 & ")"
Worksheets("PE_forward").Range("B5").Font.Bold = True
Worksheets("PE_forward").Range("B5").FormulaArray = "=IF(ISNUMBER(VLOOKUP($A$5,$A$7:$HI$1750,COLUMN(B751),FALSE)),VLOOKUP($A$5,$A$7:$HI$1750,COLUMN(B751),FALSE)," & Chr(34) & NA & Chr(34) & ")"
Worksheets("PE_forward").Columns("B").Replace What:="#VALUE!", Replacement:=""
Worksheets("PE_forward").Range("B3").NumberFormat = ""
Set copyRange = Worksheets("current").Range("A5", "A" & lastRow)
copyRange.Copy Destination:=Sheets("PE_forward").Range("A7", "A" & lastRow + 2)
'''Reverse PE'''
Set copyRange = Worksheets("current").Range("A5", "A" & lastRow)
copyRange.Copy Destination:=Sheets("Reverse_PE").Range("A9", "A" & lastRow + 4)
Worksheets("Reverse_PE").Range("B1").EntireColumn.Insert
Worksheets("Reverse_PE").Range("B2").Value = Worksheets("current").Range("A1").Value
Worksheets("Reverse_PE").Range("B5").FormulaArray = "=IF(ISNUMBER(VLOOKUP($A$5,$A$9:$HI$1750,COLUMN(B751),FALSE)),VLOOKUP($A$5,$A$9:$HI$1750,COLUMN(B751),FALSE)," & Chr(34) & NA & Chr(34) & ")"
getYield
Worksheets("Reverse_PE").Range("B3").FormulaArray = "=MEDIAN(B9:B" & lastRow + 4 & ")"
Worksheets("Reverse_PE").Range("B9").FormulaArray = "=IF(ISNUMBER(PE!B7),1/PE!B7," & Chr(34) & Chr(34) & ")"
Worksheets("Reverse_PE").Range("B9").Select
Selection.AutoFill Destination:=Sheets("Reverse_PE").Range("B9:B" & lastRow + 4), Type:=xlFillDefault
Worksheets("Reverse_PE").Range("B3:B" & lastRow + 4).Select
Selection.Style = "Percent"
Selection.NumberFormat = "0.00%"
You can't use the select method unless the sheet is first active, so add this line:
Worksheets("div. yield").Activate
Worksheets("div. yield").Range("B7").FormulaArray = "=IF(ISNUMBER(current!X5),current!X5," & Chr(34) & Chr(34) & ")"
and later at:
Worksheets("Reverse_PE").Activate
Worksheets("Reverse_PE").Range("B9").Select
There are much faster and more maintainable ways of doing what you're trying to do, but the above sheet activation will solve your immediate problem.
Don't forget to activate each sheet before you try to select one of the cells on it.

Using String Variable in VBA Formula throwing object/application error

I'm getting an "application-defined or object-defined error" being thrown when I try to set a cell in my active sheet to a formula. I think its due to me trying to use the Sheets.Name function in the formula, see code below:
Public Sub getChannels()
Dim lastRow As Long
Dim i As Integer, counter As Integer
Dim rng As Range, rngB As Range, rngC As Range
Dim sht As Worksheet
Dim test As String
Set sht = Sheets("Summary Sheet - 30-07-2015")
sht.Activate
lastRow = sht.Cells(sht.Rows.Count, "B").End(xlUp).Row
For counter = 1 To lastRow Step 3
If ActiveSheet.Cells(counter, 12) = "LTE 2C" Then
ActiveSheet.Cells(counter, 16) = _
"=INDEX('LTE 2C'!C[55],MATCH(""'"" & sht.name &""'""!RC[-14],'LTE 2C'!C[-11],0))"
ActiveSheet.Cells(counter, 17) = _
"=INDEX('LTE 2C'!C[53],MATCH(""'"" & sht.name &""'""!RC[-15],'LTE 2C'!C[-12],0))"
ActiveSheet.Cells(counter, 18) = _
"=INDEX('LTE 2C'!C[55],MATCH(""'"" & sht.name &""'""!RC[-16],'LTE 2C'!C[-13],0))"
Range("P" & counter & ":R" & counter).Select
Selection.Copy
Range("P" & counter + 1 & ":P" & counter + 2).Select
ActiveSheet.Paste
End If
Next
End Sub
Am I missing something obvious?
Change your formula like this:
ActiveSheet.Cells(counter, 16) = _
"=INDEX('LTE 2C'!C[55],MATCH(" & "'" & sht.name & "'" & "!RC[-14],'LTE 2C'!C[-11],0))"
ActiveSheet.Cells(counter, 17) = _
"=INDEX('LTE 2C'!C[53],MATCH(" & "'" & sht.name & "'" & "!RC[-15],'LTE 2C'!C[-12],0))"
ActiveSheet.Cells(counter, 18) = _
"=INDEX('LTE 2C'!C[55],MATCH(" & "'" & sht.name & "'" & "!RC[-16],'LTE 2C'!C[-13],0))"
Nelly is correct, but another way to do this would be to simply remove the unnecessary extra string for each apostrophe and replace it with this:
ActiveSheet.Cells(counter, 16) = _
"=INDEX('LTE 2C'!C[55],MATCH('" & sht.name & "'!RC[-14],'LTE 2C'!C[-11],0))"
Where the apostrophes are just attached to the strings before and after. It really makes no difference, but it removes the extra (&)s.

Find matching cell with different strings inside one cell

My goal of my macro:
I have 2 sheets, sheet1 master report and sheet2 import Input.
In column A of both sheets I have several strings in one cell.
I would like to see if there is a match and if there is the match the row from sheet2 (from column B) will be copied and paste in the row corresponding in sheet1.
This part of my code is done.
But now it starts to be tricky: If there is new string in the same cell as the matching string so I would like to add them as well in the cell of the column A sheet1.
For instance:
Sheet1 Column A Cell34:
MDM-9086
Sheet2 Column A Cell1:
MDM-9086,MDM-12345
After the macro it would be like this:
Sheet1 Column A cell34:
MDM-9086,MDM-12345
If there is no match between column A of both sheets so I would like to copy the entire row of the sheet2 and past it in the last free row of the sheet1.
See my code:
Sub MDMNumbers()
Dim LastRw1 As Long, LastRw2 As Long, NxtRw As Long
Dim I As Integer
Dim m As Range
Dim Tb
LastRw1 = Sheets(1).Range("A" & Rows.Count).End(xlUp).Row
LastRw2 = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row
With Worksheets(2)
LastRw2 = .Range("A" & Rows.Count).End(xlUp).Row
For NxtRw = 2 To LastRw2
Tb = Split(.Range("A" & NxtRw), ",")
For I = 0 To UBound(Tb)
With Sheets(1).Range("A2:A" & LastRw1)
Set m = .Find(Trim(Tb(I)), LookAt:=xlPart)
If Not m Is Nothing Then
Sheets(2).Range("B" & NxtRw & ":Q" & NxtRw).Copy _
Sheets(1).Range("B" & m.Row)
Set m = Nothing
End If
End With
Next I
Next NxtRw
End With
End Sub
Example:
Sheet 1, Column A (start row 2)
MDM-123,MDM-27827
MDM-1791728,MDM-124
MDM-125
MDM-126,MDM-28920
MDM-127,MDM-1008
""
Sheet 2, Column A (start row 2)
MDM-123,MDM-27272
MDM-124
MDM-125,MDM-1289
MDM-126
MDM-1008
MDM-127
MDM-172891
Result on Sheet 1, Column A (start row 2):
MDM-123,MDM-27827,MDM-27272
MDM-124,MDM-1791728
MDM-125,MDM-1289
MDM-126,MDM-28920
MDM-127,MDM-1008
MDM-1008
MDM-172891
For your # 2.
Option Explicit
Public Sub MDMNumbers()
Dim LastRw1 As Long, LastRw2 As Long, NxtRw As Long, rng1 As Range, rng2 As Range
Dim i As Long, m As Range, tb() As String, celVal As String, notFound As Boolean
Dim additions1 As String, additions2 As String
LastRw1 = Worksheets(1).Range("A" & Worksheets(1).Rows.Count).End(xlUp).Row + 1
LastRw2 = Worksheets(2).Range("A" & Worksheets(2).Rows.Count).End(xlUp).Row
notFound = True
For NxtRw = 2 To LastRw2
celVal = Worksheets(2).Range("A" & NxtRw).Value2
If Len(celVal) > 0 Then
tb = Split(celVal, ",")
For i = 0 To UBound(tb)
Set m = Worksheets(1).Columns(1).Find(Trim(tb(i)), LookAt:=xlPart)
If Not m Is Nothing And notFound Then
Set rng1 = Worksheets(2).Range("B" & NxtRw & ":Q" & NxtRw)
Set rng2 = Worksheets(1).Range("B" & m.Row & ":Q" & m.Row)
rng1.Copy rng2
With Worksheets(2).Range("A" & NxtRw)
additions1 = Replace(.Value2, "," & tb(i), vbNullString)
additions1 = Replace(additions1, tb(i) & ",", vbNullString)
additions1 = Replace(additions1, tb(i), vbNullString)
End With
With Worksheets(1).Range("A" & m.Row)
additions2 = Replace(.Value2, "," & tb(i), vbNullString)
additions2 = Replace(additions2, tb(i) & ",", vbNullString)
additions2 = Replace(additions2, tb(i), vbNullString)
If Len(additions2) > 0 Then
If Len(additions1) > 0 Then
.Value2 = tb(i) & "," & additions2 & "," & additions1
Else
.Value2 = tb(i) & "," & additions2
End If
Else
.Value2 = tb(i) & "," & additions1
End If
End With
Set m = Nothing
notFound = False
End If
Next
If notFound Then
Set rng1 = Worksheets(2).Range("A" & NxtRw & ":Q" & NxtRw)
Set rng2 = Worksheets(1).Range("A" & LastRw1 & ":Q" & LastRw1)
rng1.Copy rng2
LastRw1 = LastRw1 + 1
End If
notFound = True
End If
Next
End Sub
It should work as expected now
Test data and result:
Why don't you copy the whole row from sheet2 to sheet1 like
For NxtRw = 2 To LastRw2
...
Sheets(2).Range("A" & NxtRw & ":Q" & NxtRw).Copy _
Sheets(1).Range("A" & m.Row)
...
Next NxtRw
? (The rest of the loop should stay the same.)

How to increase only last digit of a serial number string in Excel VBA?

I'm new to vba and trying to write a barcode scanner algorithm. It works fine right now but I want to keep serial numbers in my exel table and their structure has to be like "A151000". I want with each barcode entered a cell with an inputbox also be assigned to a serial number. for example when a new entry(Barcode) written in column C I want in column B serial numbers last digit increased by 1 and stored in that cell automatically.
Right now I can drag the cell from corner and exel increases the last digit. How can I trigger this with new entries automatically? Thanks in advance.
A151000
A151001
A151002
...
Sub DataInput()
Dim SearchTarget As String
Dim myRow As Long
Dim Rng As Range
Static PrevCell As Range
Dim FoundCell As Range
Dim CurCell As Range
Dim a As String
Dim Target As Range
Dim buttonclick As Boolean
V = True
If PrevCell Is Nothing Then
myRow = Selection.Row
Set PrevCell = Range("C" & myRow)
End If
Set Rng = Range("C:C,C:C") 'Columns for search defined here
With Rng
Set FoundCell = .Cells.Find(What:=SearchTarget, _
After:=PrevCell, LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, _
MatchCase:=True)
End With
Dim Eingabezahl As String
Do While Eingabezahl! = ""
Eingabezahl = InputBox("Last barcode scanned" & " " & Eingabezahl)
Range("C" & Range("C" & Rows.Count).End(xlUp).Row + 1) = Eingabezahl
Range("D" & Range("D" & Rows.Count).End(xlUp).Row + 1) = Now()
Range("E" & Range("E" & Rows.Count).End(xlUp).Row + 1) = "VALID"
Loop
End Sub
TO use the Autofill function and not change your original code you could just add in the autofill in your sub:
Dim Eingabezahl As String
Dim rngLastBCell As Range
Do While Eingabezahl = ""
Eingabezahl = InputBox("Last barcode scanned" & " " & Eingabezahl)
Set rngLastBCell = Range("B" & Rows.Count).End(xlUp)
rngLastBCell.AutoFill Destination:=Range(rngLastBCell, rngLastBCell.Offset(1)), Type:=xlFillDefault
Range("C" & Range("C" & Rows.Count).End(xlUp).Row + 1) = Eingabezahl
Range("D" & Range("D" & Rows.Count).End(xlUp).Row + 1) = Now()
Range("E" & Range("E" & Rows.Count).End(xlUp).Row + 1) = "VALID"
Loop
Or you could use the following that using the same concept (an autofill) but condenses al of your calls to the worksheet into a single line:
Dim Eingabezahl As String
Dim rngLastBCell As Range
Do While Eingabezahl = ""
Eingabezahl = InputBox("Last barcode scanned" & " " & Eingabezahl)
Set rngLastBCell = Range("B" & Rows.Count).End(xlUp)
rngLastBCell.AutoFill Destination:=Range(rngLastBCell, rngLastBCell.Offset(1)), Type:=xlFillDefault
rngLastBCell.Offset(1, 1).Resize(, 3) = Array(Eingabezahl, Now(), "VALID")
Loop
Although I would recommend just using appenending the current row to the end of your serial and not making as many calls to the worksheet by using an array:
Dim rngB As Range
Dim Eingabezahl As String
Dim SerialBase As String
SerialBase = "A15100"
Do While Eingabezahl = ""
Eingabezahl = InputBox("Last barcode scanned" & " " & Eingabezahl)
Set rngB = Range("B" & Rows.Count).End(xlUp).Offset(1)
rngB.Resize(, 4).Value = Array(SerialBase & rngB.Row, Eingabezahl, Now(), "VALID")
Loop