VBA: insert a new row before found cell - vba

Below is the code that I'm running, I'm not too sure if I can get what I want.
But strangely, the code is taking too long to run.
I was waiting for it for an hour.
So I figured there must be some errors in the code.
Can anybody shed some light on this?
Set x = Workbooks.Open("C:\Users\Desktop\testing.xlsx")
For Each ws In x.Worksheets
If ws.Name <> "Master" Then
lrow = ws.Cells(Rows.Count, "A").End(xlUp).Row
Set rng = ws.Range(Cells(1, 1), Cells(lrow, 1))
For Each Acell In rng
If (Acell.Value = "Sum") Then
Acell.Offset(-1, 0).EntireRow.Insert
End If
Next Acell
End If
Next ws
I'm looking for that "Sum" word in Col A, for every sheets in workbook except "master" sheet.

Instead of the For Each loop use a For i = lRow to 1 Step -1 and then use i to access each row: If ws.Cells(i, 1) = "Sum" Then ws.Rows(i).Insert.
When looping from the bottom, then inserting/deleting rows doesn't affect rows above (which are not processed yet) but just rows below (which are already processed).
Dim iRow As Long, lRow As Long
Dim ws As Worksheet
Dim x As Workbook
Set x = Workbooks.Open("C:\Users\Desktop\testing.xlsx")
For Each ws In x.Worksheets
If ws.Name <> "Master" Then
lRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
For iRow = lRow To 1 Step -1 'walk through rows from last row (lRow) to first row going upwards (Step -1)
If ws.Cells(iRow, 1) = "Sum" Then
ws.Rows(iRow).Insert xlDown 'insert new row and move other rows down
Exit For 'if there is only one "Sum" you can exit for here (to shorten the run time)
'if there are more that one "Sum" in a sheet then remove that line.
End If
Next iRow
End If
Next ws

When you insert a row and then continue with the loop you will end up on a "Sum"-row again (it has been pushed one row down due to the Insert). Therefore your code will insert row after row after row after row... forever
Try this code (inside the If)... not the best solution perhaps, but it works:
lastrow = ws.Cells(Rows.Count, "A").End(xlUp).Row
R = 1
Do Until R > lastrow
If (ws.Cells(R, 1).Value = "Sum") Then
ws.Cells(R, 1).EntireRow.Insert
R = R + 1 ' Jump one extra step (to skip the inserted row)
lastrow = lastrow+ 1 ' The last row is increased due to the inserted row
End If
R = R + 1
Loop

Since there is only 1 sum in a column
Set x = Workbooks.Open("C:\Users\Desktop\testing.xlsx")
For Each ws In x.Worksheets
If ws.Name <> "Master" Then
lrow = ws.Cells(Rows.Count, "A").End(xlUp).Row
Set rng = ws.Range(Cells(1, 1), Cells(lrow, 1))
For Each Acell In rng
If (Acell.Value = "Sum") Then
Acell.Offset(-1, 0).EntireRow.Insert
exit for
End If
Next Acell
End If
Next ws
try this code.

You are looping through the worksheets but not using each individual worksheet as the parent worksheet to the cells. Without a qualified parent worksheet, each Cells simply defaults to the ActiveSheet.
For Each ws In x.Worksheets
If ws.Name <> "Master" Then
with ws
lrow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range(.Cells(1, 1), .Cells(lrow, 1))
For Each Acell In rng
If Acell.Value = "Sum" Then
Acell.Offset(-1, 0).EntireRow.Insert
End If
Next Acell
end with
End If
Next ws
Note that you are starting in row 1 and if A1 is Sum then you are trying to insert a row at row 0. There is no row zero.

Have you tried setting Workbook Calculation to Manual, i found this helpful since I tend to work with workbooks with a load of sheets an every sheets has a load of formulas.
File>Options>Formulas
then set Workbook Calculations to manual, but if you want to automate this.
Sub Macro1()
'
' Macro1 Macro
'
' Keyboard Shortcut: Ctrl+e
'
calcu
'your code here
ActiveWorkbook.Application.Calculation = xlCalculationAutomatic
End Sub
'=
Function calcu()
Dim xlCalc As XlCalculation
xlCalc = Application.Calculation
ActiveWorkbook.Application.Calculation = xlCalculationManual
On Error GoTo CalcBack
Exit Function
CalcBack:
ActiveWorkbook.Application.Calculation = xlCalc
End Function
I got this from somewhere in stack but I forgot which post, so if you're the one who did this, thanks. :)

Related

Copy varying range from multiple sheets and paste from same row

I am working currently with one workbook and want to implement a preparatory work, copy/pasting all the relevant range from my workbook contained in separate worksheets (3 worksheets at most).
I have the below code to loop through the worksheets, unfortunately I am unable to write the paste-command so as to paste these ranges from the same row successively. I want Transpose:= True. I.E Rgn from sheet1 starting from B2, after last filled cell on the right starts Rgn from Sheet2, after last filled cell starts Rgn from Sheet3 (provided Rgn exists for Sheet3).
Currently, my code overwrites what was copied from previous sheet.
I found a potential reference here (VBA Copy Paste Values From Separate Ranges And Paste On Same Sheet, Same Row Offset Columns (Repeat For Multiple Sheets)) but I am not sure how to use Address nor how the Offset is set in the solution.
' Insert temporary tab
Set sh = wb.Sheets.Add(after:=wb.Sheets(wb.Sheets.Count))
sh.Name = "Prep"
'Loop
For Each sh In wb.Worksheets
Select Case sh.Index
Case 1
Sheets(1).Range("D16:D18").Copy
Case 2
lastrow = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row
lastcol = Sheets(2).Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = Sheets(2).Range("M9", Sheets(2).Cells(lastrow, lastcol))
Rng.Copy
Case 3
'Check if Range (first col for answers) is not empty
If Worksheetunction.CountA(Range("L9:L24")) = 0 Then
Exit For
Else
lastrow = Sheets(3).Range("A" & Rows.Count).End(xlUp).Row
lastcol = Sheets(3).Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = Sheets(3).Range("L9", Sheets(3).Cells(lastrow, lastcol))
Rng.Copy
End If
End Select
wb.Sheets("Prep").UsedRange.Offset(1,1).PasteSpecial Paste:=xlPasteAll, Transpose:=True
Next
Set sh = Nothing
Set Rng = Nothing
Can you try this? UsedRange can be unpredictable. You can also have problems if you don't have anything in the first cell of Rng, in which case this code will need adjusting.
I would also prefer to use the sheeet name rather than index.
Sub x()
Dim sh As Worksheet, wb As Workbook, Rng As Range
Set sh = wb.Sheets.Add(after:=wb.Sheets(wb.Sheets.Count))
sh.Name = "Prep"
'Loop
For Each sh In wb.Worksheets
Select Case sh.Index
Case 1
Set Rng = sh.Range("D16:D18")
Case 2
lastrow = sh.Range("A" & Rows.Count).End(xlUp).Row
lastcol = sh.Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = sh.Range("M9", sh.Cells(lastrow, lastcol))
Case 3
'Check if Range (first col for answers) is not empty
If WorksheetFunction.CountA(sh.Range("L9:L24")) = 0 Then
Exit For
Else
lastrow = sh.Range("A" & Rows.Count).End(xlUp).Row
lastcol = sh.Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = sh.Range("L9", sh.Cells(lastrow, lastcol))
End If
End Select
Rng.Copy
wb.Sheets("Prep").Cells(2, Columns.Count).End(xlToLeft).Offset(, 1).PasteSpecial Paste:=xlPasteAll, Transpose:=True
Next
Set sh = Nothing
Set Rng = Nothing
End Sub

Excel VBA - Merge rows until last row

I'm trying to make a macro that will scroll through a spreadsheet an entire row at a time and merge all cells in the active row if they have data. It should do this until the last row.
The code currently sees all rows as empty and therefor skips them, I need an if condition or do until statement that will help detect and skip empty rows, detect rows with data and merge their cells and stop entirely when it reaches the last row.
My current code:
Sub merge()
Dim LastRow As Long, i As Long
Sheets("Body").Activate
LastRow = Cells(Rows.Count, "A").End(xlUp).Row
Rows("1:1").Select
For i = 1 To LastRow
If Range("A" & i).Value = "*" Then
Selection.merge = True
Selection.Offset(1).Select
Else
Selection.Offset(1).Select
End If
Next i
End Sub
I have also tried:
sub merge2()
Dim LastRow As Long, i As Long
Sheets("Body").Activate
LastRow = Cells(Rows.Count, "A").End(xlUp).Row
Rows("1:1").Select
Do Until ActiveCell.EntireRow > LastRow
'this line below was a concept
If ActiveCell.EntireRow & ActiveCell.Column.Value = "*" Then
Selection.merge = True
Selection.Offset(1).Select
Else
Selection.Offset(1).Select
End If
Loop
End Sub
This is untested but should do what you want.
Option Explicit
Sub merge()
Dim ws As Worksheet
Dim LastRow As Integer, i As Integer
Set ws = ThisWorkbook.Sheets("Body")
ws.Activate
With ws
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
For i = 1 To LastRow
If Not IsEmpty(Range("A" & i)) And ws.Cells(i, Columns.Count).End(xlToLeft).Column > 1 Then
ws.Rows(i & ":" & i).merge
End If
Next i
End Sub
This If will test for a) whether the cell in column A is empty and b) whether there are any other cells in that row. if statement a evaluates to false AND statement b is greater than 1 it will execute the If statement
#Tom I've taken your code and added in an error handler that makes it work without fault, thank you very much for your patience, you've been a fantastic help.
Sub merge2()
Dim ws As Worksheet
Dim LastRow As Integer, i As Integer
Set ws = ThisWorkbook.Sheets("Body")
ws.Activate
With ws
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
For i = 1 To LastRow
If Not IsEmpty(Range("A" & i)) And ws.Cells(i, Columns.Count).End(xlToLeft).Column >= 1 Then
On Error Resume Next
ws.Rows(i & ":" & i).merge = True
End If
Next i
End Sub

I want to copy the Some of entire row having same word in the first column as in A3,A4,A5,A6 & paste to another sheet from the vacant rows?

I have some rows in copySheet.sheet1 having some special keyword in first column as "Ojha" . So I want to copy those entire row having "Ojha" in first row & paste it into another pasteSheet.sheet2 . At first I found that cell Having "Ojha". So I put it in Foundcell. So now I used...:
Foundcell.EntireRow.Copy
& in another sheet first I find the vacant rows from where the rows will paste, so
RowCount = WorksheetFunction.CountA(pasteSheet.Range("A:A")) + 1
pasteSheet.Range("A" & RowCount).PasteSpecial xlPasteValues
so it pasted only first row having "Ojha"
So now I want to copy all those rows which are having "Ojha" in the first column & paste to pasteSheet next to next.
If you just want to loop through the cells, this will work
Sub Loopy()
Dim sh As Worksheet, ws As Worksheet
Dim Rws As Long, rng As Range, c As Range
Set sh = Sheets("Sheet1")
Set ws = Sheets("Sheet2")
Application.ScreenUpdating = 0
With sh
Rws = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range(.Cells(1, 1), .Cells(Rws, 1))
End With
With ws
For Each c In rng.Cells
If c = "Ojha" Then
c.EntireRow.Copy
.Cells(.Rows.Count, "A").End(xlUp).Offset(1).PasteSpecial xlPasteValues
End If
Next c
End With
Application.CutCopyMode = 0
End Sub
You can also use an autofilter macro...

I need to create a vba script or macro that can transpose and format data all at once

I have found the code
Sub Test()
Application.ScreenUpdating = False
Dim LastRow As Long
LastRow = Cells.Find("*", SearchOrder:=xlByRows,SearchDirection:=xlPrevious).Row
Dim lColumn As Long
Dim x As Long
Dim rng As Range
For Each rng In Range("A1:A" & LastRow)
lColumn = Cells(rng.Row, Columns.Count).End(xlToLeft).Column
For x = 1 To lColumn - 2
Range(Cells(rng.Row, "A"), Cells(rng.Row, "B")).Copy Sheets("Sheet2").Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
Sheets("Sheet2").Cells(Rows.Count, "C").End(xlUp).Offset(1, 0) = rng.Offset(0, x + 1)
Next x
Next rng
Application.ScreenUpdating = True
End Sub
I am trying to modify it to suit my needs but it isn't quite doing what I need it to do.
Basically, my table is like this:
A B C D
FILENAME ID FIELD1 FIELD2
1 2 3 4
and I want it to look like this:
A FILENAME 1
B ID 2
C FIELD1 3
D FIELD2 4
however, sometimes there may be more columns or rows associated with a given part of the range that is related to a set of data. right now the columns that
I don't know nearly enough about excel and vba to modify this code to do that, but it would be nice if I could.
below are a couple of links that explain closely how I want the final table to look.
http://pastebin.com/1i5MqTL7
http://imgur.com/a/PKAcy
The ID's are not unique product pointers, but that's the REAL world. Different considerations and assumptions about the consistency of your input data, but try this:
Private Sub TransposeBits()
Application.ScreenUpdating = False
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet2")
'start will be the starting row of each set
Dim start As Long
start = 2
'finish will be the last row of each set
Dim finish As Long
finish = start
Dim lastRow As Long
lastRow = Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'printRow will keep track of where to paste-transpose each set
Dim printRow As Long
printRow = lastRow + 2
'lastCol will measure the column count of each set
Dim lastCol As Long
'Just dealing with a single entry here - delete as necessary
If lastRow < 3 Then
lastCol = Cells(start, 1).End(xlToRight).Column
With ws
.Range(.Cells(start, 1), .Cells(finish, lastCol)).Copy
.Cells(printRow, 1).PasteSpecial Transpose:=True
End With
Application.ScreenUpdating = True
'in the trivial case, we can exit the sub after dealing with the one-line transpose
Exit Sub
End If
'more general case
For i = 3 To lastRow
If Not Range("A" & i).Value = Range("A" & i - 1).Value Then
'the value is different than above, so set the finish to the above row
finish = i - 1
lastCol = Cells(start, 1).End(xlToRight).Column
'copy the range from start row to finish row and paste-transpose
With ws
.Range(.Cells(start, 1), .Cells(finish, lastCol)).Copy
.Cells(printRow, 1).PasteSpecial Transpose:=True
End With
'after finding the end of a set, reset the start and printRow variable
start = i
printRow = printRow + lastCol
End If
Next i
'here we deal with the last set after running through the loop
finish = lastRow
lastCol = Cells(start, 1).End(xlToRight).Column
With ws
.Range(.Cells(start, 1), .Cells(finish, lastCol)).Copy
.Cells(printRow, 1).PasteSpecial Transpose:=True
End With
Application.ScreenUpdating = True
End Sub
You can use the Paste Special that #Jeeped uses - just write it in code:
Sub TransposeData()
Dim rLastCell As Range
With ThisWorkbook.Worksheets("Sheet1")
'NB: If the sheet is empty this will throw an error.
Set rLastCell = .Cells.Find("*", SearchDirection:=xlPrevious)
'Copy everything from A1 to the last cell.
.Range(.Cells(1, 1), rLastCell).Copy
'Paste/Transpose in column A, one row below last row containing data.
.Cells(rLastCell.Row + 1, 1).PasteSpecial Transpose:=True
End With
End Sub

Delete rows over multiple worksheets in Excel if cell value equals "blank"

I want to delete rows over multiple worksheets (only specific ones within the workbook) if a cell value is blank. Note, the rest of the fields in the row do contain data. So far I have the below however unsure how to specify the worksheets. Can anyone help?
Sub sbDelete_rows_if_cell_blank()
Dim lRow As Long
Dim iCntr As Long
lRow = 2000
For iCntr = lRow To 1 Step -1
If Cells(iCntr, 1).Value = "" Then
Rows(iCntr).Delete
End If
Next
End Sub
Putting your code inside this loop will loop through all the worksheets in the Workbook that this code is inside and run your code in each.
Sub sbDelete_rows_if_cell_blank()
Dim lRow As Long
Dim iCntr As Long
Dim ws as Worksheet
For each ws in ThisWorkbook.Worksheets
' Find last row in column A
lRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
For iCntr = lRow To 1 Step -1
If ws.name<>"Sheet1" and ws.name <> "Sheet2" then ' change this line to the sheet names you want to leave out.
If IsEmpty(ws.Cells(iCntr, 1)) Or Trim(ws.Cells(iCntr, 1).Value) = "" Then
ws.Rows(iCntr).Delete
End If
end if
Next iCntr
Next ws
End Sub
Updated with D_Bester's suggestion for if condition
Update 2: See Comments
This will do what I think you want to achieve
Sub Combine()
Dim nws, ws As Worksheet
Dim rng As Range
' Add New Sheet
On Error Resume Next
Set nws = ThisWorkbook.Sheets("Combined")
If nws Is Nothing Then
With ThisWorkbook.Sheets
Set nws = .Add(After:=Sheets(.Count))
nws.Name = "Combined"
End With
End If
On Error GoTo 0
For Each ws In ThisWorkbook.Sheets
If Not ws.Name = nws.Name Then
With ws
Set rng = Range(.Cells(1, 1), .Cells(.UsedRange.Rows.Count, .UsedRange.Columns.Count))
rng.Copy Destination:=nws.Cells(nws.Cells(nws.Rows.Count, "A").End(xlUp).Row + 1, 1)
End With
End If
Next ws
End Sub
You can loop through the sheets, then use specialcells to delete the blanks.
Yoi can also set the loop so it doesn't delete the blanks in "Sheet1"(in this example)
Sub DeleteBlnkRows()
Dim sh As Worksheet
For Each sh In Sheets
If sh.Name <> "Sheet1" Then
sh.Columns("A:A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
End If
Next sh
End Sub