I have four sheets with raw data that I would like to be duplicated in my workbook and left alone for cross reference. Then I would like to remove all rows above the cell with the text "proj def" (it appears twice, but there are cells that lie in between the two appearances - which will be evident in my code). I would like to do this for the first four sheets of my workbook while leaving the original duplicated worksheets alone but am only able to do so with the first worksheet labeled "ptd". I have tried to activate the next worksheet "ytd" and even delete the original worksheet "ptd" to see if it would allow me to change the location of myRange but I have had no success. Essentially I want to run this code in sub methods, two for the first sheet "ptd", two more for the second sheet "ytd", another 2 for "qtr" and the final 2 for "mth". Any edits to my sample code would be much appreciated.
Sub part1()
Worksheets("ptd").Copy After:=Worksheets("mth")
Worksheets("ytd").Copy After:=Worksheets("ptd (2)")
Worksheets("qtr").Copy After:=Worksheets("ytd (2)")
Worksheets("mth").Copy After:=Worksheets("qtr (2)")
End Sub
Sub part2()
Worksheets("ptd").Activate
Set rngActiveRange = ActiveCell
Dim MyRange As Range
Set MyRange = ActiveSheet.Range("A:A")
MyRange.Find("Customer Unit", LookIn:=xlValues).Select
rngActiveRange.Offset(-1, 0).Select
Range(rngActiveRange.Row & ":" & 1).Rows.Delete
End Sub
Sub part3()
Dim MyRange As Range
Set MyRange = ActiveSheet.Range("A:A")
MyRange.Find("Project Definition", LookIn:=xlValues).Select
ActiveCell.Offset(-1, 0).Select
Range(ActiveCell.Row & ":" & 1).Rows.Delete
End Sub
Sub part4()
Worksheets("ytd").Activate
Set rngActiveRange = ActiveCell
Dim MyRange As Range
Set MyRange = ActiveSheet.Range("A:A")
MyRange.Find("Customer Unit", LookIn:=xlValues).Select
rngActiveRange.Offset(-1, 0).Select
Range(rngActiveRange.Row & ":" & 1).Rows.Delete
End Sub
Sub part5()
Dim MyRange As Range
Set MyRange = ActiveSheet.Range("A:A")
MyRange.Find("Project Definition", LookIn:=xlValues).Select
ActiveCell.Offset(-1, 0).Select
Range(ActiveCell.Row & ":" & 1).Rows.Delete
End Sub
If I understand correctly, the below should work. The main thing I did was re-write with avoiding the use of .Select/.Activate.
Sub remove_Rows()
Dim ws As Worksheet
Dim foundCel As Range
' Copy sheets
Worksheets("ptd").Copy After:=Worksheets("mth")
Worksheets("ytd").Copy After:=Worksheets("ptd (2)")
Worksheets("qtr").Copy After:=Worksheets("ytd (2)")
Worksheets("mth").Copy After:=Worksheets("qtr (2)")
' Start removing rows
For Each ws In ActiveWorkbook.Worksheets
With ws
If InStr(1, .Name, "(") = 0 Then
Set foundCel = .Range("A:A").Find("Customer Unit", LookIn:=xlValues)
.Range(foundCel.Offset(-1, 0).Row & ":" & 1).Rows.Delete
Set foundCel = .Range("A:A").Find("Project Definition", LookIn:=xlValues)
.Range(foundCel.Offset(-1, 0).Row & ":" & 1).Rows.Delete
End If
End With
Next ws
End Sub
Related
hopefully a quick fix on this one. I have a sub routine that I am using to amend the column sizes for all the sheets in a workbook which works absolutely fine but I wanted to add to this sub so that it will change the font color black for all cells within my ranges and remove any fill color from them also. I have written the code below but it doesn't seem to perform the way I want. Any ideas as to how I can correct this would be awesome!
Sub forEachWs()
Dim ws As Worksheet
'Opens new workbook for formatting
Workbooks.Open "C:\Users\XNEID\Desktop\Test MPAN Destination
Folder\Shell_MPANs_Test1.xlsx"
For Each ws In ActiveWorkbook.Worksheets
Call resizingColumns(ws)
Next
End Sub
Sub resizingColumns(ws As Worksheet)
With ws
.Range("A1:BB1").EntireColumn.AutoFit
Range("A2:BB2", Range("A2:BB2").End(xlDown)).Select
Selection.Font.Color = vbBlack
Range("A2:BB2", Range("A2:BB2").End(xlDown)).Select
Selection.Interior.ColorIndex = xlNone
End With
End Sub
You need to fully qualify the cell's object
Work with variables. See how I have used it to find the last row
Avoid the use of .Select
Is this what you are trying?
With ws
.Columns("A:BB").EntireColumn.AutoFit
lrow = .Range("A" & .Rows.Count).End(xlUp).Row
With .Range("A2:BB" & lrow)
.Font.Color = vbBlack
.Interior.ColorIndex = xlNone
End With
End Withh
I would suggest defining a last row (by working up from the bottom), and you omitted the dots necessary for your With statement
Sub resizingColumns(ws As Worksheet)
Dim n As Long
With ws
n = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("A1:BB1").EntireColumn.AutoFit
.Range("A2:BB" & n).Font.Color = vbBlack
.Range("A2:BB" & n).Interior.ColorIndex = xlNone
End With
End Sub
Avoid using Select and ActiveWorkbook. Instead, simply reference the ranges directly. Try this:
Sub forEachWs()
Dim ws As Worksheet
Dim wb As Workbook
'Opens new workbook for formatting
Set wb = Workbooks.Open "C:\Users\XNEID\Desktop\Test MPAN Destination
Folder\Shell_MPANs_Test1.xlsx"
For Each ws In wb.Worksheets
Call resizingColumns(ws)
Next
End Sub
Sub resizingColumns(ws As Worksheet)
With ws
.Range("A1:BB1").EntireColumn.AutoFit
.Range("A2:BB" & .Cells(.Rows.Count, 1).End(xlUp).Row).Font.Color = vbBlack
.Range("A2:BB" & .Cells(.Rows.Count, 1).End(xlUp).Row).Interior.ColorIndex = xlNone
End With
End Sub
I am trying to copy a number of rows from each worksheet to the worksheet called "renew" in the same workbook.
The rows are defined as between the key words of "Service Requests" and "Renewals".
so step 1: define those row numbers, and step 2: copy them to the Renew sheet.
I run into the problem with step 2, somehow, i couldn't work out how to use the rownumber1 and rownumber2 in the copy command.
Any help would be appreciated. Thanks!
Sub test()
Dim ws As Worksheet
Application.ScreenUpdating = False
Sheets("Renew").Activate
For Each ws In Worksheets
If ws.Name <> "Renew" Then
For i = 1 To 100
Dim rownumber1 As Integer
Dim rownumber2 As Integer
If Range("A" & i).Text = "Service Requests" Then
rownumber1 = i
ElseIf Range("A" & i).Text = "Renewals" Then
rownumber2 = i
End If
Next i
'copy rows between rownumber1 and rownumber2 to the renew sheet
ws.Rows("rownumber1:rownumber2").EntireRow.Copy
ActiveSheet.Paste Range("A65536").End(xlUp).Offset(1, 0)
End If
Next ws
End Sub
update:
Sub test2()
Dim ws As Worksheet
Dim rownumber1 As Integer
Dim rownumber2 As Integer
Dim FoundCell As Excel.Range
Application.ScreenUpdating = False
Sheets("Renew").Activate
For Each ws In Worksheets
If ws.Name <> "Renew" Then
Set FoundCell = ws.Range("A:A").Find(what:="Service Requests", lookat:=xlWhole)
If Not FoundCell Is Nothing Then
rownumber1 = FoundCell.Row
End If
Set FoundCell = ws.Range("A:A").Find(what:="Renewals", lookat:=xlWhole)
If Not FoundCell Is Nothing Then
rownumber2 = FoundCell.Row
End If
'copy renewals to the renewalsummary
ws.Rows(rownumber1 & ":" & rownumber2).EntireRow.Copy
ActiveSheet.Paste Range("A65536").End(xlUp).Offset(1, 0)
End If
Next ws
End Sub
What you're looking for is:
ws.Rows(rownumber1 & ":" & rownumber2).EntireRow.Copy
Although, there are some other things to consider with your code. It may be a work in progress so I only answered your question, but:
Your loop is going to return row 100 every time, so I'm curious what the point of your loop is.
You should never DIM in a loop, since you can only declare a variable once and the loop will attempt to do it every time and should throw an error (Dim your rownumber variables with your ws variable).
Why loop to 100? You should loop to the end of the list of values.
Reply to Edits
It looks pretty good. the main thing is that it works. Although I would change this:
ActiveSheet.Paste Range("A65536").End(xlUp).Offset(1, 0)
to this:
ActiveSheet.Paste Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
Hard-coded values aren't very future-proof, this looks at the last row of the sheet (whatever that might be). If any of your sheets start to reach the row max you need to do this:
If Cells(Rows.Count, 1) <> "" Then
ActiveSheet.Paste Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
Else
MsgBox("Sheet " & ws.Name & " is full, row cannot be copied")
End If
But that's probably way down the road and at that point you might be outgrowing Excel.
I'm on XL2007 - Windows 7.
I need an element of error handling in the below code.
Some of the values in range rngburndown do not exist as worksheets, and i need the VBA to skip these cells, and copy the rows that do exist as worksheets to the nextavailable row in the matching worksheet name.
Sub Retrieve_Forecasts()
Dim objWorksheet As Worksheet
Dim rngBurnDown As RANGE
Dim rngCell As RANGE
Dim strPasteToSheet As String
Dim objNewSheet As Worksheet
Dim rngNextAvailbleRow As RANGE
'DEFINE SOURCE WORKSHEET
Set objWorksheet = ThisWorkbook.Worksheets("Forecasts")
'DEFINE LIST OF FORECASTS - INCLUDING VALUES WHICH MAY NOT EXIST AS WORKSHEETS
Set rngBurnDown = objWorksheet.RANGE("A2:A" & objWorksheet.Cells(Rows.Count, "A").End(xlUp).Row)
'LOOP THROUGH RANGE
For Each rngCell In rngBurnDown.Cells
objWorksheet.Select
If rngCell.Value <> "" Then
'SELECT ROW
rngCell.EntireRow.Select
'COPY
Selection.Copy
'FIND AND PASTE WHERE WORKSHEET NAME MATCHES FORECAST LIST
Set objNewSheet = ThisWorkbook.Worksheets(rngCell.Value)
objNewSheet.Select
Set rngNextAvailbleRow = objNewSheet.RANGE("A1:A" & objNewSheet.Cells(Rows.Count, "A").End(xlUp).Row)
RANGE("A" & rngNextAvailbleRow.Rows.Count + 1).Select
ActiveSheet.Paste
End If
Next rngCell
objWorksheet.Select
objWorksheet.Cells(1, 1).Select
End Sub
You could use the commands "On Error GoTo 0" to ignore all errors or use "On Error Resume Next" to ignore the error and execute the next instruction as shown in https://msdn.microsoft.com/en-us/library/5hsw66as.aspx
Example:
For Each rngCell In rngBurnDown.Cells
On Error GoTo 0
objWorksheet.Select
If rngCell.Value <> "" Then
'SELECT ROW
rngCell.EntireRow.Select
'COPY
Selection.Copy
'FIND AND PASTE WHERE WORKSHEET NAME MATCHES FORECAST LIST
Set objNewSheet = ThisWorkbook.Worksheets(rngCell.Value)
objNewSheet.Select
Set rngNextAvailbleRow = objNewSheet.RANGE("A1:A" & objNewSheet.Cells(Rows.Count, "A").End(xlUp).Row)
RANGE("A" & rngNextAvailbleRow.Rows.Count + 1).Select
ActiveSheet.Paste
End If
Next rngCell
i need to copy data from one sheet to another and paste into the next available row where the column headings match.
I am having difficulty creating the range to copy into.
this seems to be the issue -
rng1.SpecialCells(xlCellTypeVisible).Copy Destination:=Sheets("Combined Totals").Range(tCell.Offset(1) & lRow)
i ahve tried creating the destination to paste to using Cells and Range, but i can't seem to add variables into the syntax correctly.
What am i doing wrong?
Set this to the relevant worksheet
Set ws = ThisWorkbook.Sheets("OPT 1 Total")
With ws
'~~> Find the cell which has the name
Set sCell = .Range("A1:Z1").Find("MN")
Set tCell = Sheets("Combined Totals").Range("A1:Z1").Find("MN")
'~~> If the cell is found
If Not sCell Is Nothing Then
'~~> Get the last row in that column and check if the last row is > 1
lRow = .Range(Split(.Cells(, sCell.Column).Address, "$")(1) & .Rows.Count).End(xlUp).Row
If lRow > 1 Then
'~~> Set your Range
Set rng1 = .Range(sCell.Offset(1), .Cells(lRow, sCell.Column))
'bCell.Offset(1).Activate
Debug.Print tCell.Address
rng1.SpecialCells(xlCellTypeVisible).Copy Destination:=Sheets("Combined Totals").Range(tCell.Offset(1) & lRow)
'Cells(2, 1).Resize(rng1.Rows.Count) '
'~~> This will give you the address
Debug.Print rng1.Address
End If
End If
End With
EDIT2: parameterized....
Sub CopyAll()
TransferToTotals "OPT 1 Total", Array("MN", "TX", "CA")
TransferToTotals "OPT 2 Total", Array("MN", "TX", "CA")
End Sub
Sub TransferToTotals(srcSheet As String, arrHeaders)
Dim ws As Worksheet, sCell As Range, tCell As Range, lstCell As Range
Dim wsd As Worksheet, i As Long, arrHeadings
Set wsd = ThisWorkbook.Sheets("Combined Totals")
On Error Resume Next
Set ws = ThisWorkbook.Sheets(srcSheet)
On Error GoTo 0
If ws Is Nothing Then
Debug.Print "Source sheet '" & srcSheet & "' not found!"
Exit Sub
End If
For i = LBound(arrHeaders) To UBound(arrHeaders)
With ws
Set sCell = .Range("A1:Z1").Find(arrHeaders(i))
Set tCell = wsd.Range("A1:Z1").Find(arrHeaders(i))
If Not sCell Is Nothing And Not tCell Is Nothing Then
Set lstCell = .Cells(.Rows.Count, sCell.Column).End(xlUp)
If lstCell.Row > 1 Then
'EDIT - paste values only...
.Range(sCell.Offset(1), lstCell).SpecialCells( _
xlCellTypeVisible).Copy
wsd.Cells(Rows.Count, tCell.Column).End(xlUp) _
.Offset(1, 0).PasteSpecial xlPasteValues
End If
Else
Debug.Print "Couldn't find both '" & _
arrHeaders(i) & "' headers"
End If
End With
Next i
End Sub
I have two sheets containing the employee records.
Sheet1 contains the Event Date, CardNo, Employee Name, Dept Id, Employee No, Entry and Exit Time, Total Working Hours, Status, ConcatinatedColumn and Remarks (copied through vlookup from sheet2)
Sheet2 contains ConcatinatedColumn, Event Date, Employee No, Name, Remarks.
If the data in the remarks column of sheet2 is "Sick Off" then that row should be inserted to sheet1 without effecting the previous records.
I've already written the code for it but it does not work.
Would be really grateful if anyone can help me out !
THANKS IN ADVANCE !
MY CODE :
Sub SickOff()
Dim objWorksheet As Sheet2
Dim rngBurnDown As Range
Dim rngCell As Range
Dim strPasteToSheet As String
'Used for the new worksheet we are pasting into
Dim objNewSheet As Sheet1
Dim rngNextAvailbleRow As Range
'Define the worksheet with our data
Set objWorksheet = ThisWorkbook.Worksheets("Sheet2")
'Dynamically define the range to the last cell.
'This doesn't include and error handling e.g. null cells
'If we are not starting in A1, then change as appropriate
Set rngBurnDown = objWorksheet.Range("G2:G" & objWorksheet.Cells(Rows.Count, "G").End(xlUp).Row)
'Now loop through all the cells in the range
For Each rngCell In rngBurnDown.Cells
objWorksheet.Select
If rngCell.Value = "Sick Off" Then
'select the entire row
rngCell.EntireRow.Select
'copy the selection
Selection.Copy
'Now identify and select the new sheet to paste into
Set objNewSheet = ThisWorkbook.Worksheets("Sheet1" & rngCell.Value)
objNewSheet.Select
'Looking at your initial question, I believe you are trying to find the next available row
Set rngNextAvailbleRow = objNewSheet.Range("A1:A" & objNewSheet.Cells(Rows.Count, "A").End(xlUp).Row)
Range("A" & rngNextAvailbleRow.Rows.Count + 1).Select
ActiveSheet.Paste
End If
Next rngCell
objWorksheet.Select
objWorksheet.Cells(1, 1).Select
'Can do some basic error handing here
'kill all objects
If IsObject(objWorksheet) Then Set objWorksheet = Nothing
If IsObject(rngBurnDown) Then Set rngBurnDown = Nothing
If IsObject(rngCell) Then Set rngCell = Nothing
If IsObject(objNewSheet) Then Set objNewSheet = Nothing
If IsObject(rngNextAvailbleRow) Then Set rngNextAvailbleRow = Nothing
End Sub
Let's say you have data in Sheet2 as shown below
Let's say the end of data in Sheet1 looks like this
Logic:
We are using autofilter to get the relevant range in Sheet2 which match Sick Off in Col G. Once we get that, we copy the data to the last row in Sheet1. After the data is copied, we simply shuffle data across to match the column headers. As you mentioned that the headers won't change so we can take the liberty of hardcoding the column names for shuffling this data.
Code:
Paste this code in a module
Option Explicit
Sub Sample()
Dim wsI As Worksheet, wsO As Worksheet
Dim lRow As Long, wsOlRow As Long, OutputRow As Long
Dim copyfrom As Range
Set wsI = ThisWorkbook.Sheets("Sheet1")
Set wsO = ThisWorkbook.Sheets("Sheet2")
'~~> This is the row where the data will be written
OutputRow = wsI.Range("A" & wsI.Rows.Count).End(xlUp).Row + 1
With wsO
wsOlRow = .Range("G" & .Rows.Count).End(xlUp).Row
'~~> Remove any filters
.AutoFilterMode = False
'~~> Filter G on "Sick Off"
With .Range("G1:G" & wsOlRow)
.AutoFilter Field:=1, Criteria1:="=Sick Off"
Set copyfrom = .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow
End With
'~~> Remove any filters
.AutoFilterMode = False
End With
If Not copyfrom Is Nothing Then
copyfrom.Copy wsI.Rows(OutputRow)
'~~> Shuffle data
With wsI
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("A" & OutputRow & ":A" & lRow).Delete Shift:=xlToLeft
.Range("F" & OutputRow & ":F" & lRow).Copy .Range("K" & OutputRow)
.Range("F" & OutputRow & ":F" & lRow).ClearContents
.Range("B" & OutputRow & ":B" & lRow).Copy .Range("E" & OutputRow)
.Range("B" & OutputRow & ":B" & lRow).ClearContents
End With
End If
End Sub
Output: