Creating new column and insert value base on another column - vba

I need help.
Currently I need to optimize the way i code and the process. Is there an alternative way for me to do this? The only way to differeniate the value is by the the first to digits. And there are hundred over values. As you can see in the codes, 99 will be assign value of 1042, 95 will be assign 261 and this goes on. How do I make it easier so that I have to input the values manually.Thanks in advance guys
Sub Netting()
Dim Found As Range
Dim LR As Long
Dim ws As Worksheet
Dim cell As Range
Dim a As Variant, v As Variant
Set ws = Sheets("PAYABLES - OUTFLOWS")
Set Found = ws.Rows(1).Find(What:="Invoice amount", _
LookIn:=xlValues, lookat:=xlWhole)
If Found Is Nothing Then Exit Sub
a = [{"HI99162152",1042;"HI99162159",1042;"99162161",1042;"HI95400159",261; "HI95400164", 261; "HI97500493",3004;"HI97500497", 3004 }] 'create 2-d lookup array
LR = ws.Cells(ws.Rows.Count, Found.Column).End(xlUp).Row
Found.Offset(0, 1).EntireColumn.Insert
ws.Cells(1, Found.Column + 1).Value = "Netting"
For Each cell In ws.Range(ws.Range("C2"), ws.Cells(LR, 3))
v = Application.VLookup(cell.Value, a, 2, False)
cell.EntireRow.Cells(Found.Column + 1).Value = IIf(IsError(v), "", v)
Next cell
End Sub

Sub Netting()
Dim Found As Range
Dim LR As Long
Dim ws As Worksheet
Dim cell As Range
Dim a As Variant, v As Variant, num
Set ws = Sheets("PAYABLES - OUTFLOWS")
Set Found = ws.Rows(1).Find(What:="Invoice amount", _
LookIn:=xlValues, lookat:=xlWhole)
If Found Is Nothing Then Exit Sub
a = [{"99",1042;"95",261;"97",3004}] 'create 2-d lookup array
LR = ws.Cells(ws.Rows.Count, Found.Column).End(xlUp).Row
Found.Offset(0, 1).EntireColumn.Insert
ws.Cells(1, Found.Column + 1).Value = "Netting"
For Each cell In ws.Range(ws.Range("C2"), ws.Cells(LR, 3))
num = Cstr(Mid(cell.Value, 3, 2))
v = Application.VLookup(num, a, 2, False)
cell.EntireRow.Cells(Found.Column + 1).Value = IIf(IsError(v), "", v)
Next cell
End Sub
If there are a large number of values in your array then it might be easier to manage that as a table on a worksheet.

Related

VBA finding value and put it in specific column

Hope you you can help me here. I have a repetitive task every week, which I could do the same way every single time through Excel formulas, but I am looking for a more automated way of going about this.
What I want to achieve is to set-up a dynamic range that will look for multiple key words such as in this case "OA" & "SNC" and if it matches it will return the value in the column G & H respectively. At the same time it has to skip blank rows. What is the best way to go about this?
I figured it shouldn't be too hard, but I cannot figure it out.
As per image above, I want to consolidate the charges per category (OA & SNC) in the designated columns ("G" & "H") on row level.
My approach to the task
Procedure finds data range, loops through it's values, adding unique values to the dictionary with sum for specific row and then loads all these values along with sums per row.
Option Explicit
Sub CountStuff()
Dim wb As Workbook, ws As Worksheet
Dim lColumn As Long, lRow As Long, lColTotal As Long
Dim i As Long, j As Long
Dim rngData As Range, iCell As Range
Dim dictVal As Object
Dim vArr(), vArrSub(), vArrEmpt()
'Your workbook
Set wb = ThisWorkbook
'Set wb = Workbooks("Workbook1")
'Your worksheet
Set ws = ActiveSheet
'Set ws = wb.Worksheets("Sheet1")
'Number of the first data range column
lColumn = ws.Rows(1).Find("1", , xlValues, xlWhole).Column
'Number of the last row of data range
lRow = ws.Cells(ws.Rows.Count, lColumn).End(xlUp).Row
'Total number of data range columns
lColTotal = ws.Cells(1, lColumn).End(xlToRight).Column - lColumn + 1
'Data range itself
Set rngData = ws.Cells(1, lColumn).Resize(lRow, lColTotal)
'Creating a dictionary
Set dictVal = CreateObject("Scripting.Dictionary")
'Data values -> array
vArr = rngData.Offset(1, 0).Resize(rngData.Rows.Count - 1, _
rngData.Columns.Count).Value
'Empty array
ReDim vArrEmpt(1 To UBound(vArr, 1))
'Loop through all values
For i = LBound(vArr, 1) To UBound(vArr, 1)
For j = LBound(vArr, 2) To UBound(vArr, 2)
'Value is not numeric and is not in dictionary
If Not IsNumeric(vArr(i, j)) And _
Not dictVal.Exists(vArr(i, j)) Then
'Add value to dictionary
dictVal.Add vArr(i, j), vArrEmpt
vArrSub = dictVal(vArr(i, j))
vArrSub(i) = vArr(i, j - 1)
dictVal(vArr(i, j)) = vArrSub
'Value is not numeric but already exists
ElseIf dictVal.Exists(vArr(i, j)) Then
vArrSub = dictVal(vArr(i, j))
vArrSub(i) = vArrSub(i) + vArr(i, j - 1)
dictVal(vArr(i, j)) = vArrSub
End If
Next j
Next i
'Define new range for results
Set rngData = ws.Cells(1, lColumn + lColTotal - 1). _
Offset(0, 2).Resize(1, dictVal.Count)
'Load results
rngData.Value = dictVal.Keys
For Each iCell In rngData.Cells
iCell.Offset(1, 0).Resize(lRow - 1).Value _
= Application.Transpose(dictVal(iCell.Value))
Next
End Sub
I've used a simple custom function, possibly overkill as this could be done with worksheet formulae, but given that your ranges can vary in either direction...
Function altsum(r As Range, v As Variant) As Variant
Dim c As Long
For c = 2 To r.Columns.Count Step 2
If r.Cells(c) = v Then altsum = altsum + r.Cells(c - 1)
Next c
If altsum = 0 Then altsum = vbNullString
End Function
Example below, copy and formula in F2 across and down (or apply it one go with another bit of code).

Copy Specific Range from one workbook to another based on condition

Thanks for taking the time to read this. I have a Master contact workbook containing a list of people who need follow up calls. In the very first column of this workbook the initials of the person being assigned the follow-up call are listed (example: CWS). What I want is a formula that will scan all cells in the first column for a set of initials, and then copy the data from columns E through J to a new workbook assigned specifically to that case manager. The code below is just a skeleton, but it was enough to do a small test run. I haven't touched VBA in 10 years so I'm sure it's far from perfect
Sub MoveContactInfo()
Dim xrow As Long
xrow = 4
Sheets("Master Data Set").Select
Dim lastrow As Long
lastrow = Cells(Rows.Count, 1).End(x1Up).Row
Dim rng As Range
Do Until xrow = lastrow + 1
ActiveSheet.Cells(xrow, 1).Select
If ActiveCell.Text = "CWS" Then
rng = Range(Cells(xrow, 5), Cells(xrow, 10))
rng.Copy
Workbooks.Open Filename:="D:\My Documents\Excel Spreadsheets\TEST.xls"
Worksheets("CWS").Select
Cells(4, 1).PasteSpecial
End If
xrow = xrow + 1
Loop
End Sub
Thanks so much for the help. Please let me know if there's anything else I can clarify. For now, I'm just trying to paste to a test workbook I've created filled with worksheets named after each Case Manager.
I would avoid the Do Loop if you're only searching for a single value one time. If you need to modify it to search for the same value more then once, you'll find some good examples of using Range().FindNext here: Range.FindNext Method (Excel).
Sub MoveContactInfo()
Dim Search As String
Dim f As Range
Dim wb As Workbook
Search = "CWS"
With Sheets("Master Data Set")
Set f = .Range("A1", .Range("A" & .Rows.Count).End(xlUp)).Find(What:=Search, After:=Range("A1"), LookAt:=xlWhole, MatchCase:=False)
If Not f Is Nothing Then
Set wb = Workbooks.Open(FileName:="D:\My Documents\Excel Spreadsheets\TEST.xls")
If Not wb Is Nothing Then
On Error Resume Next
f.EntireRow.Columns("E:J").Copy wb.Worksheets(Search).Cells(4, 1)
On Error GoTo 0
End If
End If
End With
End Sub
UPDATE: The OP states in a comment that there are multiple records that need to be copied.
I modified the code to collect the data in an array and write the data to the range in a single operation.
Sub MoveContactInfo()
Dim Search As String
Dim f As Range
Dim Data() As Variant
Dim x As Long
Dim wb As Workbook, ws As Worksheet
Search = "CWS"
ReDim Data(5, x)
With Sheets("Master Data Set")
For Each f In .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
If f.Value = Search Then
ReDim Preserve Data(6, x)
Data(0, x) = f(1, "E")
Data(1, x) = f(1, "F")
Data(2, x) = f(1, "G")
Data(3, x) = f(1, "H")
Data(4, x) = f(1, "I")
Data(5, x) = f(1, "J")
x = x + 1
End If
Next
If Not f Is Nothing Then
Set wb = Workbooks.Open(Filename:="D:\My Documents\Excel Spreadsheets\TEST.xls")
If Not wb Is Nothing Then
On Error Resume Next
Set ws = wb.Worksheets(Search)
On Error GoTo 0
If ws Is Nothing Then
MsgBox "Worksheet not found-> " & Search, vbInformation, "Retry"
Else
ws.Cells(4, 1).Resize(UBound(Data, 2), UBound(Data, 1)) = Application.Transpose(Data)
End If
End If
End If
End With
End Sub
Tidied a few things up. You were pretty close, good effort with being out so long.
Sub MoveContactInfo()
Dim xrow As Long
Dim rng As Range
Set ws = ThisWorkbook.Sheets("Master Data Set")
Set wsDest = Workbooks.Open("D:\My Documents\Excel Spreadsheets\TEST.xlsx")
xrow = 4
ilastrow = ws.Cells(Rows.Count, 1).End(xlUp).Row
initial = "CWS"
j = 1
For i = xrow To ilastrow
If ws.Cells(i, 1).text = initial Then
ws.Range("E" & i & ":J" & i).Copy Destination:=wsDest.Sheets(initial).Range(Cells(j, 1), Cells(j, 6))
j = j + 1
End If
Next i
End Sub

How to optimize the vba code to search value from different sheet

I have written this below code to automate search function for a value T5536
which is in A1 cell of sheet1 and compare the A1 cell value with a column from sheet2 which has n number of values.
When the A1 value T5536 matches the value from Sheet2 A column then it should update the Sheet1 with Corresponding ES or IS values.
If the ES value in Sheet2 has Indirect word or string then it should update IS value in sheet1.
Please find the below code for the same :-
Sub test()
Dim lrow As Long
Dim i, j As Variant
Dim ms, ws As Worksheet
Dim num, esr, isr,x As Long
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set ms = Worksheets("sheet1")
Worksheets("Sheet2").Activate
ms.Cells(2, 3) = ""
ms.Cells(2, 2) = ""
Set ws = Worksheets("Sheet2")
num = WorksheetFunction.Match("number", Range("1:1"), 0)
esr = WorksheetFunction.Match("ES", Range("1:1"), 0)
isr = WorksheetFunction.Match("IS", Range("1:1"), 0)
x = sheet2.cells(sheet2.rows.count,"A").end(xlup).row
FoundRange = ms.Range("A1")
For i = 2 To x
If ws.Cells(i, num) = FoundRange Then
Worksheets("sheet1").Activate
ms.Cells(2, 3) = ws.Cells(i, isr)
If ws.Cells(i, es) = "indirect" Then
ms.Cells(2, 2) = ws.Cells(i, is)
Else
ms.Cells(2, 2) = ws.Cells(i, es)
End If
End If
If ms.Cells(2, 2) <> "" Then
Exit For
End If
Next i
End Sub
The following code will work and takes less time when there are only few values to match in sheet2 A column, but if there are n number of values in sheet2 then it will be difficult to go through for loop and fulfil the task, kindly help me in tweaking this code to search the value very fast and update the corresponding values.
I have attached the images which might help to analyse the query.
Check it out. You can edit this code as you require.
Sub loopExample()
Dim sh As Worksheet, ws As Worksheet
Dim LstRw As Long, Frng As Range
Dim rng As Range, c As Range, x
Set sh = Sheets("Sheet1")
Set ws = Sheets("Sheet2")
Set Frng = sh.Range("A1")
With ws
LstRw = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range("A2:A" & LstRw)
End With
For Each c In rng.Cells
If c = Frng Then
x = IIf(c.Offset(0, 1) = "indirect", 2, 1)
sh.Range("B2") = c.Offset(0, x)
End If
Next c
End Sub

Identifier too long

I am faced with this problem: "Identifier too long". What can I do to fix this? I tried using a break "_" . But there will another error: Missing end bracket. Thanks guys.
Sub Netting()
Dim Found As Range
Dim LR As Long
Dim ws As Worksheet
Dim cell As Range
Dim a As Variant, v As Variant, num
Set ws = Sheets("PAYABLES - OUTFLOWS")
Set Found = ws.Rows(1).Find(What:="Invoice Amount", _
LookIn:=xlValues, lookat:=xlWhole)
If Found Is Nothing Then Exit Sub
a = [{"991",1042;"916", 1042;"954",261;"975",3004;"938",726;"901",762;"482",728; _
"482",728;"934",723;"200",724;"201",724;"952",724;"992",3030;"980",3207;"116",626;"939",722;"390",517;"484",548;"339",59;"141",717;"935",59;"994",3370;"140",8408;"950",775;"370", 734 }] 'create 2-d lookup array
LR = ws.Cells(ws.Rows.Count, Found.Column).End(xlUp).Row
Found.Offset(0, 1).EntireColumn.Insert
ws.Cells(1, Found.Column + 1).Value = "Netting"
For Each cell In ws.Range(ws.Range("C2"), ws.Cells(LR, 3))
num = CStr(Mid(cell.Value, 3, 3))
v = Application.VLookup(num, a, 2, False)
cell.EntireRow.Cells(Found.Column + 1).Value = IIf(IsError(v), "", v)
Next cell
End Sub
There is a limit on the number of characters per line. You can accomplish this using a much simpler way. Add your data to a spreadsheet ("Sheet1" for example) and in column A and column B.
Sub Assign2DVector()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim a As Variant
a = ws.Range("A1:B20").Value ' set to whatever your actual range is
End Sub

VBA check for value in a range

I am trying to loop through a column and if cells = "what i'm lookng for" then do something.
I have this so far, where I'm off is in the if statement where I check for the "name":
Option Explicit
Sub test()
Dim wksDest As Worksheet
Dim wksSource As Worksheet
Dim rngSource As Range
Dim name As String
Dim LastRow As Long
Dim LastCol As Long
Dim c As Long
Application.ScreenUpdating = False
Set wksSource = Worksheets("Sheet1")
With wksSource
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
For c = 16 To 20
LastRow = .Cells(.Rows.Count, c).End(xlUp).Row
Set rngSource = .Range(.Cells(5, 16), .Cells(LastRow, 16))
name = rngSource.Value
If name = "mark"
do something
End If
Next c
End With
Application.ScreenUpdating = True
'MsgBox "Done!", vbExclamation
End Sub
OK Chris
Maybe a bit of simplification is required but also a few assumptions.
It doesn't seem like LastCol is being used for anything - so let's assume this is the Column you want to loop through.
Your loop has fixed start and end values yet you are determining the LastRow - so let's assume you want to start from row 5 (in your code) and loop to the LastRow in the LastCol.
In order to determine LastCol you must have data in the row you are using to do this - so let's assume that there are values in row 1 in all columns up to column you want to loop say 16 (in your code).
If you want to (IF) test for a single (string) value in this case then you must arrange for your rngSource to be a single cell value. You also don't need to assign this to a variable unless you need to use it again.
Finally, if you want to check for other values you may want to consider using a SELECT CASE structure in place of your IF THEN structure.
Have a look at the following and change my assumptions to meet your requirement - good luck.
Sub test()
Dim wksDest As Worksheet
Dim wksSource As Worksheet
Dim rngSource As Range
Dim name As String
Dim LastRow As Long
Dim LastCol As Long
Dim c As Long
Application.ScreenUpdating = False
Set wksSource = Worksheets("Sheet1")
With wksSource
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
LastRow = .Cells(Rows.Count, LastCol).End(xlUp).Row
FirstRow = 5
For c = FirstRow To LastRow
If .Range(.Cells(c, LastCol), .Cells(c, LastCol)).Value = "Mark" Then
MsgBox ("do something")
End If
Next c
End With
End Sub
You can just do that with one line.
If Not IsError(Application.Match(ValueToSearchFor, RangeToSearchIn, 0)) Then
'The value found in the given range
End If
Example:
Search for "Canada" in column C of sheet named "Country"
If Not IsError(Application.Match("Canada", Sheets("Country").Range("C:C"), 0)) Then
'The value found in the given range
End If
Pass value to find and Column where value need to be checked. It will return row num if its found else return 0.
Function checkForValue(FindString As String,ColumnToCheck as String) As Long
SheetLastRow = Sheets("Sheet1").Cells.Find(What:="*", SearchOrder:=xlRows, SearchDirection:=xlPrevious, LookIn:=xlValues).row
With Sheets("Sheet1").Range("$" & ColumnToCheck & "$1:$" & ColumnToCheck & "$" & CStr(SheetLastRow) )
Set rng = .Find(What:=FindString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
lookat:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not rng Is Nothing Then
checkForValue = rng.row 'return row its found
'write code you want.
Else
checkForValue = 0
End If
End With
End Function
I tried Hari's suggestion, but Application.Match works weird on range names (not recognizing them...)
Changed to: WorksheetFunction.Match(...
It works, but when value is not present A runtime ERROR jumps before IsError(...) is evaluated.
So I had to write a simple -no looping- solution:
dim Index as Long
Index = -1
On Error Resume Next
Index = WorksheetFunction.Match(Target,Range("Edificios"), 0) 'look for Target value in range named: Edificios
On Error GoTo 0
If Index > 0 Then
' code for existing value found in Range # Index row
End If
Remeber Excel functions first index = 1 (no zero based)
Hope this helps.
I'm guessing what you really want to do is loop through your range rngSource. So try
Set rngSource = .Range(.Cells(5, 16), .Cells(LastRow, 16))
for myCell in rngSource
if myCell.Value = "mark" then
do something
end if
next myCell