How do you go through the specific worksheet and in a specific column for every row that contains word "firewall" - then insert an empty row above? The Row with "firewall" may be followed by rows that contain other values. The last line in the column is always "Grand Total". I supposed can be used as condition to stop the loop.
I found on Stack Overflow this example which is almost exactly what I need, but it does it only once, and I need through the entire column for all matches. The worksheet should be specified.
Sub NewRowInsert()
Dim SearchText As String
Dim GCell As Range
SearchText = "Original"
Set GCell = Worksheets("Sheet2").Cells.Find(SearchText).Offset(1)
GCell.EntireRow.Insert
End Sub
My data example:
firewall abc
policy x
policy y
firewall xyz
policy z
policy xxx
Grand Total
Insert Rows (Find feat. Union)
Option Explicit
Sub NewRowInsert()
Const sText As String = "FirEWaLL"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1")
Dim LastRow As Long: LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim rg As Range: Set rg = ws.Range("A2:A" & LastRow)
Dim sCell As Range: Set sCell = rg.Find(sText, , xlFormulas, xlPart)
Application.ScreenUpdating = False
Dim trg As Range
Dim sCount As Long
If Not sCell Is Nothing Then
Dim FirstAddress As String: FirstAddress = sCell.Address
Do
If trg Is Nothing Then
Set trg = sCell
Else
Set trg = Union(trg, sCell.Offset(, sCount Mod 2))
End If
sCount = sCount + 1
Set sCell = rg.FindNext(sCell)
Loop Until sCell.Address = FirstAddress
trg.EntireRow.Insert
End If
Application.ScreenUpdating = True
Select Case sCount
Case 0
MsgBox "'" & sText & "' not found.", vbExclamation, "Fail?"
Case 1
MsgBox "Found 1 occurrence of '" & sText & "'.", _
vbInformation, "Success"
Case Else
MsgBox "Found " & sCount & " occurrences of '" & sText & "'.", _
vbInformation, "Success"
End Select
End Sub
Related
I have been trying to find an way to create multiple sheets using Specific Column data.
If Col"A" has multiple duplicate entries then filter single value create the new sheet using that value name, copy all the data and paste into newly added sheet.
I am unable to elaborate this thing in words and sorry for my poor English, i have attached an example workbook.
Where Sheet1 has data using Column A code will create multiple sheets. Your help will be much appreciated.
Sub CopyPartOfFilteredRange()
Dim src As Worksheet
Dim tgt As Worksheet
Dim filterRange As Range
Dim copyRange As Range
Dim lastRow As Long
Set src = ThisWorkbook.Sheets("Sheet1")
Set tgt = ThisWorkbook.Sheets("Sheet8")
src.AutoFilterMode = False
lastRow = src.Range("A" & src.Rows.Count).End(xlUp).Row
Set filterRange = src.Range("A1:A" & lastRow)
Set copyRange = src.Range("A1:P" & lastRow)
filterRange.AutoFilter field:=1, Criteria1:="CC"
copyRange.SpecialCells(xlCellTypeVisible).Copy tgt.Range("A1")
End Sub
Data Sheet
CC New Sheet
DD New Sheet
Till the last value HH
Please, test the next adapted code:
Sub CopyPartOfFilteredRange()
Dim src As Worksheet, tgt As Worksheet, copyRange As Range, filterRange As Range, lastRow As Long
Dim dict As Object, filterArr, i As Long
Set src = ActiveSheet ' ActiveWorkbook.Sheets("Sheet1")
lastRow = src.Range("A" & src.rows.count).End(xlUp).row
Set copyRange = src.Range("A1:P" & lastRow)
Set filterRange = src.Range("A2:A" & lastRow) 'it assumes that there are headers on the first row
filterArr = filterRange.value 'place it in an array for faster iteration
Set dict = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(filterArr)
If filterArr(i, 1) <> "" Then dict(filterArr(i, 1)) = 1 'extract uniques strings
Next
filterArr = dict.Keys 'unique strings to be used in filterring
'some optimization:
With Application
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
End With
For i = 0 To UBound(filterArr)
src.AutoFilterMode = False
'insert the new sheet and name it as filterr criteria, or use the existing one, if any:
On Error Resume Next
Set tgt = ActiveWorkbook.Sheets(left(filterArr(i), 31))
If err.Number = 0 Then 'if sheets already exists:
tgt.cells.Clear 'clear its content and use it
Else 'if not, insert and name it:
Set tgt = ActiveWorkbook.Sheets.Add(After:=src)
If Len(filterArr(i)) > 31 Then filterArr(i) = left(filterArr(i), 31)
tgt.Name = filterArr(i): err.Clear
End If
On Error GoTo 0
filterRange.AutoFilter field:=1, Criteria1:=filterArr(i)
copyRange.SpecialCells(xlCellTypeVisible).Copy tgt.Range("A1")
Next i
src.AutoFilterMode = False
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = xlCalculationAutomatic
End With
MsgBox "Processed " & UBound(filterArr) & "PCP Provider Names..."
End Sub
The above code has been updated to process the active sheet (and sheets on active workbook).
It needs a little optimization (`ScreenUpdating`, `EnableEvents`, `Calculation`) and check if the sheet with a specific name already exists, clearing all (in such a case) and reuse it, instead of inserting a new one.
There is a lot going on here:
You want sheets named with the duplicate values in column A. First, you need the unique values, which you can find using the Unique function: https://support.microsoft.com/en-us/office/unique-function-c5ab87fd-30a3-4ce9-9d1a-40204fb85e1e
You need to pass those values into an array and then loop through each: https://www.automateexcel.com/vba/loop-through-array/
Then you need to copy the values and paste to each new sheet which can be done with the autofilter and usedrange.
Then you need a lot error handling for sheets added or deleted.
Try this solution:
Sub CopyPartOfFilteredRange()
Application.ScreenUpdating = False
Dim i As Long
Dim LastRow As Long
Dim UValues As Variant
Dim myrange As Range
Dim sht As Worksheet
Dim list As New Collection
Set sht = ThisWorkbook.Sheets(1)
On Error Resume Next
LastRow = sht.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row
If LastRow = 0 Then
MsgBox "Worksheet contains no data"
Application.ScreenUpdating = True
End
End If
On Error GoTo 0
Set myrange = sht.Range("A2:A" & LastRow)
On Error Resume Next
For Each Value In myrange
list.Add CStr(Value), CStr(Value) 'extract unique strings
Next
On Error GoTo 0
ReDim UValues(list.Count - 1, 0)
For i = 0 To list.Count - 1
UValues(i, 0) = list(i + 1)
Next
For i = LBound(UValues) To UBound(UValues)
If Len(UValues(i, 0)) = 0 Then
GoTo Nexti
Else
On Error Resume Next
ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)).Name = UValues(i, 0)
If Err.Number = "1004" Then
On Error GoTo 0
Application.DisplayAlerts = False
MsgBox "Worksheet name " & UValues(i, 0) & " already taken"
ActiveSheet.Delete
Application.DisplayAlerts = True
GoTo Nexti
Else
On Error GoTo 0
sht.AutoFilterMode = False
sht.UsedRange.AutoFilter Field:=1, Criteria1:=UValues(i, 0), VisibleDropDown:=False, Operator:=xlFilterValues
sht.UsedRange.SpecialCells(xlCellTypeVisible).Copy
With ThisWorkbook.Sheets(UValues(i, 0))
.Range("A1").PasteSpecial ''Set this to appropriate sheet number
End With
Application.CutCopyMode = False
End If
End If
Nexti:
Next i
sht.AutoFilterMode = False
Application.ScreenUpdating = True
End Sub
Create Unique Worksheets
This will delete each possibly existing sheet before it will add a new worksheet and copy the filtered data to it.
If a worksheet name exceeds the 31 character limit, its name will be truncated.
If a worksheet name is invalid, it will not be renamed.
The Solution
Option Explicit
Sub CopyUniqueWorksheets()
Const ProcTitle As String = "Copy Unique Worksheets"
Dim dTime As Double: dTime = Timer ' time measuring
Debug.Print "Started '" & ProcTitle & "' at '" & Now & "'." ' log
Const swsName As String = "Sheet1"
Const sCol As Long = 1
Const dFirstCellAddress As String = "A1"
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets(swsName)
If sws.AutoFilterMode Then sws.AutoFilterMode = False
Dim srg As Range: Set srg = sws.Range("A1").CurrentRegion ' Source Range
Dim srCount As Long: srCount = srg.Rows.Count ' Source Rows Count
If srCount < 2 Then Exit Sub ' just headers or no data at all
Dim sData As Variant: sData = srg.Columns(sCol).Value
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim dKey As Variant
Dim dString As String
Dim r As Long
' Write the unique strings to a dictionary.
For r = 2 To srCount
dKey = sData(r, 1)
If Not IsError(dKey) Then
If Len(dKey) > 0 Then
dString = CStr(dKey)
If StrComp(dString, swsName, vbTextCompare) <> 0 Then
dict(dString) = Empty
End If
End If
End If
Next r
If dict.Count = 0 Then Exit Sub ' only blanks and error values and whatnot
Erase sData
Application.ScreenUpdating = False
Dim scrg As Range ' Source Copy Range
Dim dws As Object
Dim dwsName As String
For Each dKey In dict.Keys
' Restrict to maximum allowed characters (31).
dwsName = dKey
If Len(dwsName) > 31 Then
dwsName = Left(dwsName, 31)
Debug.Print "'" & dKey & "' is too long." & vbLf _
& "'" & dwsName & "' is used in the continuation." ' log
End If
' Delete possibly existing sheet.
On Error Resume Next
Set dws = wb.Sheets(dwsName)
On Error GoTo 0
If Not dws Is Nothing Then ' destination sheet exists
Application.DisplayAlerts = False
dws.Delete
Application.DisplayAlerts = True
'Else ' destination sheet doesn't exist
End If
' Create a reference to a newly added (destination) worksheet.
Set dws = wb.Worksheets.Add(After:=wb.Sheets(wb.Sheets.Count))
' Rename Destination Worksheet.
On Error Resume Next
dws.Name = dwsName
If Err.Number <> 0 Then ' invalid sheet name
' log
Debug.Print "'" & dwsName & "' cannot be used as a sheet name."
'Else ' valid sheet name
End If
On Error GoTo 0
' Create a reference to the Source Copy Range.
srg.AutoFilter sCol, dKey
Set scrg = srg.SpecialCells(xlCellTypeVisible) ' headers are visible
sws.AutoFilterMode = False
' Copy the Source Copy Range to the Destination Worksheet.
scrg.Copy dws.Range(dFirstCellAddress)
' Initialize Destination Worksheet variable (reference).
Set dws = Nothing
Next dKey
sws.Activate
Application.ScreenUpdating = True
Debug.Print "It took " & Timer - dTime & " seconds." ' time measuring
Debug.Print "Ended '" & ProcTitle & "' at '" & Now & "'." ' log
MsgBox "Unique worksheets created.", vbInformation, ProcTitle
End Sub
Barely Related
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: In a workbook ('wb'), deletes all sheets except the ones
' whose names are in a list ('ExceptionsList').
' Remarks: At least one of the remaining sheets has to be visible.
' A very hidden sheet cannot be deleted.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub DeleteSheets()
On Error GoTo ClearError
Const ExceptionsList As String = "Sheet1"
Const Delimiter As String = "," ' tied to 'ExceptionsList'
Dim wb As Workbook: Set wb = ActiveWorkbook
Dim Exceptions() As String: Exceptions = Split(ExceptionsList, Delimiter)
Dim sh As Object
Dim ex As Long
Dim IsFoundVisibleSheet
For ex = 0 To UBound(Exceptions)
On Error Resume Next
Set sh = Nothing
Set sh = wb.Sheets(Exceptions(ex))
On Error GoTo ClearError
If Not sh Is Nothing Then ' sheet exists
If sh.Visible = xlSheetVisible Then ' sheet is visible
IsFoundVisibleSheet = True
Exit For
'Else ' sheet is not visible
End If
'Else ' sheet doesn't exist
End If
Next ex
If Not IsFoundVisibleSheet Then Exit Sub ' no remaining visible sheets
Dim SheetNames() As String: ReDim SheetNames(1 To wb.Sheets.Count)
Dim VeryHidden() As String: ReDim VeryHidden(1 To wb.Sheets.Count)
Dim sn As Long
Dim vh As Long
Dim shName As String
For Each sh In wb.Sheets
shName = sh.Name
If IsError(Application.Match(shName, Exceptions, 0)) Then
sn = sn + 1
SheetNames(sn) = shName
If sh.Visible = xlVeryHidden Then
vh = vh + 1
VeryHidden(vh) = shName
'Else ' sheet is not very hidden
End If
'Else ' sheet found in 'Exceptions'
End If
Next sh
If sn = 0 Then Exit Sub ' no sheets to delete
ReDim Preserve SheetNames(1 To sn)
If vh > 0 Then
ReDim Preserve VeryHidden(1 To vh)
For vh = 1 To vh
wb.Sheets(VeryHidden(vh)).Visible = xlSheetVisible
Next vh
'Else ' no very hidden sheets
End If
Application.DisplayAlerts = False ' delete without confirmation
wb.Sheets(SheetNames).Delete
Application.DisplayAlerts = True
ProcExit:
Exit Sub
ClearError:
Debug.Print "Run-time error '" & Err.Number & "': " & Err.Description
Resume ProcExit
End Sub
Initial (Old) Answer
The idea is valid, but it takes forever on OP's data.
This will delete each possibly existing sheet before copying the source worksheet and renaming it. Then it will filter it to delete the undesired rows (not entire rows) of the table range in the copied worksheet.
Option Explicit
Sub CopyUniqueWorksheets()
Const swsName As String = "Sheet1"
Const sCol As Long = 1
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets(swsName)
If sws.AutoFilterMode Then sws.AutoFilterMode = False
Dim srg As Range: Set srg = sws.Range("A1").CurrentRegion ' Table Range
Dim scrg As Range: Set scrg = srg.Columns(sCol) ' Column Range
Dim srCount As Long: srCount = scrg.Rows.Count
Dim dcrgAddress As String: dcrgAddress = scrg.Address(0, 0)
Dim sdrg As Range: Set sdrg = srg.Resize(srCount - 1).Offset(1) ' Data Range
Dim ddrgAddress As String: ddrgAddress = sdrg.Address(0, 0)
If srCount < 2 Then Exit Sub ' just headers or no data at all
Dim sData As Variant: sData = scrg.Value
Dim drgAddress As String: drgAddress = srg.Address(0, 0)
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim dKey As Variant
Dim dString As String
Dim r As Long
For r = 2 To srCount
dKey = sData(r, 1)
If Not IsError(dKey) Then
If Len(dKey) > 0 Then
dString = CStr(dKey)
If StrComp(dString, swsName, vbTextCompare) <> 0 Then
dict(dString) = Empty
End If
End If
End If
Next r
Application.ScreenUpdating = False
Dim dws As Object
Dim drg As Range ' Delete Range
Dim dcrg As Range ' Column Range
Dim ddrg As Range ' Data Range
For Each dKey In dict.Keys
' Delete possibly existing sheet.
On Error Resume Next
Set dws = wb.Sheets(dKey)
On Error GoTo 0
If Not dws Is Nothing Then ' destination sheet exists
Application.DisplayAlerts = False
dws.Delete
Application.DisplayAlerts = True
'Else ' destination sheet doesn't exist
End If
' Copy source worksheet.
sws.Copy After:=wb.Sheets(wb.Sheets.Count)
Set dws = ActiveSheet
' Rename destination worksheet.
On Error Resume Next
dws.Name = dKey
If Err.Number <> 0 Then
MsgBox "'" & dKey & "' is an invalid sheet name.", vbExclamation
End If
On Error GoTo 0
' Delete rows.
Set dcrg = dws.Range(dcrgAddress)
Set ddrg = dws.Range(ddrgAddress)
dcrg.AutoFilter 1, "<>" & dKey
On Error Resume Next
Set drg = ddrg.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
dws.AutoFilterMode = False ' to not delete entire rows
If Not drg Is Nothing Then
drg.Delete xlShiftUp
Set drg = Nothing
End If
Set dws = Nothing
Next dKey
sws.Activate
Application.ScreenUpdating = True
MsgBox "Unique worksheets created.", vbInformation
End Sub
I have the below macro that cuts my report up by name (when it asks me which column to filter on, its 2).
It works perfectly for I need, as it also saves down each cut per person for each report where the report is saved. However, I also need it to pick up everything by name of person in all other tabs in the report. EG: Dave Smith is on the main summary page, and the below macro cuts it by Dave Smith, and saves that cut down. But Dave Smith also has data in 7/8 other tabs, that also need to be included in the new, saved down cut.
Sub parse_data()
'This macro splits data into multiple worksheets
'based on the variables on a column found in Excel.
'An InputBox asks you which columns you'd like
'to filter by, and it just creates these worksheets.
Const TITLE_ROW = 1
Dim wbOut As Workbook
Dim ws As Worksheet, wsOut As Worksheet
Dim iLastRow As Long, iRow As Long
Dim iFilterCol As Integer
Dim sPath As String
' get filter column nu,ber
iFilterCol = Application.InputBox( _
prompt:="Which column would you like to filter by?", _
title:="Filter column", Default:="3", Type:=1)
If iFilterCol < 1 Then
MsgBox iFilterCol & " not valid", vbCritical
Exit Sub
End If
Set ws = ActiveSheet
sPath = ThisWorkbook.Path & "\"
iLastRow = ws.Cells(ws.Rows.Count, iFilterCol).End(xlUp).Row
Dim dict As Object, key
Set dict = CreateObject("Scripting.Dictionary")
' get unique values using dictionary
For iRow = TITLE_ROW + 1 To iLastRow
key = Trim(ws.Cells(iRow, iFilterCol))
If Not dict.exists(key) Then
dict.Add key, iRow
End If
Next
' create separate workbooks
Application.ScreenUpdating = False
For Each key In dict
' apply filter
ws.Rows(TITLE_ROW).AutoFilter Field:=iFilterCol, Criteria1:=key
' create new workbook
Set wbOut = Workbooks.Add
Set wsOut = wbOut.Sheets(1)
wsOut.Name = key
ws.Range("A" & TITLE_ROW & ":A" & iLastRow).EntireRow.Copy wsOut.Range("A1")
wsOut.Columns.AutoFit
' save and close
wbOut.SaveAs (sPath & key & ".xlsx")
wbOut.Close False
Next
ws.Activate
ws.AutoFilterMode = False
Application.ScreenUpdating = True
MsgBox dict.Count & " workbooks created", vbInformation
End Sub
Use Find to locate the filter column for the other sheets, apply filter and repeat the code for the first sheet.
Option Explicit
Sub parse_data()
'This macro splits data into multiple worksheets
'based on the variables on a column found in Excel.
'An InputBox asks you which columns you'd like
'to filter by, and it just creates these worksheets.
Const TITLE_ROW = 1
Dim wbOut As Workbook, wb As Workbook
Dim ws As Worksheet, wsOut As Worksheet, wsOther As Worksheet
Dim rng As Range
Dim iLastRow As Long, iRow As Long, iLastOther As Long
Dim iFilterCol As Integer, n As Integer
Dim sPath As String, sSummary As String
' get filter column nu,ber
iFilterCol = Application.InputBox( _
prompt:="Which column would you like to filter by?", _
Title:="Filter column", Default:="3", Type:=1)
If iFilterCol < 1 Then
MsgBox iFilterCol & " not valid", vbCritical
Exit Sub
End If
Set wb = ThisWorkbook ' or ActiveWorkbook
Set ws = ActiveSheet
sSummary = ws.Name
sPath = ThisWorkbook.Path & "\"
iLastRow = ws.Cells(ws.Rows.Count, iFilterCol).End(xlUp).Row
Dim dict As Object, key
Set dict = CreateObject("Scripting.Dictionary")
' get unique values using dictionary
For iRow = TITLE_ROW + 1 To iLastRow
key = Trim(ws.Cells(iRow, iFilterCol))
If Not dict.exists(key) Then
dict.Add key, iRow
End If
Next
' create separate workbooks
Application.ScreenUpdating = False
For Each key In dict
' apply filter
ws.Rows(TITLE_ROW).AutoFilter Field:=iFilterCol, Criteria1:=key
' create new workbook
Set wbOut = Workbooks.Add(xlWBATWorksheet) ' 1 sheet
Set wsOut = wbOut.Sheets(1)
wsOut.Name = key
ws.Range("A" & TITLE_ROW & ":A" & iLastRow).EntireRow.Copy wsOut.Range("A1")
wsOut.Columns.AutoFit
' search other worksheets
For Each wsOther In wb.Sheets
If wsOther.Name <> sSummary Then
'find name to get filter column
wsOther.AutoFilterMode = False
Set rng = wsOther.UsedRange.Find(CStr(key), LookIn:=xlValues, lookat:=xlWhole)
If Not rng Is Nothing Then
iLastOther = wsOther.Cells(ws.Rows.Count, rng.Column).End(xlUp).Row
wsOther.Rows(TITLE_ROW).AutoFilter _
Field:=rng.Column, Criteria1:=CStr(key)
n = wbOut.Sheets.Count
Set wsOut = wbOut.Sheets.Add(after:=wbOut.Sheets(n))
wsOut.Name = wsOther.Name
wsOther.Range("A" & TITLE_ROW & ":A" & iLastOther).EntireRow.Copy _
wsOut.Range("A1")
wsOut.Columns.AutoFit
End If
wsOther.AutoFilterMode = False
End If
Next
' save and close
wbOut.SaveAs (sPath & key & ".xlsx")
wbOut.Close False
Next
ws.Activate
ws.AutoFilterMode = False
Application.ScreenUpdating = True
MsgBox dict.Count & " workbooks created", vbInformation
End Sub
I need to find a specific word from an Excel file. I want to search row by row, and if the word is found, skip 2 rows down and copy the next 20 rows and loop to the next word.
Sub Example4()
Dim FilePath As Workbook
Dim wsheet As Worksheet
Dim i, lcount, lcount2 As Integer
Dim cell, rgFound As Range
Dim Found As Range, LastRow As Long
Set FilePath = Workbooks.Open("D:\SLC.txt")
Dim rowVal As Integer
rowVal = 1
For lcount = 1 To FilePath.Sheets("SLC").Range("A1048576").End(xlUp).Row
Set rgFound = Range("A1:A1048576").Find("TXN. NO TXN SEQ", ThisWorkbook.Sheets(), Cells(rowVal, 1))
FilePath.Cells(wsheet.Range(rowVal).End(xlDown).Row + 3).xlCopy
wbook2.Worksheets(1).Range("A1").PasteSpecial xlPasteValuesAndNumberFormats
wbook2.SaveAs ("D:\SLC_Copied.xlsx")
wbook2.Close
rowVal = rgFound1.Row
Debug.Print lcount
Next lcount
End Sub
As Siddharth Rout suggested, use Find and FindNext.
Try to choose variable names appropriate to their type, calling a workbook object FilePath is confusing to others trying to understand your script.
Option Explicit
Sub Example4()
Const TEXT = "TXN. NO TXN SEQ"
Const TEXT_FILENAME = "D:\SLC.txt"
Const OUT_FILENAME = "D:\SLC_Copied.xlsx"
Dim wbText As Workbook, wbOut As Workbook, rngOut As Range
Dim wsText As Worksheet, wsOut As Worksheet, count As Integer
Dim rngSearch As Range, rngFound As Range, rowFirstFind As Long
' open text file no link update, read only
Set wbText = Workbooks.Open(TEXT_FILENAME, False, True)
Set wsText = wbText.Sheets(1)
' search
Set rngSearch = wsText.Columns("A:A")
Set rngFound = rngSearch.Find(what:=TEXT, LookIn:=xlValues, LookAt:=xlPart)
If rngFound Is Nothing Then
wbText.Close
MsgBox "No lines match [" & TEXT & "]", vbCritical, "Exiting Sub"
Exit Sub
Else
' create new workbook for results
Set wbOut = Workbooks.Add
Set wsOut = wbOut.Sheets(1)
Set rngOut = wsOut.Range("A1")
rowFirstFind = rngFound.Row
Do
'Debug.Print rngFound.Row
rngFound.Offset(3, 0).Resize(20, 1).Copy rngOut
Set rngOut = rngOut.Offset(20, 0)
Set rngFound = rngSearch.FindNext(rngFound)
count = count + 1
Loop Until rngFound.Row = rowFirstFind
End If
wbText.Close False
wbOut.SaveAs OUT_FILENAME
MsgBox count & " blocks copied to " & wbOut.Name, vbInformation, "Finished"
wbOut.Close
End Sub
Basically i have this script which compare 2 sheets, which compares a value in a column to the new sheet, if it finds the value, it will copy the information from Old sheet "B" to new sheet "B" column.
The script is working flawlessly (Thanks to the author)
I have trying to configure it to search and compare not only 1 column, but 2, if column X AND Y are equal to X AND Y in the new sheet it will do the same task.
The reason for this is that sometimes i have the value it searches for in few different rows, so when it compares it will find it at few places. While this script works perfect only when there are unique "Find" values.
Can you help me to edit so it fits "Find" and compare Column "P" & Column "V" if those are the same in new sheet, it will copy the Values in Column "B" old sheet to "B" new sheet.
Sub movecommentsInternode()
Dim Wb As Workbook
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim rSourcePCol As Range
Dim rSourcePCell As Range
Dim rDestPCol As Range
Dim rFound As Range
Dim sFirst As String
Dim sNotFound As String
Set Wb = ActiveWorkbook
Set wsSource = Wb.Sheets("Internode Buffer")
Set wsDest = Wb.Sheets("DataInternode")
Set rSourcePCol = wsSource.Range("P2", wsSource.Cells(wsSource.Rows.Count, "P").End(xlUp))
Set rDestPCol = wsDest.Range("P2", wsDest.Cells(wsDest.Rows.Count, "P").End(xlUp))
If rSourcePCol.row < 2 Then
MsgBox "No comment available, therefor no import is needed " ' & wsSource.Name
Exit Sub
ElseIf rDestPCol.row < 2 Then
MsgBox "Data Sheet is empty, please import the correct IO-List to be able to merge the comments " ' & wsDest.Name
Exit Sub
End If
For Each rSourcePCell In rSourcePCol.Cells
Set rFound = rDestPCol.Find(rSourcePCell.Value, rDestPCol.Cells(rDestPCol.Cells.Count), xlValues, xlWhole)
If rFound Is Nothing Then
sNotFound = sNotFound & Chr(10) & rSourcePCell.Value
Else
sFirst = rFound.Address
Do
rFound.Offset(, -14).Value = rSourcePCell.Offset(, -14).Value
Set rFound = rDestPCol.FindNext(rFound)
Loop While rFound.Address <> sFirst
End If
Next rSourcePCell
If Len(sNotFound) = 0 Then
MsgBox ("Import completed" & vbCrLf & "All comments have been merged with the new imported IO-List")
Else
MsgBox ("Import completed" & vbCrLf & "The following tag-comments have not been merged with new IO-List:" & sNotFound)
End If
End Sub
Also as a extra thing: Can you help me make it show the missing tags in a list (New sheet) insted of as comment. Will be ackward if there is hundreds of missing tags showing all in Msgbox.
Give this a try:
Sub movecommentsInternode()
Dim Wb As Workbook
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim wsMissingTags As Worksheet
Dim rSourcePCol As Range
Dim rSourcePCell As Range
Dim rDestPCol As Range
Dim rFound As Range
Dim sFirst As String
Dim sNotFound As String
Dim bFound As Boolean
Dim aHeaders() As Variant
Dim aMissingTags As Variant
Set Wb = ActiveWorkbook
Set wsSource = Wb.Sheets("Internode Buffer")
Set wsDest = Wb.Sheets("DataInternode")
Set rSourcePCol = wsSource.Range("P2", wsSource.Cells(wsSource.Rows.Count, "P").End(xlUp))
Set rDestPCol = wsDest.Range("P2", wsDest.Cells(wsDest.Rows.Count, "P").End(xlUp))
If rSourcePCol.Row < 2 Then
MsgBox "No comment available, therefor no import is needed " ' & wsSource.Name
Exit Sub
ElseIf rDestPCol.Row < 2 Then
MsgBox "Data Sheet is empty, please import the correct IO-List to be able to merge the comments " ' & wsDest.Name
Exit Sub
End If
For Each rSourcePCell In rSourcePCol.Cells
bFound = False
Set rFound = rDestPCol.Find(rSourcePCell.Value, rDestPCol.Cells(rDestPCol.Cells.Count), xlValues, xlWhole)
If Not rFound Is Nothing Then
sFirst = rFound.Address
Do
If rSourcePCell.Offset(, 6).Value = rFound.Offset(, 6).Value Then
rFound.Offset(, -14).Value = rSourcePCell.Offset(, -14).Value
bFound = True
End If
If bFound = True Then Exit Do 'First match for both columns found, exit find loop (this line can be removed if preferred)
Set rFound = rDestPCol.FindNext(rFound)
Loop While rFound.Address <> sFirst
End If
If bFound = False Then sNotFound = sNotFound & "|" & rSourcePCell.Value & vbTab & rSourcePCell.Offset(, 6).Value
Next rSourcePCell
If Len(sNotFound) = 0 Then
MsgBox ("Import completed" & vbCrLf & "All comments have been merged with the new imported IO-List")
Else
On Error Resume Next
Set wsMissingTags = Wb.Worksheets("Missing Tags")
On Error GoTo 0
If wsMissingTags Is Nothing Then
'Missing Tags worksheet doesn't exist, create it and add headers
aHeaders = Array(wsSource.Range("P1").Value, wsSource.Range("V1").Value)
Set wsMissingTags = Wb.Worksheets.Add(After:=Wb.Worksheets(Wb.Worksheets.Count))
wsMissingTags.Name = "Missing Tags"
With wsMissingTags.Range("A1").Resize(, UBound(aHeaders) - LBound(aHeaders) + 1)
.Value = aHeaders
.Font.Bold = True
.Borders(xlEdgeBottom).LineStyle = xlContinuous
End With
Else
'Missing Tags worksheet already exists, clear previous contents (if any)
wsMissingTags.Range("A1").CurrentRegion.Offset(1).ClearContents
End If
aMissingTags = Split(Mid(sNotFound, 2), "|")
With wsMissingTags.Range("A2").Resize(UBound(aMissingTags) - LBound(aMissingTags) + 1)
.Value = Application.Transpose(aMissingTags)
.TextToColumns .Cells, xlDelimited, Tab:=True
End With
MsgBox "Import completed" & vbCrLf & "See the Missing Tags worksheet for a list of tag-comments that have not been merged with new IO-List."
End If
End Sub
It is a fine code. I modified and tried it and find working as per my understanding of your requirement The modified full code is:
Sub movecommentsInternode()
Dim Wb As Workbook
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim rSourceHCol As Range
Dim rDestHCol As Range
Dim rdestHCell As Range
Dim rSourceHCell As Range
Dim rSourceHCol2 As Range 'added
Dim rDestHCol2 As Range 'added
Dim rSourceHCell2 As Range 'added
Dim rdestHCell2 As Range 'added
Dim rFound As Range
Dim sFirst As String
Dim sNotFound As String
Set Wb = ActiveWorkbook
Set wsSource = Wb.Sheets("Internode Buffer")
Set wsDest = Wb.Sheets("DataInternode")
Set rSourceHCol = wsSource.Range("H2", wsSource.Cells(wsSource.Rows.Count, "H").End(xlUp))
Set rDestHCol = wsDest.Range("H2", wsDest.Cells(wsDest.Rows.Count, "H").End(xlUp))
'Next two lines added
Set rSourceHCol2 = wsSource.Range("V2", wsSource.Cells(wsSource.Rows.Count, "V").End(xlUp))
Set rDestHCol2 = wsDest.Range("V2", wsDest.Cells(wsDest.Rows.Count, "V").End(xlUp))
If rSourceHCol.Row < 2 Or rSourceHCol2.Row < 2 Then ' condition modified
MsgBox "No comment available, therefor no import is needed " ' & wsSource.Name
Exit Sub
ElseIf rDestHCol.Row < 2 Or rDestHCol2.Row < 2 Then ' condition modified
MsgBox "Data Sheet is empty, please import the correct IO-List to be able to merge the comments " ' & wsDest.Name
Exit Sub
End If
For Each rSourceHCell In rSourceHCol.Cells
Set rSourceHCell2 = rSourceHCell.Offset(0, 14) 'corresponding value in V Col Source Sheet
Set rFound = rDestHCol.Find(rSourceHCell.Value, rDestHCol.Cells(rDestHCol.Cells.Count), xlValues, xlWhole)
If rFound Is Nothing Then
sNotFound = sNotFound & Chr(10) & rSourceHCell.Value
Else
sFirst = rFound.Address
Do
'Next two lines and if clause added
Set rdestHCell2 = rFound.Offset(0, 14) 'corresponding value in V Col Destination Sheet
If rSourceHCell2.Value = rdestHCell2.Value Then ' added
rFound.Offset(0, -6).Value = rSourceHCell.Offset(0, -6).Value 'offset from H to B
End If
Set rFound = rDestHCol.FindNext(rFound)
Loop While rFound.Address <> sFirst
End If
Next rSourceHCell
If Len(sNotFound) = 0 Then
MsgBox ("Import completed" & vbCrLf & "All comments have been merged with the new imported IO-List")
Else
MsgBox ("Import completed" & vbCrLf & "The following tag-comments have not been merged with new IO-List:" & sNotFound)
End If
End Sub
Edit: line Set rSourceHCell2 = rSourceHCell.Offset(0, 14) moved after line For Each rSourceHCell In rSourceHCol.Cells . If it does not work try to use If StrComp(rSourceHCell2.Value, rDestHCell2.Value) = 0 Then in place of If rSourceHCell2.Value = rdestHCell2.Value Then
This code is for updating client information in my source document for a mail merge from a list that I can pull from my client server at any time.
I've hit a snag in this code near the end. The process it currently goes through is as follows:
user selects the merge document that needs to be updated
user selects the list with the updated addresses
code steps through the merge document, grabs the name of a company, then
searches through the second document for that company, copies the address information from the list, and
pastes it next to the company name in the merge document and
starts over with the next company name in the merge document
I'm currently stuck between steps four and five.'
here's a selection of the code I'm trying to adapt to search the source workbook, but I think this isn't going to work - I need to paste the found term into the macro workbook, and I have a gap in my knowledge of VBA here.
I can post my full code if necessary, but I didn't want to throw the whole thing in right away.
Thanks in advance!
Set sourcewkb = ActiveWorkbook
Dim rnnng As Range
Dim searchfor As String
Debug.Print celld
searchfor = celld
Set rnnng = Selection.Find(what:=searchfor)
If rnnng Is Nothing Then
Debug.Print "yes"
Else
Debug.Print "no"
End If
EDIT
I tried some of what was suggested in the comment, but I'm having an issue where the selection.find is finding the variable in question whether or not it's actually there. I think somehow it's searching in both workbooks?
Full code (some parts are marked out as notes for convenience during editing the code, they generally aren't the parts I'm concerned about):
UPDATED full code:
Sub addressfinder()
Dim rCell
Dim rRng As Range
Dim aftercomma As String
Dim celld As String
Dim s As String
Dim indexOfThey As Integer
Dim mrcell As Range
Dim alreadyfilled As Boolean
Dim nocompany As Boolean
Dim sourcewkb
Dim updaterwkb
Dim fd As FileDialog
Dim cellstocopy As Range
Dim cellstopaste As Range
Dim x As Byte
'select updater workbook
updaterwkb = "L:\Admin\Corporate Books\2015\letter macro\Annual Consent Letter Macro.xlsm"
'this is the finished updater workbook selecter.
' Set fd = Application.FileDialog(msoFileDialogFilePicker)
'
'
' Dim vrtselecteditem As Variant
' MsgBox "select the Annual Consent Letter Macro workbook"
'
' With fd
' If .Show = -1 Then
' For Each vrtselecteditem In .SelectedItems
'
'
' updaterwkb = vrtselecteditem
' Debug.Print updaterwkb
' Next vrtselecteditem
' Else
' End If
' End With
'select file of addresses
sourcewkb = "L:\Admin\Corporate Books\2015\letter macro\source workbook_sample.xlsx"
'this is the finished source select code
' Dim lngcount As Long
' If MsgBox("Have you gotten this year's updated contact list exported from Time Matters or Outlook?", vbYesNo, "confirm") = vbYes Then
' If MsgBox("Is the information in that excel workbook formatted per the instructions?", vbYesNo, "Confirm") = vbYes Then
' MsgBox "Good. Select that workbook now."
' Else
' MsgBox "Format the workbook before trying to update the update list"
' End If
' Else
' MsgBox "Have someone export you a client list with company name, client name, and client address"
'
' End If
'
'
' With Application.FileDialog(msoFileDialogOpen)
' .AllowMultiSelect = False
' .Show
' For lngcount = 1 To .SelectedItems.Count
' Debug.Print .SelectedItems(lngcount)
' sourcewkb = .SelectedItems(lngcount)
'
' Next lngcount
' End With
'
Workbooks.Open (sourcewkb)
'start the code
Set updaterwkb = ActiveWorkbook
Set rRng = Sheet1.Range("a2:A500")
For Each rCell In rRng.Cells
'boolean resets
alreadyfilled = False
nocompany = False
'setting up the step-through
s = rCell.Value
indexOfThey = InStr(1, s, ",")
aftercomma = Right(s, Len(s) - indexOfThey + 1)
celld = Left(s, Len(s) - Len(aftercomma))
Debug.Print rCell.Value, "celld", celld
Debug.Print "address", rCell.Address
'setting up already filled check
Set mrcell = rCell.Offset(rowoffset:=0, ColumnOffset:=6)
Debug.Print "mrcell", mrcell.Value
If Len(rCell.Formula) = 0 Then
Debug.Print "company cell sure looks empty"
nocompany = True
End If
If Len(mrcell.Formula) > 0 Then
Debug.Print "mrcell has content"
alreadyfilled = True
Else: Debug.Print "mrcell has no content"
End If
If alreadyfilled = False Then
If nocompany = False Then
'the code for copying stuff
'open source document
'search source document for contents of celld
'if contents of celld are found, copy everything to the right of the cell in which
'they were found and paste it horizontally starting at mrcell
'if not, messagebox "address for 'celld' not found
'Set sourcewkb = ActiveWorkbook
'
'Dim rnnng As Range
'Dim searchfor As String
'Debug.Print celld
'searchfor = celld
'
'Set rnnng = Selection.Find(what:=searchfor)
'If Not rnnng Is Nothing Then
' Debug.Print "yes"
' Else
' Debug.Print "no"
'
'End If
Dim wb1 As Workbook
Dim wb2 As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim company As String
Dim lastRow As Long
Dim rng As Variant
Dim llc As String
Dim inc As String
Dim searchfor As String
Set wb1 = ThisWorkbook
Set wb2 = Workbooks("source workbook_sample.xlsx") 'change workbook name
Set ws1 = ThisWorkbook.Worksheets(1) 'change worksheet #
Set ws2 = wb2.Worksheets(1) 'change worksheet #
llc = ",LLC"
inc = ",INC."
'lastRow = ws1.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row
With ws1
For i = 1 To 500
If Cells(i, 1).Value = searchfor Then
company = .Cells(i, 1)
With ws2
'change range as necessary
Set f = .Range("A1:D100").Find(company, LookIn:=xlValues)
If Not f Is Nothing Then
Debug.Print searcfor
fRow = f.Row
rng = .Range("B" & fRow & ":D" & fRow)
ws1.Range("B" & i & ":D" & i) = rng
End If
End With
End If
Next
End With
'
Else
Debug.Print "skipped cuz there ain't no company"
End If
Else
Debug.Print "skipped cuz it's filled"
End If
''
'
Debug.Print "next"
Next rCell
End Sub
fixed code:
With ws1
For i = 1 To 500
If Cells(i, 1).Value = searchfor Then
company = .Cells(i, 1)
With ws2
'change range as necessary
Set f = .Range("A1:D100").Find(company, LookIn:=xlValues)
If Not f Is Nothing Then
Debug.Print searcfor
fRow = f.Row
rng = .Range("B" & fRow & ":D" & fRow)
ws1.Range("B" & i & ":D" & i) = rng
End If
End With
End If
Next
End With
Dim wb1 As Workbook
Dim wb2 As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim company As String
Dim lastRow As Long
Dim rng As Variant
Dim llc As String
Dim inc As String
Dim searchfor As String
Set wb1 = ThisWorkbook 'Annual Consent Letter Macro
Set wb2 = Workbooks("source workbook_sample.xlsx")
Set ws1 = ThisWorkbook.Worksheets(1)
Set ws2 = wb2.Worksheets(1)
llc = ",LLC"
inc = ",INC."
With ws1
For i = 1 To 500
If Cells(i, 1).Value = searchfor Then
company = .Cells(i, 1)
With ws2
'change range as necessary
Set f = .Range("A1:A500").Find(company, LookIn:=xlValues)
If Not f Is Nothing Then
Debug.Print searcfor
fRow = f.Row
rng = .Range("B" & fRow & ":D" & fRow)
ws1.Range("B" & i & ":D" & i) = rng
End If
End With
End If
Next
End With
End Sub