I have an Excel Sheet wherein column "A" contains Serial numbers. One serial number may repeat to several rows. The cells in column "A" are merged [if more than one rows are appearing for One serial number]. I have made following macro to UN-merge these cells and repeat the serial number in subsequent blank rows until next serial number appears. The problem I am facing is that this macro is running very slow e.g. for a sheet containing 30,000 rows it may take a very long time. Is there a neat and less slower way to do it?
Here is the code I am using. Please guide.
Sub Unmerge_Cell()
Dim NumRows As Integer
Range("B2").Select
NumRows = Range("B2", Range("B2").End(xlDown)).Rows.Count
Columns("A:A").Select
Selection.UnMerge
Range("A2").Select
Range("A2").Activate
For i = 1 To NumRows - 1
If IsEmpty(ActiveCell.Offset(1, 0).Value) = True Then
ActiveCell.Select
Selection.Copy
ActiveCell.Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Else
ActiveCell.Offset(1, 0).Select
ActiveCell.Offset(0, 0).Activate
End If
Next
Range("A1").Select
End Sub
Regards
This should be the fastest solution, no loop, simple.
Sub unMerge()
Dim lastRow As Long
lastRow = Range("B2").End(xlDown).Row
Range("A:A").unMerge
Range("A2:A" & lastRow).SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=r[-1]c"
With Range("A2:A" & lastRow)
.Value = .Value 'convert formula to constant
End With
End Sub
I tried to simplyfy your code. I haven't tested it in Excel ;-/
Sub Unmerge_Cell()
Dim NumRows As Integer
Dim i as Long
NumRows = Range("B2", Range("B2").End(xlDown)).Rows.Count
For i = 1 To NumRows - 1
If IsEmpty(Range("A2").Offset(i,0).Value) Then
Range("A2").Offset(i,0).Value = Range("A2").Offset(i-1,0).Value
End If
Next
End Sub
You can also turn off and turn on the screen updating when you macro is running
At the beginning on your code insert
application.screenupdating = false
And turn it on at the end
application.screenupdating = true
Related
I am trying to get a macro to delete all rows with blank cells in row "F".
Here is my code:
Sub DeleteBlanks()
On Error Resume Next
Range([indirect("V1")]).Select.EntireRow.SpecialCells(xlBlanks).EntireRow.Delete
End Sub
The indirect(V1) refers to a variable which indicates what range to work in. Currently cell V1 contains Materjal!F1:F191.
But after applying the code to a button, when i click it, it only SELECTS the range, but does not remove the rows with empty cell values.
What am I doing wrong ?
fRange = Range(Cells(1,"F"),Cells(.CountRows,"F"))
If fRange = "" Then
Cells(.countRows,"F").EntireRow.Delete
End If
Is this working?
Try this:
Sub Macro1()
Dim i As Integer
Dim last As Integer
last = ActiveSheet.UsedRange.Rows.Count
''select unused column
Range("AA1").Select
Selection.Formula = "=IF(F1 = """", ""Y"", ""N"")"
Selection.AutoFill Destination:=Range("AA1:AA" & last)
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("AA1").Select
For i = 1 To last
If Selection.Value = "Y" Then
Selection.EntireRow.Delete
Else: ActiveCell.Offset(1, 0).Select
End If
Next
Columns("AA:AA").ClearContents
End Sub
I am trying to transpose every second and third row to columns B and C and then preferably delete the old rows so that I don't have two unused rows in B and C. I tried recording a macro, which worked for only the selection I made. Then I tried deleting the specific selections and replacing them with an offset range but I keep getting an error in the PasteSpecial line.
Sub SortRawData()
'
' SortRawData Macro
'
' Keyboard Shortcut: Ctrl+q
'
Selection.Offset(1, 0).Resize(Selection.Rows.Count + 2, _
Selection.Columns.Count).Select
ActiveCell.Copy
ActiveCell.Offset(-1, 1).Select
ActiveCell.PasteSpecial Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
Selection.Delete Shift:=xlUp
End Sub
I tried initially using Selection everywhere I have ActiveCell but neither seemed to work. I know I am missing the selection for the two rows I want to delete after I transpose the data into column B and C. What I have is a raw data dump of information that is formatted as:
Item1 Weight1 Color1 Item2 Weight2 Color2 Item 3 Weight 3 Color 3
I can get it to transpose one selection at a time by I can't seem to square away the automation of it.
Sub SortRawData2()
'
' SortRawData2 Macro
'
' Keyboard Shortcut: Ctrl+w
'
Selection.Copy
Range("B1").Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Rows("2:3").Select
Application.CutCopyMode = False
Selection.Delete Shift:=xlUp
End Sub
This is the initial recorded macro and even it fails debugging at the PasteSpecial line. Any suggestions would be much appreciated!
Thanks!
Try this, then code an autofilter to remove the empty rows:
Sub SortRawData2()
Dim lLastRow As Long, lLoop As Long
lLastRow = Cells(Rows.Count, 1).End(xlUp).Row
For lLoop = 1 To lLastRow Step 3
Cells(lLoop, 2) = Cells(lLoop + 1, 1)
Cells(lLoop, 3) = Cells(lLoop + 2, 1)
Cells(lLoop + 1, 1).Resize(2).ClearContents
Next lLoop
With Range("A1:A" & lLastRow)
.AutoFilter field:=1, Criteria1:="="
.Offset(1).SpecialCells(xlCellTypeVisible).EntireRow.Delete
.AutoFilter
End With
End Sub
Hi I have tired creating a loop which copies the entire row and pastes it in another worksheet, dependent upon two things.
Firstly, there is a level of completion column, if the values are not equal to 100% then they should be copied, also I only want rows copied that are not blank.
Having copied the rows into the next sheet, I want to run through column B and each time the value changes there should be inserted a new blank row.
I am not sure whether you can use this kind of loop this way, any input would be greatly appreciated.
Sheets("Tracker").Activate
For Each c In Range("H:B")
If c.Value <> "100%" _
And c.Offset(0, -6) <> "" Then
EntireRow.Select
Application.CutCopyMode = xlCopy
Selection.Copy
End If
Next
Sheets("Project Overview").Activate
Range("A24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Sheets("Project Overview").Activate
For Each b In Range("B24:B")
If b.Value <> "" Then
Selection.Insert Shift:=xlDown
End If
Next
End Sub
First, the line For Each c In Range("H:B") will loop through every cell in columns B-H. Is this really what you want? I don't think so. It will take your code forever to loop through that! It will also check your conditions for each and every cell!
Try the code I have pasted below. It uses AutoFilter which is much faster and more reliable, along with the SpecialCells, method to copy and paste the data.
When you insert the rows, you need to step backward from the last row to the beginning. This is because when Excel insert rows it will through your original counter off.
Sub FilterCopy()
Dim wT As Worksheet, wPO As Worksheet
Set wT = Sheets("Tracker")
Set wPO = Sheets("Project Overview")
With wT
Dim lRow As Long
lRow = .Range("B" & .Rows.Count).End(xlUp).Row
With .Range("B1:H" & lRow)
.AutoFilter 7, "<>100%" '7th column not 100% (column H)
.AutoFilter 1, "<>" '1st column not blank (column B)
End With
Intersect(.UsedRange,.UsedRange.Offset(1), .Range("B1").EntireColumn).SpecialCells(xlCellTypeVisible).EntireRow.Copy
End With
With wPO
.Range("A24").PasteSpecial xlPasteValues
lRow = .Range(.Range("B24"), .Range("B" & .Rows.Count).End(xlUp)).Rows
Dim i As Integer
For i = lRow To 24 Step -1
If .Range("B" & i) <> "" Then .Range("B" & i).Insert Shift:=xlDown
Next
End With
End Sub
I have the following VBA code that takes a single row from Sheet "Tabled data", copies the data, then pastes the data into the next available row in Sheet "Running list". However the original row has formulas and I need the values to paste, not the formulas. I've seen numerous ways to do it with Range.PasteSpecial but this code didn't use Range and I'm not sure how to incorporate it.
Note: I modified this code from here: http://msdn.microsoft.com/en-us/library/office/ff837760(v=office.15).aspx. It originally had an IF statement to match content in a cell then paste it in a certain sheet according to the content in the cell. I only had one sheet to copy to and didn't need the IF. I don't really need to find the last row of data to copy either as it will only ever be one row with range of A2:N2. But if I take out the FinalRow section and the For and replace with Range("A2:N2") it doesn't work so I left those in.
Any guidance on how to add in the PasteValues property without making this more complicated? I'm also open to simplification of the For or FinalRow variable such as using Range. I'm only sort of familiar with VBA, having done a few things with it, but usually after much searching and modifying code.
Public Sub CopyData()
Sheets("Tabled data").Select
' Find the last row of data
FinalRow = Cells(Rows.Count, 1).End(xlUp).Row
' Loop through each row
For x = 2 To FinalRow
ThisValue = Cells(x, 1).Value
Cells(x, 1).Resize(1, 14).Copy
Sheets("Running list").Select
NextRow = Cells(Rows.Count, 1).End(xlUp).Row + 1
Cells(NextRow, 1).Select
ActiveSheet.Paste
Sheets("Tabled data").Select
Next x
End Sub
Hopefully we can actually make this more simple.
Public Sub CopyRows()
Sheets("Sheet1").UsedRange.Copy
lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
'check if the last cell found is empty
If IsEmpty(ActiveSheet.Cells(lastrow, 1)) = True Then
'if it is empty, then we should fill it
nextrow = lastrow
Else
'if it is not empty, then we should not overwrite it
nextrow = lastrow + 1
End If
ActiveSheet.Cells(nextrow, 1).Select
ActiveSheet.Paste
End Sub
edit: I expanded it a little so that there won't be a blank line at the top
I found a working solution. I recorded a macro to get the paste special in there and added the extra code to find the next empty row:
Sub Save_Results()
' Save_Results Macro
Sheets("Summary").Select 'renamed sheets for clarification, this was 'Tabled data'
'copy the row
Range("Table1[Dataset Name]").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
' paste values into the next empty row
Sheets("Assessment Results").Select
Range("A2").Select
NextRow = Cells(Rows.Count, 1).End(xlUp).Row + 1
Cells(NextRow, 1).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
' Return to main sheet
Sheets("Data Assessment Tool").Select
End Sub
Just copy the data all at once, no need to do it a row at a time.
Sub CopyData()
With ThisWorkbook.Sheets("Tabled data")
Dim sourceRange As Range
Set sourceRange = .Range(.Cells(2, 1), .Cells(getLastRow(.Range("A1").Parent), 14))
End With
With ThisWorkbook.Sheets("Running list")
Dim pasteRow As Long
Dim pasteRange As Range
pasteRow = getLastRow(.Range("A1").Parent) + 1
Set pasteRange = .Range(.Cells(pasteRow, 1), .Cells(pasteRow + sourceRange.Rows.Count, 14))
End With
pasteRange.Value = sourceRange.Value
End Sub
Function getLastRow(ws As Worksheet, Optional colNum As Long = 1) As Long
getLastRow = ws.Cells(ws.Rows.Count, colNum).End(xlUp).Row
End Function
Private Sub Load_Click()
Call ImportInfo
End Sub
Sub ImportInfo()
Dim FileName As String
Dim WS1 As Worksheet
Dim WS2 As Worksheet
Dim ActiveListWB As Workbook
Dim check As Integer
'Application.ScreenUpdating = False
Set WS2 = ActiveWorkbook.Sheets("KE_RAW")
confirm = MsgBox("Select (.xlsx) Excel file for Data transfer." & vbNewLine & "Please ensure the sheets are named Sort List, Second and Third.", vbOKCancel)
If confirm = 1 Then
FileName = Application.GetOpenFilename(FileFilter:="Excel Files (*.xls*),*.xls*", _
Title:="Select Active List to Import", MultiSelect:=False)
If FileName = "False" Then
MsgBox "Import procedure was canceled"
Exit Sub
Else
Call CleanRaw
Set ActiveListWB = Workbooks.Open(FileName)
End If
Set WS1 = ActiveListWB.Sheets("Sort List")
WS1.UsedRange.Copy 'WS2.Range("A1")
' WS2.Range("A1").Select
WS2.UsedRange.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'WS2.Range ("A1")
ActiveWorkbook.Close False
'Call ClearFormulas
' Call RefreshAllPivotTables
Sheets("Key Entry Data").Select
'Sheets("Raw").Visible = False
'Application.ScreenUpdating = True
MsgBox "Data has been imported to workbook"
Else
MsgBox "Import procedure was canceled"
End If
Application.ScreenUpdating = True
End Sub
Sub CleanRaw()
Sheets("KE_RAW").Visible = True
Sheets("KE_RAW").Activate
ActiveSheet.Cells.Select
Selection.ClearContents
End Sub
I am trying to select columns E and K from sheet Input, process in Working sheet and paste in the Output sheet after the last used row. I have stored the last used row number in x and paste the values in x+1 cell. However excel selects last row of the sheet (x as 65536) and gives run time error 4004. Can someone please help me in assisting the code.
Dim x As Long, y As String
Sheets("Input").Activate
Range("E:E,K:K").Select
Range("K1").Activate
Selection.Copy
Sheets("Working").Select
Cells(1, 1).Select
ActiveSheet.Paste
Cells.Select
Application.CutCopyMode = False
Selection.AutoFilter
Range("B5").Select
ActiveSheet.Range("$A$1:$H$30").AutoFilter Field:=1, Criteria1:="="
Cells.Select
Selection.Delete Shift:=xlUp
Columns("B:B").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Range("B2").Select
ActiveCell.FormulaR1C1 = _
"=IF(RC[-1]="""","""",VLOOKUP(RC[-1],Repository!C[-1]:C[1],3,0))"
Range("B2").Select
Selection.Copy
Range("B3:B30").Select
ActiveSheet.Paste
Cells.Select
Application.CutCopyMode = False
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("B2:C2").Select
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Output").Select
Range("A1").Select
x = Worksheets("Output").UsedRange.Rows.Count
y = "a" & Trim(x + 1)
ActiveSheet("Output").Range(y).Select
ActiveSheet.Paste
Your UsedRange is still thinking that the last row is 65536. Add this subroutine, then call it right before you set x.
Sub CorrectUsedRange()
Dim values
Dim usedRangeAddress As String
Dim r As Range
'Get UsedRange Address prior to deleting Range
usedRangeAddress = ActiveSheet.UsedRange.Address
'Store values of cells to array.
values = ActiveSheet.UsedRange
'Delete all cells in the sheet
ActiveSheet.Cells.Delete
'Restore values to their initial locations
Range(usedRangeAddress) = values
End Sub
Near the bottom of your code replace:
Sheets("Output").Select
with:
Sheets("Output").Select
ActiveSheet.UsedRange
this should "re-set" UsedRange
Sometimes the Used Range gets generically large and won't reset on it's own. When this happens, the only way that I've found to force it to reset itself correctly is to Save the Workbook that the subject Worksheet is in. This works for me, on Excel 2010 anyway. Since you're using .Select and Active<obj> (which I don't recommend), it would simply be this:
ActiveWorkbook.Save
I would use a Find loop to populate an array and then output the array when the macro has completed. There is no need for a "Working" sheet. This also uses Cells(Rows.Count, "A").End(xlUp) in order to find the last populated row instead of UsedRange.Rows.Count which can be unreliable.
Sub tgr()
Dim rngFound As Range
Dim rngLookup As Range
Dim arrResults() As Variant
Dim ResultIndex As Long
Dim strFirst As String
With Sheets("Input").Columns("E")
Set rngFound = .Find("*", .Cells(.Cells.Count), xlValues, xlWhole)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
ReDim arrResults(1 To WorksheetFunction.CountA(.Cells), 1 To 2)
Do
If rngFound.Row > 1 Then
ResultIndex = ResultIndex + 1
On Error Resume Next 'Just in case the VLookup can't find the value on the 'Repository' sheet
arrResults(ResultIndex, 1) = Evaluate("VLOOKUP(""" & rngFound.Value & """,Repository!A:C,3,FALSE)")
arrResults(ResultIndex, 2) = .Parent.Cells(rngFound.Row, "K").Value
On Error GoTo 0 'Remove the On Error Resume Next condition
End If
Set rngFound = .Find("*", rngFound, xlValues, xlWhole)
Loop While rngFound.Address <> strFirst
End If
End With
If ResultIndex > 0 Then Sheets("Output").Cells(Rows.Count, "A").End(xlUp).Offset(1).Resize(ResultIndex, UBound(arrResults, 2)).Value = arrResults
Set rngFound = Nothing
Erase arrResults
End Sub
instead of used range check how many rows already are filled with this code:
X = WorksheetFunction.CountA(Columns(1))
Of course this only works ok if you have no rows that are empty in Column A, as those rows would be ignored!