Copying data based on cell value - vba

I am a bit stuck and hoping to find some help. I have some experience in VBA but this particular problem exceeds my programming knowledge.
I have a sheet with 1000 - 1250 rows of data, and anywhere from 20 - 60 columns that can change monthly.
What I am hoping to do is look at each cell for an X, and when found it will create a new line on a separate tab. The line would contain the first cell in the row where the X was found and the column header from the column the X was found in.
I have been able to write some things that will find the X's in the sheet, create new items on another page and the like, but I can't get one script to do everything I need.
This is an example of the data structure:
Data
Expected result:
Output
Sorry for the links, I am too new to post photos.
Any help on how this can be achieved, documents, tips or the like would be super helpful and most appreciated. Thank you for looking!
Andrew
EDIT:
Some of the code I have put together:
Dim uSht As String
Dim wsExists As Boolean
Dim lRow As Long
Dim lcol As Long
Dim ws As Worksheet
Sub CopyData()
'Setup Sheetnames
uSht = "UPLOAD"
uTem = "TEMPLATE"
' Stop flicker
Application.ScreenUpdating = False
' Check for Upload Worksheet
WorksheetExists (uSht)
'MsgBox (wsExists)
If wsExists = False Then
' If it does not exist, create it
Call CreateSheet("UPLOAD")
End If
'Setup stuff
Dim i As Integer
Dim ws1 As Worksheet: Set ws1 = ThisWorkbook.Sheets(uTem)
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets(uSht)
lRow = Cells(Rows.Count, 1).End(xlUp).Row
lcol = Cells(1, Columns.Count).End(xlToLeft).Column
'MsgBox (lRow)
'MsgBox (lCol)
Range(Cells(lRow, lColumn)).Select
Application.ScreenUpdating = True
End Sub
Sub CreateSheet(wsName)
'Creates the uSht worksheet
With ThisWorkbook
.Sheets.Add(After:=.Sheets(.Sheets.Count)).Name = uSht
End With
End Sub
Function WorksheetExists(wsName As String) As Boolean
'Check to see if uSht exists and return.
wsName = UCase(wsName)
For Each ws In ThisWorkbook.Sheets
If UCase(ws.Name) = wsName Then
wsExists = True
Exit For
End If
Next
WorksheetExists = wsExists
End Function

Using FindAll from here: Extracting specific cells from multiple Excel files and compile it into one Excel file
(but change LookAt:=xlPart to LookAt:=xlWhole)
Rough outline:
Dim col, c, dest As Range
Set dest = sheets("results").Range("A2")
Set col = FindAll(sheets("data").range("a1").currentregion, "X")
For each c in col
dest.resize(1,2).value = array(c.entirerow.cells(1).value, _
c.entirecolumn.cells(1).value)
set dest = dest.offset(1, 0)
next

You need a Find/FindNext loop that will locate all X values in the first worksheet. After a found cell is located, the cell's row and column can be used to identify the location and project.
Option Explicit
Sub Macro1()
Dim addr As String, loc As String, pro As String
Dim ws2 As Worksheet, fnd As Range
Set ws2 = Worksheets("sheet2")
With Worksheets("sheet1")
Set fnd = .Cells.Find(What:="x", after:=.Cells(1, 1), _
LookIn:=xlFormulas, LookAt:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not fnd Is Nothing Then
addr = fnd.Address(0, 0)
Do
loc = .Cells(fnd.Row, "A").Value
pro = .Cells(1, fnd.Column).Value
With ws2
.Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0) = loc
.Cells(.Rows.Count, "A").End(xlUp).Offset(0, 1) = pro
End With
Set fnd = .Cells.FindNext(after:=fnd)
Loop Until addr = fnd.Address(0, 0)
End If
End With
End Sub

Related

Determine Range/Conditions for Copy/Paste Procedure

I need help defining my copy/paste process. I just need an example for the two conditions. The situation is as follows:
I need to search for for specific keywords in a sheet of wb1 and
copy/paste it to wb2 under certain conditions.
I dont know the specific sheet or the position of the keywords, so
every sheet in the wb should be checked
In case a keyword is found - condition 1 or condition 2 will be
applied, depending on the keyword:
Condition 1: if keyword in wb1 = "mx1" then copy/paste keyword to wb2
(specific position -> Sheet2, K7) and rename it to "Male". Result
would be: "Male" in K7 of Sheet2 in wb2.
Condition 2: if keyword in wb1 = "Data 1" then copy the
value(integer) of the adjoining cell to the right of it and paste to
wb2 (specific position -> Sheet3, K3). Result would be: "189" in K7
of Sheet3 in wb2.
A keyword can only have one of the conditions assigned.
Actually, my goal is to have a set of keywords, which have condition
1 or condition 2 assigned, as well as a specific paste-location in
wb2. So, every sheet should be checked according to the set of
keywords.
Example:
https://imgur.com/a/8VCNsrC
Would appreciate any help!
Code so far - only thing I need is condition 1 and 2....
Public Sub TransferFile(TemplateFile As String, SourceFile As String)
Dim wbSource As Workbook
Set wbSource = Workbooks.Open(SourceFile) 'open source
Dim rFnd As Range
Dim r1st As Range
Dim ws As Worksheet
Dim arr(1 To 2) As Variant
Dim i As Long
Dim wbTemplate As Workbook
Dim NewWbName As String
Dim wsSource As Worksheet
For Each wsSource In wbSource.Worksheets 'loop through all worksheets in source workbook
Set wbTemplate = Workbooks.Open(TemplateFile) 'open new template
'/* Definition of the value range */
arr(1) = "mx1"
arr(2) = "Data 1"
For i = LBound(arr) To UBound(arr)
For Each ws In ThisWorkbook.Worksheets
Debug.Print ws.Name
Set rFnd = ws.UsedRange.Find(what:=arr(i), LookIn:=xlValues, lookat:=xlPart, SearchOrder:=xlRows, _
SearchDirection:=xlNext, MatchCase:=False)
If Not rFnd Is Nothing Then
Set r1st = rFnd
Do
If i = 1 Then
wb2.Sheets("Sheet1").Range("A3").Value = "Male"
Else
wb2.Sheets("Sheet1").Range("B3").Value = rFnd.Offset(0, 1).Value
End If
Set rFnd = ws.UsedRange.FindNext(rFnd)
Loop Until r1st.Address = rFnd.Address
End If
Next
Next
NewWbName = Left(wbSource.Name, InStr(wbSource.Name, ".") - 1)
wbTemplate.SaveAs wbSource.Path & Application.PathSeparator & NewWbName & "_New.xlsx"
wbTemplate.Close False 'close template
Next wsSource
wbSource.Close False 'close source
End Sub
You can search a Range for a value, and a range applies to a (part of a) single sheet. So you need to search each worksheet separately. Similarly, you search for a single value, so in this case you need to issue 2 separate searches. I'd do it this way:
Dim rFnd As Range
Dim r1st As Range
Dim ws As Worksheet
Dim arr(1 to 2) As Variant
Dim i as Long
arr(1) = "mx1"
arr(2) = "Data 1"
For i = Lbound(arr) to Ubound(arr)
For Each ws In ThisWorkbook.Worksheets
Debug.Print ws.Name
Set rFnd = ws.UsedRange.Find(what:=arr(i), LookIn:=xlValues, lookat:=xlPart, SearchOrder:=xlRows, _
SearchDirection:=xlNext, MatchCase:=False)
If Not rFnd Is Nothing Then
Set r1st = rFnd
Do
If i = 1 then
wb2.Sheets("Sheet2").Range("K7").Value = "Male"
Else
wb2.Sheets("Sheet3").Range("K3").Value = rFnd.Offset(0, 1).Value
End If
Set rFnd = ws.UsedRange.FindNext(rFnd)
Loop Until r1st.Address = rFnd.Address
End If
Next
Next

Using Nexted for loop to iterate through all cells in a worksheet and all worksheets in a workbook

I am trying to update record on all worksheets in a workbook.
My search values are in column No 6 and the replace values are in column No 9
The code is only working for a worksheet not the entire worksheet at a time.
I tried this below but it is giving me an error
Sub AllWorksheetsLoop()
Dim WS_Count As Integer
Dim I As Integer
' Set WS_Count equal to the number of worksheets in the active
' workbook.
WS_Count = ActiveWorkbook.Worksheets.count
' Begin the loop.
For I = 1 To WS_Count
Dim N As Long
Dim count As Long
N = Cells(Rows.count, 1).End(xlUp).Row
For count = 1 To N
v1 = Cells(count, 6).Value
If v1 = "Palm Tree (M)" Then Cells(count, 9).Value = "='Project Comp Rate Akwa Ibom'!K7"
Next count
Next I
End Sub
Kindly assists pls
It sounds like you want something like, search column F of each worksheet for "Palm Tree (M)"; if found, enter the stated formula in the cell, on the same row, 3 columns to the right. I assume that you exclude the sheet referenced in the formula from being searched.
Option Explicit
Public Sub FindThatPhrase()
Application.ScreenUpdating = False
Dim ws As Worksheet, found As Range
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Project Comp Rate Akwa Ibom" Then
Set found = GetAllMatches("Palm Tree (M)", ws.Columns("F"))
If Not found Is Nothing Then
Debug.Print ws.Name, found.Address
found.Offset(, 3) = "='Project Comp Rate Akwa Ibom'!$K$7"
End If
End If
Next ws
Application.ScreenUpdating = True
End Sub
Public Function GetAllMatches(ByVal findString As String, ByVal searchRng As Range) As Range
Dim foundCell As Range
Dim gatheredRange As Range
With searchRng
Set foundCell = searchRng.Find(findString)
Set gatheredRange = foundCell
Dim currMatch As Long
For currMatch = 1 To WorksheetFunction.CountIf(.Cells, findString)
Set foundCell = .Find(What:=findString, After:=foundCell, _
LookIn:=xlValues, Lookat:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False)
If Not gatheredRange Is Nothing Then
Set gatheredRange = Union(gatheredRange, foundCell)
Else
Set gatheredRange = foundCell
End If
Next currMatch
End With
Set GetAllMatches = gatheredRange
End Function

VBA: looping through worksheets using nested For Each having worksheet as variable

Newbie at vba here. I'm trying to apply a simple For Each loop (which nullifies cells < 0) to all worksheets in the workbook by nesting this inside another For Each loop.
When I try and run my code below I get an error and I'm not sure if it has anything to do with having worksheet as a variable within a Set statement.
Can't seem to figure this out/find a solution.
Thanks
Sub deleteNegativeValue()
Application.DisplayAlerts = False
Dim lastRow As Long
Dim ws As Worksheet
Dim cell As Range
Dim res As Range
For Each ws In Workbooks(1).Worksheets
Set res = ws.Range("1:1").Find("Value", lookat:=xlPart)
lastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
For Each cell In Range(ws.Cells(1, res.Column), ws.Cells(lastRow, res.Column))
If cell < 0 Then cell = ""
Next
Next
End Sub
Try this:
Sub deleteNegativeValue()
Dim lastRow As Long
Dim ws As Worksheet
Dim cell As Range
Dim res As Range
For Each ws In ThisWorkbook.Worksheets
Set res = ws.Range("1:1").Find("Value", lookat:=xlPart)
lastRow = ws.Range("A" & Rows.Count).End(xlUp).row
If Not res Is Nothing Then
For Each cell In ws.Range(ws.Cells(1, res.Column), ws.Cells(lastRow, res.Column))
If cell < 0 Then cell = ""
Next
Else
MsgBox "No Value found on Sheet " & ws.Name
End If
Next
End Sub
There needs to be a check on the Find method, to ensure that something was found
you could try this
Option Explicit
Sub deleteNegativeValue()
Dim ws As Worksheet
Dim res As Range
For Each ws In ThisWorkbook.Worksheets
Set res = Intersect(ws.Rows(1), ws.UsedRange).Find("value", LookAt:=xlPart)
If Not res Is Nothing Then
ws.Columns(res.Column).SpecialCells(xlCellTypeConstants, xlNumbers).Replace What:="-*", Replacement:="", SearchOrder:=xlByColumns, MatchCase:=False, LookAt:=xlWhole
Else
MsgBox "No Value found on Sheet " & ws.Name
End If
Next
End Sub
which should run faster since it doesn't iterate through every cell of each column and restrict the Find method range to the used one instead of the entire row.
the only warning is that the first row of all searched in sheets must not be empty...
Try the second for-each this way:
ws.Range(ws.Cells(1, res.Column), ws.Cells(lastRow, res.Column))

VBA code to complement search keyword on worksheet with copy rows selected to new worksheet

The code below basically searches for any keyword in any sheet and highlights it. My question is, how to also copy the entire row number where the word/words is/are found to a new sheet in addition to the highlight?
Is it also possible to precise in which worksheet the search will be done?
Many thanks in advance,
Gonzalo
Sub CheckMULTIVALUE()
'This macro searches the entire workbook for any cells containing the text "#MULTIVALUE" and if found _
highlight the cell(s) in yellow. Once the process has completed a message box will appear confirming completion.
Dim i As Long
Dim Fnd As String
Dim fCell As Range
Dim ws As Worksheet
Application.ScreenUpdating = False
Fnd = InputBox("Find what:", "Find and Highlight", "#MULTIVALUE")
If Fnd = "" Then Exit Sub
For Each ws In Worksheets
With ws
Set fCell = .Range("A1")
For i = 1 To WorksheetFunction.CountIf(.Cells, Fnd)
Set fCell = .Cells.Find(What:=Fnd, After:=fCell, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False)
If fCell Is Nothing Then
MsgBox Fnd & " not on sheet !!"
Exit For
Else
With fCell
.Interior.ColorIndex = 6
End With
End If
Next i
End With
Next ws
Application.ScreenUpdating = True
MsgBox "Check complete"
End Sub
Add code before the For loop to create the results worksheet or clear it if it already exists:
Dim results As Worksheet: Set results = ActiveWorkbook.Sheets("Results")
If results Is Nothing Then
Set results = ActiveWorkbook.Sheets.Add()
results.Name = "Results"
Else
results.Cells.Clear
End If
Create a reference to its A1 cell and a counter:
Dim resultsRange As Range: Set resultsRange = results.Range("A1")
Dim matches As Long
When you find a match add what you need to the Results worksheet and increment the counter.
With fCell
.Interior.ColorIndex = 6
resultsRange.Offset(matches, 0).Value = fCell.Row
resultsRange.Offset(matches, 1).Value = fCell.Value
matches = matches + 1
End With
To specify a specific sheet remove For Each ws In Worksheets and Next ws and replace With ws with With ActiveWorkbook.Sheets("SheetNameHere")

Excel VBA - Find and Replace from External File

I have a file that I would like to run a Find and Replace on using data from another Excel file.
I have this so far, what am I doing wrong?
Sub LegalName()
Dim NameListWB As Workbook
Dim NameListWS As Worksheet
Set NameListWB = Workbooks.Open("File.xlsx")
Set NameListWS = NameListWB.Worksheets("Sheet1")
Dim rng As Range
Set rng = NameListWS.Range("A:B").Select
Do Until IsEmpty(ActiveCell)
Worksheets("Sheet1").Columns("F").Replace _
What:=ActiveCell.Value, Replacement:=ActiveCell.Offset(0, 1).Value, _
SearchOrder:=xlByColumns, MatchCase:=False
ActiveCell.Offset(1, 0).Select
Loop
End Sub
I see that you started by declaring your objects but missed out on few. Also, you need to avoid the use of .Select Interesting Read
Is this what you are trying (UNTESTED)?
Sub Sample()
Dim NameListWB As Workbook, thisWb As Workbook
Dim NameListWS As Worksheet, thisWs As Worksheet
Dim i As Long, lRow As Long
'~~> This is the workbook from where your code is running
Set thisWb = ThisWorkbook
'~~> Change this to the sheet name where you want to replace
'~~> in Column F
Set thisWs = thisWb.Sheets("Sheet1")
'~~> File.xlsx
Set NameListWB = Workbooks.Open("C:\File.xlsx")
Set NameListWS = NameListWB.Worksheets("Sheet1")
With NameListWS
'~~> Find last row in Col A of File.xlsx
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Loop though Col A
For i = 1 To lRow
'~~> Do the replace
thisWs.Columns(6).Replace What:=.Range("A" & i).Value, _
Replacement:=.Range("B" & i).Value, _
SearchOrder:=xlByColumns, _
MatchCase:=False
Next i
End With
End Sub