I am having difficulty getting the code in the workbook attached to function as intended. Everything is working but it is copying the photo twice. Any suggestions?
Basically, it looks at the master worksheet then creates a unique sheet for each supplier based on the date entered and copies over all records to the next empty line. What is happening is that it copies the photo over but it pastes it twice. I can't figure out why.
Code is shown in attached workbook.
Option Explicit
Const ColSht1Name As Long = 1
Const RowSht1DataFirst As Long = 2
Const ColSht1Date As Date = 3
Const ColSht1Doc As String = 4
Sub BuildSingleSupplierSheets()
' For each supplier in worksheet Sheet1, create their own worksheet.
' Copy each data row for a supplier, including a picure if any, to its own worksheet.
Dim ColSht1LastHdr As Long
Dim ColSht1LastCrnt As Long
Dim ColShapeTopLeftCell As Long
Dim Found As Boolean
Dim HeightShape As Single
Dim InxShape As Long
' Dim RowPerPicture() As String
Dim RngDest As Range
Dim RowCrntNext As Long
Dim RowSht1Crnt As Long
Dim RowSht1Last As Long
Dim ShapeCrnt As Shape
Dim WshtSht1 As Worksheet
Dim WshtCrnt As Worksheet
Dim WshtNameCrnt As String
Dim x As String
Dim bottomL As Integer
Dim c As Range
Set WshtSht1 = Worksheets("Sheet1")
x = InputBox("Enter Report Date")
With Worksheets("Sheet1")
RowSht1Last = .Cells(Rows.Count, ColSht1Name).End(xlUp).Row
ColSht1LastHdr = 0
For RowSht1Crnt = 1 To RowSht1DataFirst - 1
ColSht1LastCrnt = .Cells(RowSht1Crnt, Columns.Count).End(xlToLeft).Column
If ColSht1LastHdr < ColSht1LastCrnt Then
ColSht1LastHdr = ColSht1LastCrnt
End If
Next
End With
' Copy every row from worksheet Sheet1 to the worksheet for the row's
' supplier. Create and initialise supplier worksheet if it does not
' already exist.
For RowSht1Crnt = RowSht1DataFirst To RowSht1Last
If WshtSht1.Cells(RowSht1Crnt, ColSht1Date).Value = x And WshtSht1.Cells(RowSht1Crnt, "B").Value = "DR" Then
WshtNameCrnt = WshtSht1.Cells(RowSht1Crnt, ColSht1Name).Value
' Create and initiialise worksheet WshtNameCrnt if it does not already exist
If Not SheetExists(WshtNameCrnt) Then
Set WshtCrnt = Worksheets.Add(After:=Worksheets(Worksheets.Count))
WshtCrnt.Name = WshtNameCrnt
With WshtSht1
.Range(.Cells(1, 1), .Cells(RowSht1DataFirst - 1, ColSht1LastHdr)).Copy _
Destination:=WshtCrnt.Range("A1")
End With
Else
Set WshtCrnt = Worksheets(WshtNameCrnt)
End If
' Copy current row of worksheet Sheet1 to the next free row
' of the supplier worksheet
RowCrntNext = LastRow(WshtCrnt) + 1
With WshtSht1
ColSht1LastCrnt = .Cells(RowSht1Crnt, Columns.Count).End(xlToLeft).Column
.Range(.Cells(RowSht1Crnt, 1), .Cells(RowSht1Crnt, ColSht1LastCrnt)).Copy _
Destination:=WshtCrnt.Cells(RowCrntNext, 1)
End With
' Ensure columns wide enought for data
With WshtCrnt
.Cells.Range(.Cells(1, 1), .Cells(1, ColSht1LastCrnt)).EntireColumn.AutoFit
.Cells.Range(.Cells(1, 1), .Cells(1, ColSht1LastCrnt)).Borders(xlEdgeBottom).Color = RGB(0, 0, 0)
.Cells.Range(.Cells(1, 1), .Cells(1, ColSht1LastCrnt)).Borders(xlEdgeTop).Color = RGB(0, 0, 0)
.Cells.Range(.Cells(1, 1), .Cells(1, ColSht1LastCrnt)).Borders(xlInsideHorizontal).Color = RGB(0, 0, 0)
.Cells.Range(.Cells(1, 1), .Cells(1, ColSht1LastCrnt)).Borders(xlInsideVertical).Color = RGB(0, 0, 0)
End With
' Check Shapes collection to see if there is a picture on this row
With WshtSht1
Found = False
For InxShape = 1 To .Shapes.Count
With .Shapes(InxShape)
If .Type = msoPicture Then
If .TopLeftCell.Row = RowSht1Crnt Then
Found = True
Exit For
End If
End If
End With
Next
End With
If Found Then
' Picture on current row of Sheet1. Copy to supplier worksheet
Set ShapeCrnt = WshtSht1.Shapes(InxShape)
With ShapeCrnt
ColShapeTopLeftCell = .TopLeftCell.Column
HeightShape = .Height
End With
ShapeCrnt.Copy
WshtCrnt.Paste
With WshtCrnt
Set RngDest = .Cells(RowCrntNext, ColShapeTopLeftCell)
RngDest.RowHeight = HeightShape + 4!
With .Shapes(.Shapes.Count)
.Top = RngDest.Top + 2!
.Left = RngDest.Left + 2!
Call .ScaleWidth(1!, msoCTrue) '
Call .ScaleHeight(1!, msoCTrue) '
End With
End With
End If
End If
Next RowSht1Crnt
End Sub
Function LastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
Function SheetExists(SName As String, _
Optional ByVal WB As Workbook) As Boolean
'Chip Pearson
On Error Resume Next
If WB Is Nothing Then Set WB = ThisWorkbook
SheetExists = CBool(Len(WB.Sheets(SName).Name))
End Function
Workbook Example
You have 2 paste operations in your code. One that you know of:
WshtCrnt.Paste
and one that is part of this range copy statement:
.
.
With WshtSht1
.Range(.Cells(1, 1), .Cells(RowSht1DataFirst - 1, ColSht1LastHdr)).Copy_
Destination:=WshtCrnt.Range("A1")
.
.
By specifying a "Destination" you are requesting a copy AND paste of your range.
Related
I have made this code to create an output sheet where columns from different sheets are sorted by header name and pasted one after the other.
For some reason, it is not pasting the columns underneath each other, but instead overwriting each one with the next:
Dim ws As worksheet
Dim max_ws As worksheet
Dim output_ws As worksheet
Dim max_ws_header As Range
Dim output_ws_header As Range
Dim header_cell As Range
Dim cc As Long
Dim max_cc As Long
Dim output_header_counter As Long
Dim ws_header_counter As Long
Dim output_header_name As String
Dim ws_header_name As String
Application.DisplayAlerts = False
Sheets("indice").Delete
Sheets("aneca").Delete
Application.DisplayAlerts = True
For Each ws In Worksheets
ws.Rows(1).EntireRow.Delete
ws.Columns.Hidden = False
Next ws
max_cc = 0
For Each ws In Worksheets
cc = last_column_index(ws, 1)
If cc > max_cc Then
max_cc = cc
Set max_ws = ws
End If
Next ws
Sheets.Add.Name = "Output"
Set output_ws = Sheets("Output")
Set max_ws_header = max_ws.Range(max_ws.Cells(1, 1), max_ws.Cells(1, max_cc))
Set output_ws_header = output_ws.Range(output_ws.Cells(1, 1), output_ws.Cells(1, max_cc))
max_ws_header.Copy output_ws_header
For Each ws In Worksheets
If ws.Name <> "Output" Then
For output_header_counter = 1 To max_cc
output_header_name = output_ws.Cells(1, output_header_counter).Value
For ws_header_counter = 1 To max_cc
ws_header_name = ws.Cells(1, ws_header_counter).Value
If ws_header_name = output_header_name Then
ws.Range(Cells(1, ws_header_counter), Cells(last_row_index(ws, ws_header_counter), ws_header_counter)).Copy _
output_ws.Range(Cells(last_row_index(output_ws, output_header_counter) + 1, output_header_counter), Cells(last_row_index(ws, ws_header_counter), output_header_counter))
End If
Next ws_header_counter
Next output_header_counter
End If
The functions last_row_index and last_column_index are UDFs that I made as follows:
Function last_row_index(target_worksheet As worksheet, target_column_index As Long) As Long
last_row_index = target_worksheet.Cells(Rows.Count, target_column_index).End(xlUp).Row
End Function
Function last_column_index(target_worksheet As worksheet, target_row_index As Long) As Long
last_column_index = target_worksheet.Cells(target_row_index, Columns.Count).End(xlToLeft).Column
End Function
Here is an example of the output:
I figured out the solution, posting it here to close the question:
For Each ws In Worksheets
If ws.Name <> "Output" And ws.Name <> "indice" And ws.Name <> "aneca" Then
For row_index = 2 To last_row_index(ws, 1)
output_counter = last_row_index(output_ws, 1)
For column_index = 1 To last_column_index(ws, 1)
ws_header = ws.Cells(1, column_index).Value
For o_column_index = 1 To max_cc
output_header = output_ws.Cells(1, o_column_index).Value
If output_header = ws_header Then
ws.Cells(row_index, column_index).Copy output_ws.Cells(output_counter + 1, column_index)
Exit For
End If
Next o_column_index
Next column_index
Next row_index
End If
Next ws
I made an output counter variable and made it find the last row each time it starts on a new row in the input sheets, and then I add +1 to it every time it pastes a row.
I'm using this code to transfer invoice data in one sheet to invoice history in another sheet and it is working as intended. However, I cannot figure out how to transfer said data to the invoice history sheet without ruining the formatting of the table. The picture below shows what happens when the data is entered manually versus when the code is used (last three rows).
Dim xNew As Worksheet 'New Invoice Sheet
Dim xInvoices As Worksheet 'Invoice History Sheet
Dim iCurrentRow As Integer
Set xNew = ThisWorkbook.Sheets("New_Invoice")
Set xInvoices = ThisWorkbook.Sheets("Invoices")
iCurrentRow = xInvoices.Cells(xInvoices.Rows.Count, "B").End(xlUp).Row + 1
With xInvoices
.Cells(iCurrentRow, 2) = xNew.Range("F5")
.Cells(iCurrentRow, 3) = xNew.Range("B9")
.Cells(iCurrentRow, 4) = xNew.Range("Total")
.Cells(iCurrentRow, 5) = "Not Paid"
.Cells(iCurrentRow, 6) = "Outright"
.Cells(iCurrentRow, 7) = Date + 1
End With
You did not answered the clarification question, but if there is a real ListObject in the sheet you try pasting below its last row, please try the next code:
Sub testLstRTable()
Dim xNew As Worksheet, xInvoices As Worksheet, firstR As Long, lastR As Long, tb As ListObject
Set xNew = ThisWorkbook.Sheets("New_Invoice")
Set xInvoices = ThisWorkbook.Sheets("Invoices")
Set tb = xInvoices.ListObjects("YourTable") 'use here your real table name!!!
firstR = tb.HeaderRowRange.row 'for the case when the table header row is not the first...
lastR = tb.ListRows.count + firstR
xInvoices.Range(xInvoices.cells(lastR + 1, 2), xInvoices.cells(lastR + 1, 7)).value = _
Array(xNew.Range("F5").value, xNew.Range("B9").value, xNew.Range("Total").value, "Not Paid", "Outright", Date + 1)
End Sub
Please, pay attention to changing the Table name, using the one existing in the involved sheet.
But if you name a simple formatted range as a table, please use the next code variant:
Sub testKeepFormat()
Dim xNew As Worksheet, xInvoices As Worksheet, lastR As Long
Set xNew = ThisWorkbook.Sheets("New_Invoice")
Set xInvoices = ThisWorkbook.Sheets("Invoices")
lastR = xInvoices.Range("B" & xNew.rows.count).End(xlUp).row
With xInvoices.Range(xInvoices.cells(lastR + 1, 2), xInvoices.cells(lastR + 1, 7))
.value = Array(xNew.Range("F5").value, xNew.Range("B9").value, xNew.Range("Total").value, "Not Paid", "Outright", Date + 1)
.Interior.Color = .Offset(-2).Interior.Color
.cells(1, 2).HorizontalAlignment = .Offset(-2).cells(1, 2).HorizontalAlignment
End With
End Sub
Copy Row Data Using Insert
This will use the formatting of the last row.
Option Explicit
Sub RecordNewInvoice()
Const sName As String = "NewInvoice"
Const dName As String = "Invoices"
Const dCol As String = "B"
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim RowData As Variant: RowData = GetRowData(sws)
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dCell As Range: Set dCell = dws.Cells(dws.Rows.Count, dCol).End(xlUp)
dCell.Offset(1).EntireRow.Insert
dCell.Offset(1).Resize(, UBound(RowData)).Value = RowData
End Sub
Function GetRowData( _
sws As Worksheet) _
As Variant
Dim RowData(1 To 6) As Variant
RowData(1) = sws.Range("F5").Value
RowData(2) = sws.Range("B9").Value
RowData(3) = sws.Range("Total").Value
RowData(4) = "Not Paid"
RowData(5) = "Outright"
RowData(6) = Date + 1
GetRowData = RowData
End Function
Screenshot#1
So i have to replace positive & negative numbers in column "A", from sheet "1" to sheet second[positive] and third sheet[negative].
Here is what i tried:
Sub Verify()
Dim row As Long
For row = 1 To 20
If ActiveSheet.Cells(row,1) <> "" Then
If ActiveSheet.Cells(row,1) > 0 Then
ActiveSheet.Cells(row,2) = ActiveSheet.Cells(row,1)
End If
End If
Next
End Sub
Here is what that program do:
Screenshot#2
So as we see i am getting positive values in column "B" sheet 1.
Your code is not currently working because you are only using ActiveSheet, rather than placing data on other worksheets as required. Below is some VBA code that loops column A in your original sheet, and outputs the data to column A in two different sheets as required:
Sub sSplitPositiveNegative()
Dim wsOriginal As Worksheet
Dim wsPositive As Worksheet
Dim wsNegative As Worksheet
Dim lngLastRow As Long
Dim lngPositiveRow As Long
Dim lngNegativeRow As Long
Dim lngLoop1 As Long
Set wsOriginal = ThisWorkbook.Worksheets("Original")
Set wsPositive = ThisWorkbook.Worksheets("Positive")
Set wsNegative = ThisWorkbook.Worksheets("Negative")
lngLastRow = wsOriginal.Cells(wsOriginal.Rows.Count, "A").End(xlUp).Row
lngNegativeRow = 2
lngPositiveRow = 2
For lngLoop1 = 1 To lngLastRow
If wsOriginal.Cells(lngLoop1, 1).Value > 0 Then
wsPositive.Cells(lngPositiveRow, 1) = wsOriginal.Cells(lngLoop1, 1)
lngPositiveRow = lngPositiveRow + 1
Else
wsNegative.Cells(lngNegativeRow, 1) = wsOriginal.Cells(lngLoop1, 1)
lngNegativeRow = lngNegativeRow + 1
End If
Next lngLoop1
Set wsPositive = Nothing
Set wsNegative = Nothing
Set wsOriginal = Nothing
End Sub
You will need to change the names of the worksheets referenced in the code to match those in your workbook.
Regards
Made the code a little reusable for you. Feel free to change sheet names or the last_row variable. The last_pos_val and last_neg_val are used so you won't have empty rows on the second and third sheet. You didn't specify what to do with zero, so it's currently added to the negative sheet.
Sub Verify()
Dim row As Long, last_row As Long, last_pos_val As Long, last_neg_val As Long
Dim ws_source As Worksheet, ws_pos As Worksheet, ws_neg As Worksheet
Dim wb As Workbook
Set wb = ThisWorkbook
Set ws_source = wb.Sheets("Sheet1")
Set ws_pos = wb.Sheets("Sheet2")
Set ws_neg = wb.Sheets("Sheet3")
last_pos_val = 1
last_neg_val = 1
last_row = 20
For row = 1 To last_row
If ws_source.Cells(row,1) <> "" Then
If ws_source.Cells(row,1) > 0 Then
ws_pos.Cells(last_pos_val,1) = ws_source.Cells(row,1)
last_pos_val = last_pos_val + 1
Else
ws_neg.Cells(last_neg_val,1) = ws_source.Cells(row,1)
last_neg_val = last_neg_val + 1
End If
End If
Next
End Sub
Split Positive & Negative
Adjust the values in the constants section.
Both subs are needed. The first sub calls the second one.
The Code
Option Explicit
Sub SplitPN()
Const Source As String = "Sheet1"
Const Positive As String = "Sheet2"
Const Negative As String = "Sheet3"
Const FirstRow As Long = 1
Const SourceColumn As Long = 1
Const PositiveFirstCell As String = "A1"
Const NegativeFirstCell As String = "A1"
Dim rngSource As Range
Dim rngPositive As Range
Dim rngNegative As Range
With ThisWorkbook
With .Worksheets(Source)
Set rngSource = .Columns(SourceColumn).Find(What:="*", _
LookIn:=xlFormulas, SearchDirection:=xlPrevious)
If rngSource Is Nothing Then Exit Sub
If rngSource.Row < FirstRow Then Exit Sub
Set rngSource = .Range(.Cells(FirstRow, SourceColumn), rngSource)
End With
Set rngPositive = .Worksheets(Positive).Range(PositiveFirstCell)
Set rngNegative = .Worksheets(Negative).Range(NegativeFirstCell)
End With
SplitPosNeg rngSource, rngPositive, rngNegative
End Sub
Sub SplitPosNeg(SourceRange As Range, PositiveFirstCell As Range, _
NegativeFirstCell As Range)
Dim Source, Positive, Negative
Dim UB As Long, i As Long
Source = SourceRange
UB = UBound(Source)
ReDim Positive(1 To UB, 1 To 1)
ReDim Negative(1 To UB, 1 To 1)
For i = 1 To UBound(Source)
Select Case Source(i, 1)
Case Is > 0: Positive(i, 1) = Source(i, 1)
Case Is < 0: Negative(i, 1) = Source(i, 1)
End Select
Next
PositiveFirstCell.Resize(UB) = Positive
NegativeFirstCell.Resize(UB) = Negative
End Sub
The excel vba macro I have created goes through an entire column and searches each value in the column against another column found on another worksheet. I have a T/F column where I mark down "T" if it is found, "F" if it is not found. However, I feel like the way I am doing it might not be very efficient, as the macro takes about 30 minutes to go through 31,000 rows of values to be searched from another column with about 27,000 number of values.
For a simple illustration, I have included a few images which explains what the macro does.
Initially the T/F column will be empty. Only after executing the macro, would it be filled. I loop through each row in column A and try to find the value against the SearchCol in the next picture.
Here is the vba code I am currently using.
Sub CheckIfValuesExist()
Dim ActiveWS As Worksheet, WS2 As Worksheet
Dim ValueColLetter As String, SearchColLetter As String, TFColLetter As String
Dim LastRow As Long, i As Long
Dim target As Variant, rng As Range
Set ActiveWS = ActiveWorkbook.Worksheets(1)
Set WS2 = ActiveWorkbook.Worksheets(2)
ValueColLetter = "A"
SearchColLetter = "A"
TFColLetter = "B"
LastRow = ActiveWS.Cells.Find(What:="*", SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, _
LookIn:=xlFormulas).Row
For i = 2 To LastRow
target = ActiveWS.Range(ValueColLetter & i).Value
If target <> "" Then
With WS2.Range(SearchColLetter & ":" & SearchColLetter) 'searches all of column A
Set rng = .Find(What:=target, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not rng Is Nothing Then
ActiveWS.Range(TFColLetter & i).Value = "T" 'value found
Else
ActiveWS.Range(TFColLetter & i).Value = "F" 'value not found
End If
End With
End If
Next i
End Sub
The macro works as intended, I just find it to be slow. Is there any better way to do the same thing but in a quicker manner?
Check Column Against Column
Array Match Range Version
Sub CheckIfValuesExist()
Const cSheet1 As Variant = 1 ' Value Worksheet Name/Index
Const cSheet2 As Variant = 2 ' Search Worksheet Name/Index
Const cFirst As Long = 2 ' First Row
Const cVal As Variant = "A" ' Value Column
Const cSrc As Variant = "A" ' Search Column
Const cTF As Variant = "B" ' Target Column
Const cT As String = "T" ' Found String
Const cF As String = "F" ' Not Found String
Dim RngS As Range ' Search Range
Dim vntV As Variant ' Value Array
Dim vntT As Variant ' Target Array
Dim LastV As Long ' Value Last Column Number
Dim LastS As Long ' Search Last Column Number
Dim i As Long ' Value/Target Row Counter
Dim dummy As Long ' Match Dummy Variable
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
On Error GoTo ProcedureExit
With ThisWorkbook.Worksheets(cSheet1)
LastV = .Columns(.Cells(1, cVal).Column).Find("*", , -4123, , 2, 2).Row
vntV = .Range(.Cells(cFirst, cVal), .Cells(LastV, cVal))
End With
With ThisWorkbook.Worksheets(cSheet2)
LastS = .Columns(.Cells(1, cSrc).Column).Find("*", , -4123, , 2, 2).Row
Set RngS = .Range(.Cells(cFirst, cSrc), .Cells(LastS, cSrc))
ReDim vntT(1 To UBound(vntV), 1 To 1)
For i = 1 To UBound(vntV)
On Error Resume Next
If vntV(i, 1) <> "" Then
dummy = Application.Match(vntV(i, 1), RngS, 0)
If Err Then
vntT(i, 1) = cF
Else
vntT(i, 1) = cT
End If
End If
On Error GoTo 0
Next
End With
On Error GoTo ProcedureExit
With ThisWorkbook.Worksheets(cSheet1)
.Range(.Cells(cFirst, cTF), .Cells(.Rows.Count, cTF)).ClearContents
.Cells(cFirst, cTF).Resize(UBound(vntT)) = vntT
End With
ProcedureExit:
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End Sub
Let us assume that data included in Sheet 1.
Try:
Option Explicit
Sub VlookUp()
Dim LastRowSV As Long, LastRowV As Long, Counts As Long
Dim wsName As String
Dim wsListSV As Range, cellSV As Range, wsListV As Range, cellV As Range
With ThisWorkbook.Worksheets("Sheet1")
'Find the last row of Search Values
LastRowSV = .Cells(.Rows.Count, "D").End(xlUp).Row
'Find the last row of Values
LastRowV = .Cells(.Rows.Count, "A").End(xlUp).Row
'Set the list with the Search Values
Set wsListSV = .Range(Cells(2, 4), Cells(LastRowSV, 4))
'Set the list with the Values
Set wsListV = .Range(Cells(3, 1), Cells(LastRowV, 1))
'Loop each value in Search Values
For Each cellV In wsListV
Counts = Application.WorksheetFunction.CountIf(wsListSV, cellV)
If Counts <> 0 Then
cellV.Offset(0, 1).Value = "T"
Else
cellV.Offset(0, 1).Value = "F"
End If
Next
End With
End Sub
Result:
Why don't you use the MATCH formula?
If your values are in Col A and the search values are at
the cells $F$5:$F$10 the formula is:
=MATCH(A2,$F$5:$F$10,0)
or if you insist on a T/F result:
=IF(ISERROR(MATCH(A2,$F$5:$F$10,0)),"T","F")
Of cause you can insert this formula also with a macro.
The code i've provided here is able to search Sheet1 and then copy the value ( the whole row containing the value) that has been searched into a new sheet and then rename the sheet after search string.
But now i am trying to search all of the sheet in excel instead of one sheet, and this time i am also required to include the header of the relevant row.
for example if i search Apple, the macro will search all the sheet for Apple, and for example if apple is found on sheet7, it will be copied in a new sheet named "Apple" with the relevant header.
But example if there are both apple on sheet7 and sheet8, both will be copied into a new sheet name "Apple" but both of the header must also be copied into the new sheet.
How do i start working on it? i know i have to find out the number of sheets and loop it but after that what should i include?
Dim strSearch
Dim rg As Range, rgF As Range
Dim i As Integer
Dim celltxt As String
Dim strSearch2
'Dim x, NumberOfWorksheet As Integer 'to count worksheet for loop
Application.ScreenUpdating = False
strSearch = Application.InputBox("Please enter the search string")
strSearch2 = Replace(strSearch, "*", " ")
' NumberOfWorksheet = ThisWorkbook.Sheets.Count
' For x = 0 To NumberOfWorksheet
If Len(strSearch) > 0 Then
Worksheets.Add().Name = strSearch2
Set rg = Sheets("Sheet1").Cells(1).CurrentRegion 'Define whole search range here
For i = 1 To rg.Rows.Count 'we look rows by rows (to copy row once only)
Set rgF = rg.Rows(i).Find(strSearch, , xlValues, xlWhole)
If Not rgF Is Nothing Then
rg.Rows(i).Copy Sheets(strSearch2).Range("A60000").End(xlUp).Offset(1, 0)
Set rgF = Nothing
End If
Next i
'Next x
Application.ScreenUpdating = True
End If
It has worked on Excel 2007:
Sub sof20312498SearchCopy()
Dim i As Long, nRowsAddePerSheet As Long, nRows As Long, _
nRowsMax As Long, nSheets As Long
Dim strSearch, strSearch2
Dim rg As Range, rgF As Range
Dim wks
'
'Dim x, NumberOfWorksheet As Integer 'to count worksheet for loop
Dim x
'
strSearch = Application.InputBox("Please enter the search string")
strSearch2 = Replace(strSearch, "*", "")
If Len(strSearch2) <= 0 Then
MsgBox "Abandon: Search string must not be empty."
Exit Sub
End If
Application.ScreenUpdating = False
nSheets = Sheets.Count
nRowsMax = ActiveSheet.Rows.Count
For x = 1 To nSheets
'
' get the worksheet, if nonexistent, add it:
'
On Error Resume Next
Set wks = Worksheets(strSearch2)
If (Err) Then
Set wks = Worksheets.Add(After:=Sheets(Sheets.Count))
wks.Name = strSearch2
Err.Clear
End If
On Error GoTo 0
'
' Define whole search range here:
'
'Set rg = Sheets("Sheet1").Cells(1).CurrentRegion
'
Sheets(x).Activate
Set rg = ActiveSheet.Cells(1).CurrentRegion
'
' we look rows by rows (to copy row once only):
'
nRows = rg.Rows.Count
nRowsAddePerSheet = 0
For i = 1 To nRows
Set rgF = rg.Rows(i).Find(strSearch, , xlValues, xlWhole)
'
' if found, copy the source row as the last row of the destination Sheet:
'
If Not rgF Is Nothing Then
'
' copy header if required, Row(1) is assumed as header:
'
If (nRowsAddePerSheet <= 0) Then
If (i <> 1) Then
rg.Rows(1).Copy wks.Range("A" & nRowsMax).End(xlUp).Offset(1, 0)
End If
End If
'
rg.Rows(i).Copy wks.Range("A" & nRowsMax).End(xlUp).Offset(1, 0)
nRowsAddePerSheet = nRowsAddePerSheet + 1
End If
Next
Next
Set rgF = Nothing
Set rg = Nothing
Set wks = Nothing
Application.ScreenUpdating = True
End Sub
For the search string "Apple", Sheet1 and Sheet2 contain it as whole word:
Sheet1
Sheet2
Apple - Here is the Sheet Apple: