excel vba showing incorrect data after certain manipulations - excel

Sequence of events which I am trying to achieve:
1) I have data on Sheet1
2) I filter the data on Sheet1 according to a certain criteria and then copy the data to another Sheet say "Difference". The data has around 8 lines.
3) I then insert 11 lines between the data on sheet "Difference" after every 2 lines.
4) Next I insert 4 columns before the first column
5) I then insert the column header for the first 4 inserted column and row headers till the UsedRange.
6) After that I am doing certain less intensive calculations on the data such as comparing the values and looking up data from another workbook.
All this is in a macro on click of a button.
While clicking the button what happens is that sometimes I get the rows and columns in a sequence as expected and actually most of the times after the first 4 columns the rows come in a zig zag manner i.e. sometimes they would comes 5 - 6 columns after the first 4 columns and on other runs of a macro the rows would come after 50 lines or so.
I investigated my code but couldn't find any reason why this is happening. Also this happens intermittently. As I mentioned sometimes the result comes fine and most of the times the result (rows and columns) come in a zig zag manner.
Why is macro doing this? I am really having a hard time thinking about it? I have no answer. It seems so illogical.
I could post my code but it's too big. Please let me know which portion of the code should I post.
Please do suggest. Having a really hard time.
I am posting my code snippet below:
Private Sub CommandButton1_Click()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.EnableEvents = False
ActiveSheet.DisplayPageBreaks = False
Dim wb As Workbook
Dim sh1 As Worksheet
Dim sh2 As Worksheet
Dim sh3 As Worksheet
Dim ws As Worksheet
Dim i As Long
Set wb = GetObject(ActiveWorkbook.Path & "\ReconUtility_Enhanced.xlsm")
Set sh1 = wb.Sheets("Sheet1")
Set sh2 = wb.Sheets("Sheet2")
MsgBox sh2.UsedRange.Rows.count
For i = 1 To sh2.UsedRange.Rows.count
sh1.Activate
ActiveSheet.UsedRange.Select
Selection.AutoFilter
sh1.Range("E1").AutoFilter Field:=5, Criteria1:=sh2.Cells(i, 1).Value
Selection.Copy
With ThisWorkbook
Set ws = .Sheets.Add(After:=.Sheets(.Sheets.count))
ws.Name = sh2.Cells(i, 2).Value
End With
Sheets(sh2.Cells(i, 2).Value).Select
'Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Selection.PasteSpecial Paste:=xlPasteValuesAndNumberFormats, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ActiveSheet.UsedRange.Columns.AutoFit
Next i
sh1.Activate
ActiveSheet.UsedRange.Select
Selection.AutoFilter
sh1.Range("E1").AutoFilter Field:=5, Criteria1:="Field Difference"
Selection.Copy
Sheets("Field Difference").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ActiveSheet.UsedRange.Columns.AutoFit
MsgBox "Field Difference Copy completd"
' Step 2. Insert 11 lines and Insert 4 columns for analysis
Set sh3 = wb.Sheets("Field Difference")
Dim x As Long
Dim j As Long
Dim i1 As Long
Dim fieldRows As Long
j = 1
fieldRows = sh3.UsedRange.Rows.count
Dim rowsAfterInsertingLines As Long
rowsAfterInsertingLines = fieldRows / 2
Const count = 11
For i1 = 2 To fieldRows
If i1 Mod 2 = 1 Then
For x = 1 To count
sh3.Rows(i1 + j).Insert Shift:=xlDown
j = j + 1
Next
End If
Next i1
MsgBox "Inserted Lines Done"
' Inserting 4 columns before the first column
sh3.Range("A:D").EntireColumn.Insert Shift:=xlToRight
sh3.Range("A1").Value = "Data Source Name"
sh3.Range("B1").Value = "Final Status"
sh3.Range("C1").Value = "UserName"
sh3.Range("D1").Value = "Ownership"
MsgBox "Columns Inserted"
' Now a Loop to insert the values - (CMRS, DTCC-US, Difference, 2 Eye Check, 4 Eye Check)
Dim myModifiedArray() As Variant
myModifiedArray = Array("CMRS", "DTCC-US", "Difference", "Sapient Comments (History)", "Last Sapient Comment / 2 Eye Analysis", "4 Eye Analysis", "4 Eye Comments", "Last Comment made by (Sapient)", "Date of Last Comment (Sapient)", "NWM Comment (History)", "Last NWM Commnent", "Last Comment made by (NWM)", "Date of Last Comment (NWM)")
Dim rCount As Long
rCount = 2
Dim iCount As Long
Dim jCount As Long
For iCount = 1 To rowsAfterInsertingLines
For jCount = LBound(myModifiedArray) To UBound(myModifiedArray)
sh3.Cells(rCount, 1).Value = myModifiedArray(jCount)
rCount = rCount + 1
Next jCount
Next iCount
MsgBox "Row headers inserted"
End Sub

Related

VBA: How come pausing my macro makes it faster?

As suggested yesterday, I'm splitting my question into two parts, although I think they might be connected:
I have an Excel-macro that basically works, but it gets slower the more sheets are added by the macro. when I create only a few sheets (~100) it's ok but sometime it creates up to a few hundred sheets and every sheet is a different report, and I have to keep all the sheets. An then the issue starts.
Afer the macro creates all those sheets, I do tings like sorting an printing. But before the macro continues with this tasks it takes a very long time, depending on how many sheets I've just produced.
A few years ago I had an issue with a slow macro. Then I found the hint with a forced pause. I've tried it with this macro again, and it improved the speed by a huuuge amount of time. How come a pause speeds up a macro?
The code is a bit longer so I've reduced it to address the issue and marked it in the code:
Sub My_Issues()
Dim ColumnLetter As String, item As String
Dim cell As Range
Dim sheetCount As Integer, TotalRow As Integer, TotalCol As Integer
Dim uniqueArray As Variant
Dim lastRow As Long, x As Long
Application.ScreenUpdating = False
'Get unique brands:
With Sheets("Brand")
.Columns(1).EntireColumn.Delete
Sheets("Sales").Columns("R:R").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=.Range("A1"), Unique:=True
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
If .Range("A3:A" & lastRow).Cells.Count = 1 Then
ReDim uniqueArray(1, 1)
uniqueArray(1, 1) = .Range("A3")
Else
uniqueArray = .Range("A3:A" & lastRow).Value
End If
End With
TotalRow = Sheets("Sales").UsedRange.Rows.Count
TotalCol = Sheets("Sales").UsedRange.Columns.Count
ColumnLetter = Split(Cells(1, TotalCol).Address, "$")(1) 'Num2Char
sheetCount = 0 'Counter for statusbar
For x = 1 To UBound(uniqueArray, 1)
item = uniqueArray(x, 1) 'item=Brand
'Filter sales for each brand:
With Sheets("Sales")
.Range(.Cells(2, 1), .Cells(TotalRow, TotalCol)).AutoFilter Field:=18, Criteria1:=item
End With
With Sheets("Agents")
'Delete old...
.Range(.Cells(2, 1), .Cells(2, 1).End(xlDown)).Clear
'...and get new
Sheets("Sales").Range(Sheets("Sales").Cells(3, 2), Sheets("Sales").Cells(2, 2).End(xlDown)).SpecialCells(xlCellTypeVisible).Copy
.Range("A2").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
End With
'List with all agents
For Each cell In Worksheets("Agents").Range("A2", Worksheets("Agents").Range("A1").End(xlDown))
With Sheets("Report")
.Range("I4") = cell 'Copy agent and update the formulas within the report
.Range(.PageSetup.PrintArea).Copy
Sheets.Add After:=Sheets("Report")
Selection.PasteSpecial Paste:=xlPasteAllUsingSourceTheme, Operation:=xlNone _
, SkipBlanks:=False, Transpose:=False
Selection.PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
ActiveSheet.UsedRange.Value = ActiveSheet.UsedRange.Value 'Replace all formulas with values
Application.CutCopyMode = False
ActiveSheet.Name = cell
sheetCount = sheetCount + 1
If sheetAnz Mod 10 = 0 Then Application.StatusBar = sheetAnz 'Get statusupdate every 10 sheets
End With
Next
'->Issue: I create up to 400 sheets and when I want to continue and do some sorting of the sheets for example it takes a very long time.
'But if I add this break for a second, it works reasonably fine again. Why is that? Does vba needs the break to catch up with itself?
'Since the issue is not the sorting and the other stuff after the pause.
Application.Wait (Now + TimeValue("0:00:01"))
'Continue with other stuff.... sorting sheets and so on
Next
Application.ScreenUpdating = True
End Sub
Any ideas on this issue?

How to use VBA to loop through cutting a range of cells and pasting into next row

The purpose of this VBA is to make a single long row of values (tens of thousands) into something more readable by keeping each row limited to 22 values. I have a manual version of this which works for 200 rows, but am hoping to use looping to save myself time and hopefully improve performance.
Example:
I have values in A1:ZZ1 and am trying to cut W1:ZZ1 and paste into A2, then cut W2:ZD2 and paste into A3 until there are no values left to cut and paste.
I'm using Excel 2010.
Sub InsertScript22perLine()
'Turn off screen updating to speed up macro
Application.ScreenUpdating = False
Range("W1").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Cut
Selection.End(xlToLeft).Select
Range("A2").Select
ActiveSheet.Paste
Range("W2").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Cut
Selection.End(xlToLeft).Select
Range("A3").Select
ActiveSheet.Paste
'Turn screen updating back on
Application.ScreenUpdating = True
End Sub
Sub InsertScript22perLine()
Application.ScreenUpdating = False
' Starting column for input data
Dim sStartCol As String
Dim lStartCol As Long
' Count of columns
Dim lColCount As Long
' Count of columns of data for output
Dim lRowLen As Long
lRowLen = 22
Dim lRow As Long
lRow = 2
sStartCol = "W"
lStartCol = Range(sStartCol & 1).Column
' Get the column count
lColCount = Cells(1, Columns.Count).End(xlToLeft).Column
For a = lStartCol To lColCount Step lRowLen
Range(Cells(lRow, 1), Cells(lRow, lRowLen)).Value = Range(Cells(1, a), Cells(1, a + lRowLen)).Value
lRow = lRow + 1
Next
Application.ScreenUpdating = True
End Sub

VBA Copy Data goes wrong

Sub CopyTMR()
Dim sheet_number As Integer
Dim counter As Integer
Dim last_row As Integer
Dim wb As Workbook
Dim tmr As Worksheet
Set wb = ActiveWorkbook
Set tmr = wb.Sheets("Team Member Rules")
' Counting the sheets number
sheet_number = Worksheets.Count
'MsgBox sheet_number
'MsgBox "Before you continue, make sure all sheets has the Header at the first row"
' Clearing existing TMR in the sheet4
tmr.Select
ActiveSheet.UsedRange.Offset(1, 0).Clear
' If there more than 4 sheets, then we copy from the 5th until the last tab to 4th (TMR)
If sheet_number > 4 Then
' Loop to copy any sheet after TMR tab to the TMR Tab
For counter = 5 To sheet_number
' Selecting the corresponding tab to copy
Worksheets(counter).Select ActiveSheet.Range("A1:A1").Select
ActiveSheet.Range(Selection, Selection.End(xlToRight)).Select
ActiveSheet.Range(Selection, Selection.End(xlDown)).Select
' The Header is not copy
Selection.Offset(1, 0).Copy
' Moving back to TMR Tab to paste data
tmr.Select
' Selecting the last row of TMR bab before pasting data after it
last_row = ActiveSheet.Cells(Rows.Count, 2).End(xlUp).Row
ActiveSheet.Range("A" & last_row + 1).Select
ActiveSheet.Paste
Next
End If
' Best fit
tmr.Select
ActiveSheet.UsedRange.Select
Selection.AutoFilter
Application.CutCopyMode = False
Selection.ColumnWidth = 100
Selection.Columns.AutoFit
Selection.Rows.AutoFit
ActiveSheet.Range("A2").Select
ActiveWindow.FreezePanes = True End Sub
Hi All!
I am having some issue with the code above.
For some reason it works fine for a while and then stop with "run-time error 1004".
What I am trying to do is to copy the content "without the header" of all the tab after the 4th and paste them into the 4th tab.
Any tip or idea could help.
Thanks,
Try using .CurrentRegion with .Offset. A variant array will assist in avoiding the clipboard altogether.
Sub CopyTMR()
di w as long, arr as variant
for w = 5 to worksheets.count
with worksheets(w)
arr = .cells(1,1).currentregion.offset(1,0).value
end with
with worksheets(4)
.cells(.rows.count,"B").end(xlup).offset(1, -1).resize(ubound(arr, 1), ubound(arr, 2)) = arr
end with
next w
end sub

how do "relocate" cell values in a single column to a single row using Offset?

I am a bad VBA person. Please help me.
I want to relocate three values in a single column and put them in a single row using Offset. I need to flatten 3 rows of data into a single row of data.
Here is the code - it's very crude:
Sub Macro1()
'
' Macro1 Macro
'
'turn off display update
Application.ScreenUpdating = False
Dim CVFESUMMARY2(2000, 2000)
Dim MAXROW As Integer
Dim i As Integer
Dim r As Range
Dim x As Range
Dim y As Range
Dim z As Range
Set r = Range("BJ13:BJ512")
Set x = Range("BK13:BK512")
Set y = Range("BL13:BL512")
Set z = Range("BM13:BM512")
MAXROW = 300
'format "new" columns
Range("BK11").Select
ActiveCell.FormulaR1C1 = "NORM"
Range("BL11").Select
ActiveCell.FormulaR1C1 = "MIN"
Range("BM11").Select
ActiveCell.FormulaR1C1 = "MAX"
Columns("BJ:BM").Select
Selection.ColumnWidth = 12
'define the "COPY DATA FROM" starting cell location
Sheets("CVFESUMMARY2").Select
Range("BJ13").Select
'cycle through all of the rows in range r
For i = 1 To MAXROW
'copy "BJ13"
r.Select
Selection.Copy
'paste "value only" in column "BK13"
x.Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'copy "BJ13+1"
Set r = r.Offset(1, 0)
r.Select
Selection.Copy
'paste "value only" in column "BL13"
y.Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'copy "BJ13+2"
Set r = r.Offset(1, 0)
r.Select
Selection.Copy
'paste "value only" in column "BM13"
z.Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'move active cell to "BJ13+4"
Set r = r.Offset(2, 0)
Set x = x.Offset(4, 0)
Set y = y.Offset(4, 0)
Set z = z.Offset(4, 0)
Next i
'turn on display update
Application.ScreenUpdating = True
End Sub
This somewhat works but it is adding values in rows +2 and +3 that I don't want; I think the looping is wrong. Thanks in advance!
Before
After
Your desired output, can the results be compacted? (all empty rows removed, leaving a block of data) or is there information in the columns before that its linked with?
Removing the extra rows wouldn't be much extra work.
With the following code (which I think does what you want) the MaxRows value is incorrect. The way it works this should be a MaxRecords ie: the number of groups of data you.
Sub Transpose()
Dim Position As Range
Dim Source As Range
Dim MaxRow As Integer
Dim Index As Integer
' set column titles
Range("BK11").Value2 = "NORM"
Range("BL11").Value2 = "MIN"
Range("BM11").Value2 = "MAX"
' set the width
Range("BJ:BM").ColumnWidth = 12
MaxRow = 512 ' see note below
Set Position = Range("BJ13") ' define the start position
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'For Index = 1 To MaxRow
Do
' create a range that contains your first 3 values
Set Source = Range(Position, Position.Offset(RowOffset:=2))
' copy it
Source.Copy
' paste and transpose the values into the offset position
Position.Offset(ColumnOffset:=1).PasteSpecial xlPasteValues, SkipBlanks:=False, Transpose:=True
' OPTIONAL - Clear the contents of your source range
Source.ClearContents
' re-set the position ready for the next iteration
Set Position = Position.Offset(RowOffset:=4)
'Next
Loop While Position.Row < RowMax
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Note: I've not used Select and Selection as they confuse me! Using Range() makes it simpler to know where you are imo.
Update I've included one that also compacts the output
Sub TransposeCompact()
Dim Position As Range
Dim Source As Range
Dim Destination As Range
Dim MaxRow As Integer
Dim Index As Integer
' set column titles
Range("BK11").Value2 = "NORM"
Range("BL11").Value2 = "MIN"
Range("BM11").Value2 = "MAX"
' set the width
Range("BJ:BM").ColumnWidth = 12
MaxRow = 512 ' see note below
' define the start position
Set Position = Range("BJ13")
' define the first output position
Set Destination = Position.Offset(ColumnOffset:=1)
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'For Index = 1 To MaxRow
Do
' create a range that contains your first 3 values
Set Source = Range(Position, Position.Offset(RowOffset:=2))
' copy it
Source.Copy
' paste and transpose the values into the offset position
Destination.PasteSpecial xlPasteValues, SkipBlanks:=False, Transpose:=True
' OPTIONAL - Clear the contents of your source range
Source.ClearContents
' re-set the position ready for the next iteration
Set Position = Position.Offset(RowOffset:=4)
' increment the row on the output for the next iteration
Set Destination = Destination.Offset(RowOffset:=1)
'Next
Loop While Position.Row < RowMax
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Update 2
Your i variable used in the For Loop is not actually used, if your data is in rows 13 to 512 then the edits I've made to the code above should help.
The RowMax variable now will stop the macro when Position.Row goes beyond it.

Moving rows based on column values

I need to scan through all of the rows in the "Master" worksheet, find any cells with the value "Shipped" in the column "Status", then cut and paste each entire row to another sheet. The pasted rows need to be placed after the last row also.
I found this post (pasted below) which I slightly modified to delete rows successfully. But I can not figure out how to move rows instead. Should I try an entirely new method?
Sub DeleteRows()
Dim rng As Range
Dim counter As Long, numRows as long
With ActiveSheet
Set rng = Application.Intersect(.UsedRange, .Range("C:C"))
End With
numRows = rng.Rows.Count
For counter = numRows to 1 Step -1
If Not rng.Cells(counter) Like "AA*" Then
rng.Cells(counter).EntireRow.Delete
End If
Next
End Sub
I do not know VBA. I only kind of understand it because of my brief programming history. I hope that is okay and thank you for any help.
There's a couple of ways you could do it, can you add a filter to the top columns, filter by the value of 'Shipped'? Does it need to be copy and pasted into a new sheet?
It's not the most concise code but it might work
sub Shipped_filter()
dim wsSheet as worksheet
dim wsOutputSheet as worksheet
dim BottomRow as integer
Set wsSheet = worksheets("Sheet1") 'change to the sheet name
set wsOutputSheet = worksheets("Sheet2") 'change to the sheet name
'*****************************
'* Delete old data on Sheet2 *
'*****************************
wsoutputsheet.activate
Activesheet.cells.clearall
wsSheet.range("A1").select
selection.autofilter
BottomRow = wsSheet.range("A90000").end(xlup).row ' or another column you guarantee will always have a value
activesheet.range("$A$1:$Z$"&BottomRow).AutoFilter field:=1, Criteria1:="Shipped" ' change field to whatever column number Status is in
'********************************
'* Error trap in case no update *
'********************************
if activesheet.range("A90000").end(xlup).row = 1 then
msgbox("Nothing to ship")
exit sub
end if
wsSheet.range("A1:Z"&Bottomrow).select
selection.copy
wsOutputSheet.range("A1").select
selection.pastespecial Paste:=xlpastevalues
application.cutcopymode = false
msgbox('update complete')
end sub
I haven't tried it so it might need updating
I ended up combining the code I was originally using (found here) with an AutoFilter macro (found here). This is probably not the most efficient way but it works for now. If anyone knows how I can use only the For Loop or only the AutoFilter method that would be great. Here is my code. Any edits I should make?
Sub DeleteShipped()
Dim lastrow As Long
Dim rng As Range
Dim counter As Long, numRows As Long
With Sheets("Master")
'Check for any rows with shipped
If .Range("R:R").Find("Shipped", , xlValues, xlWhole, , , False) Is Nothing Then
MsgBox "No shipped plates found. ", , "No Rows Moved": Exit Sub
Else
Application.ScreenUpdating = False
'Copy and paste rows
lastrow = .Range("A" & Rows.Count).End(xlUp).Row
lastrow2 = Worksheets("ShippedBackup").Cells(Rows.Count, "A").End(xlUp).Row + 1
.Range("A1:U" & lastrow).AutoFilter field:=18, Criteria1:="Shipped"
.Range("A2:U" & lastrow).SpecialCells(xlCellTypeVisible).EntireRow.Copy
Sheets("ShippedBackup").Range("A" & lastrow2).PasteSpecial xlPasteValues, xlPasteSpecialOperationNone, False, False
.ShowAllData
'Delete rows with shipped status
Set rng = Application.Intersect(.UsedRange, .Range("R:R"))
numRows = rng.Rows.Count
For counter = numRows To 1 Step -1
If rng.Cells(counter) Like "Shipped" Then
rng.Cells(counter).EntireRow.Delete
End If
Next
MsgBox "All shipped records have been moved to the ""ShippedBackup"" worksheet.", , "Backup Complete"
End If
End With
Hope it helps someone!

Resources