Comparing Ranges and Copying - vba

I have been creating a small project that will allow a user to import and export data from work worksheet to another. I will attach screenshots to try and explain what i am trying to achieve.
I have the import section of my program working without fault and i can import all jobs that are of colour "Red" from my second worksheet. However once the row has been changed to colour "Green" in worksheet 1 it will then be exported back to sheet 2 and in turn will change the once "Red" job to "Green" effecting no other rows in sheet 2.
I have tried to implement the code as best as i could however i keep getting errors when comparing the my unique cell in both ranges.
As of just now when i run the code it will copy over the value 10 times and paste over all data from row "A4" to row "A14"
Worksheet One
Worksheet Two
Sub Button3_Click()
'#Author - Jason Hughes(AlmightyThud)
'#Version - 1.0
'#Date - 0/03/2015
'#Description - To Export all Completed Jobs to the "Daily Work Orders" Spreadsheet
'Once exported it will scan for the unique job number in the list and override the existing values
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = False
Application.EnableEvents = False
'Declare initial variables for this button'
Dim copyComplete As Boolean
copyComplete = False
Dim lR As Long
'----------------------------------'
'#When this code is uncommented it will delete all values in column A#'
Dim jobID As Range
Dim jobID2 As Range
Set jobID = Sheets("Daily Screen Update").Range("A4:A31")
Set jobID2 = Sheets("Daily Work Orders").Range("A4:A10000")
'----------------------------------'
'Activate the sheet you will be looping through'
ThisWorkbook.Sheets("Daily Screen Update").Activate
'Simple loop that will loop through all cells to check if the cell is green'
'If the cell is green then the loop will copy the cell, once copied the loop will check'
'the "Daily Work Orders" Sheet for a job ID with a similar ID and paste over it'
For Each greenjob In Range("A4:A31")
If greenjob.Cells.EntireRow.Interior.Color = RGB(146, 208, 80) Then
greenjob.Cells.EntireRow.Copy
For j = 4 To 31
For i = 4 To 10
If jobID.Cells(j, 1).Value = jobID2.Cells(i, 1).Value Then
Sheets("Daily Work Orders").Range("A" & j).PasteSpecial xlPasteAll
copyComplete = True
End If
Next i
Next j
End If
Next
'Make a check to ensure that the data has been copied
If copyComplete = True Then
MsgBox ("All completed jobs have been have been added to Daily Work Orders")
ElseIf copyComplete = False Then
MsgBox ("Nothing has been added to Daily Work Orders")
End If
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.CutCopyMode = False
End Sub

You have three For loops:
For Each greenjob In Range("A4:A31")
For j = 4 To 31
For i = 4 To 10
Loop 1 goes through all of the rows on Worksheet One and identifies ones that need to be copied, so Loop 2 going through all of those rows again each time Loop 1 catches one doesn't make sense.
Instead, just use the Job Number from the row identified in Loop 1 and compare it to the Job Numbers on Worksheet 1 using Loop 3.
So, remove For j = 4 To 31 and Next j, and replace
If jobID.Cells(j, 1).Value = jobID2.Cells(i, 1).Value Then
with
If greenjob.Value = jobID2.Cells(i, 1).Value Then
since greenjob is, conveniently, the cell in column A that contains the job number.

Related

My code is causing excel to run really slowly, I was wondering if it is because of unecessary loops

I am trying to create a table subset from a larger table. I'm pulling data from certain columns based on data that is filtered so everything up till the first blank row is reached is copied and pasted on a new sheet. Ideally I would like to create a specific type of formatted table, but for now I'm trying to copy the same format as the main table but excel seems to run very repetitively and I'm wondering if its because of redundancies.
Sub Lists()
Dim i As Integer 'define variables, i is a counter, K is a counter, c is an array to hold the values of column numbers to be coppied
'Dim k As Integer ****this variable is no longer needed with this new code of including the formating
'k = 2 'initialize value of counter k the value needed is 2 because the loop does not handle the first element, this is hard coded *** no longer needed with new formatting code
Dim c As Variant 'this variable holds the column numbers to be copied
c = Array(1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 24, 25)
Dim lNumElements As Long ' this varibale will hold the number of elements in array c
lNumElements = UBound(c) - LBound(c) + 1 'this is a formula for the number of elemnts in variable c
Dim NAME As String
NAME = InputBox("Please name the sheet") 'here the user can choose the name of the new worksheet that they wish to write the new table to
Dim ws As Worksheet 'declare a new worksheet to me made
Set ws = ThisWorkbook.Sheets.Add(After:= _
ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)) 'code used to add a new work sheet
ws.NAME = NAME 'use the name from the user input to rename the worksheet
Worksheets("Database").Select 'select the database worksheet
Worksheets("Database").Range("A1").Activate 'place the curser on the A1 range of database
'Sheets("Database").Columns(1).Copy Destination:=Sheets(ws.NAME).Columns(1) ' copy from database sheet and paste to new sheet hard coded for column 1 as the for loop did not like having column one in it as well *** no longer needed with new code
Sheets("Database").Columns(1).Copy 'copy the first column ( column A)
Worksheets(NAME).Select 'choose where you want to copy the data to on the new page
Worksheets(NAME).Range("A1").Activate 'activate the section you choose to copy to in the previous line of code
Selection.PasteSpecial Paste:=xlPasteValues 'paste the values of the code you wanted
Selection.PasteSpecial Paste:=xlPasteFormats 'keep the formating of the code you pasted
For i = 1 To lNumElements - 1 'this for loop will cycle through the number of elements in array c except for the first element
'Sheets("Database").Columns(c(i)).Copy Destination:=Sheets(ws.NAME).Columns(k) ' copy from database sheet and paste to new sheet excluding element 1). Paste information starting in column 2 (column 1 is hard coded above)
Worksheets("Database").Select
Columns(c(i)).Activate
Sheets("Database").Columns(c(i)).Copy
Worksheets(NAME).Select
Columns(i + 1).Activate
Selection.PasteSpecial Paste:=xlPasteValues
Selection.PasteSpecial Paste:=xlPasteFormats
k = k + 1
Next i
End Sub
Try this and see if it helps:
Disable Sheet Screen Updating
Application.ScreenUpdating = False
‘Place your macro code here
Application.ScreenUpdating = True
If your workbook has a lot of formulas or event macros that could slow it down significantly. Try the magic four:
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Application.Cursor = xlWait
' Your code
Application.Cursor = xlDefault
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
Try this instead of copy+paste:
Worksheets(NAME).Activate 'Just to watch it happen
For i = 1 To lNumElements - 1
Sheets(NAME).Columns(i + 1).Value = Sheets("Database").Columns(c(i)).Value
Sheets(NAME).Columns(i + 1).NumberFormat = Sheets("Database").Columns(c(i)).NumberFormat
k = k + 1
Next i

First VBA code... looking for feedback to make it faster

I wrote a small VBA macro to compare two worksheets and put unique values onto a new 3rd worksheet.
The code works, but every time I use if excel goes "not responding" and after 30-45sec comes back and everything worked as it should.
Can I make this faster and get rid of the "not responding" issue? is it just my computer not being fast enough?
I start with about 2500-2700 rows in each sheet I'm comparing.
Sub FilterNew()
Dim LastRow, x As Long
Sheets.Add(After:=Sheets(Sheets.Count)).Name = "New" 'Adds a new Sheet to store unique values
Sheets(1).Rows("1:1").Copy Sheets("New").Rows("1:1") 'Copies the header row to the new sheet
Sheets(1).Select
LastRow = Range("B1").End(xlDown).Row
Application.ScreenUpdating = False
For Each Cell In Range("B2:B" & LastRow)
x = 2 'This is for looking through rows of sheet2
Dim unique As Boolean: unique = True
Do
If Cell.Value = Sheets(2).Cells(x, "B").Value Then 'Test if cell matches any cell on Sheet2
unique = False 'If the cells match, then its not unique
Exit Do 'And no need to continue testing
End If
x = x + 1
Loop Until IsEmpty(Sheets(2).Cells(x, "B"))
If unique = True Then
Cell.EntireRow.Copy Sheets("New").Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
End If
Next
Application.ScreenUpdating = True
End Sub
This belongs in Code Review, but here is a link
http://www.excelitems.com/2010/12/optimize-vba-code-for-faster-macros.html
With your code your main issues are:
Selecting/Activating Sheets
Copy & pasting.
Fix those things and youll be set straight my friend :)
instead of a do...loop to find out duplicate, I would use range.find method:
set r = SHeets(2).range("b:b").find cell.value
if r is nothing then unique = true else unique = false
(quickly written and untested)
What about this (it's should help):
Sub FilterNew()
Dim Cel, Rng As Range
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Sheets.Add(After:=Sheets(Sheets.Count)).Name = "New" 'Adds a new Sheet to store unique values
Sheets(1).Rows("1:1").Copy Sheets("New").Rows("1:1") 'Copies the header row to the new sheet
Set Rng = Sheet(1).Range("B2:B" & Sheet(1).Range("B1").End(xlDown).Row)
For Each Cel In Rng
If Cel.Value <> Sheet(2).Cells(Cel.Row, 2).Value Then Cel.EntireRow.Copy Sheets("New").Range("A" & Rows.Count).End(xlUp).Offset(1, 0) ' The only issue I have with this is that this doesn't actually tell you if the value is unique, it just tells you ins not on the same rows of the first and second sheet - Is this alright with you?
Next
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub

If cell value matches a UserForm ComboBox column, then copy to sheet

What I am trying to do is :
loop through Column Q on Sheet "Global" starting at row 3
For every cell match value to UserForm ComboBox2 Column2, and the copy the entire row to the relevant sheet from userform2 coloum1.
loop though until last row. There could be several unique values in Column Q but will all be in the Userform2's Combobox2 columns.
I have no code as an example as I have no idea where to even begin!
This is my comboxbox, as is displays, on the backing of it each item have the below code, so a name, a code "2780" and a reference "BRREPAIRS".
.AddItem "Repairs"
ComboBox2.List(13, 1) = "2780"
ComboBox2.List(13, 2) = "BRRPEAIRS"
I need it to loop through everycell on the global sheet in column G, then match the cell value to the combobox list item from column 2. Once it has found a match it uses the code from column 1 ie "2780" to copy the entire row to the sheet matching the code in column 1.
Hopefully i have explained it a little better.
Private Sub CommandButton1_Click()
Dim findmatch As Object
Dim lastcell As Integer
Set findmatch = ThisWorkbook.Sheets("Global").Range("G:G").Find(What:=UserForm2.ComboBox2.column(1), LookIn:=xlValues)
If Not findmatch Is Nothing Then
lastcell = ThisWorkbook.Sheets(UserForm2.ComboBox2.Value).Cells(100000, 7).End(xlUp).row 'here find a way to locate last cell in sheet that has your name.. it keeps returning me 1 but other than that it works fine
ThisWorkbook.Sheets(UserForm2.ComboBox2.Value).Range(Cells(lastcell, 1), Cells(lastcell, 40)) = Range(Cells(findmatch.row, 1), Cells(findmatch.row, 40)).Value
Else
MsgBox "not found"
End If
End Sub
I have managed to get it to work with the following code below. It looks for the correct cell in the combobox. Then copies it to the correct sheet in the correct position.
The only problem is that it runs very slowley!! Can anyone suggest some way of speeding it up?
And the last question is, having error handling for if a sheet doesn't exists, it tell you to create the sheet, or even create the sheet for you??
I really appreciate all the help guys, have been bashing my head on the wall for days!!!
Dim i, lastD, lastG As Long
Dim j As Integer
With Application
.ScreenUpdating = False
.EnableEvents = False
.CutCopyMode = False
End With
' find last row
lastG = sheets("Global").Cells(Rows.Count, "Q").End(xlUp).row
For i = 3 To lastG
lookupVal = sheets("Global").Cells(i, "Q") ' value to find
' loop over values in "details"
For j = 0 To Me.ComboBox2.ListCount - 1
currVal = Me.ComboBox2.List(j, 2)
If lookupVal = currVal Then
sheets("Global").Cells(i, "Q").EntireRow.Copy
sheets(Me.ComboBox2.List(j, 1)).Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Insert shift:=xlDown
End If
Next j
Next i
With Application
.ScreenUpdating = True
.EnableEvents = True
.CutCopyMode = True
End With

get two cells to print from same page

I was wondering if its possible to have a macro that populates a page and prints it then goes to the next one from the column and so on.
The number would go on Sheet2, C2 and name on C4. this is a template so it should delete empty and then refresh the next number and name from the list in sheet1.
The only thing is could it be set so I can select the starting cell or does it have to print all in the row at once? Say I only wanted to print 20 today then another 50 tomorrow can that be done....
Its a lot of manual typing at the moment so any help would be great.
I have an example below (names changed) that the column could have up to 500 names that need to be printed to place in each folder. Below put the number in correctly I just cant work out how to also include the name from cell D2 in sheet1
Sub PrintLoop()
Dim c As Range, LR As Long
Application.ScreenUpdating = False
LR = Sheets("sheet1").Range("C" & Rows.Count).End(xlUp).Row
For Each c In Sheets("sheet1").Range("C2:C" & LR)
Sheets("sheet2").Range("C2").Value = c.Value
Sheets("sheet2").PrintPreview
Next c
Application.ScreenUpdating = True
End Sub
Select just the rows you want to print before running...
Sub PrintLoop()
Dim rw As Range
Application.ScreenUpdating = False
For Each rw In Selection.Rows
With Sheets("sheet2")
.Range("C2").Value = rw.EntireRow.Cells(3).Value
.Range("C4").Value = rw.EntireRow.Cells(4).Value
.PrintPreview
'.PrintOut From:=1, To:=1, Copies:=1
End With
Next rw
Application.ScreenUpdating = True
End Sub

Excel: Omitting rows/columns from VBA macro

With some help, I've put together two functions that will work in unison to first convert all of my data from the "text" format to a "number" format. After which it will set each column to a fixed number of characters.
The two sub-routines I'm using are listed below, but I can't figure out how to omit certain rows/columns for the respective functions.
When running the psAdd function, I want to omit the first 3 rows from the range, and for the FormatFixedNumber function I want to omit several columns. The problem with the latter is that I have 1000+ columns of data and a key header row containing a 1 or 0 that represents whether the column should be converted.
How could modify this code to skip the first 3 rows in the first sub, and several columns marked with a 0 in the second?
Sub psAdd()
Dim x As Range 'Just a blank cell for variable
Dim z As Range 'Selection to work with
Set z = Cells
Set x = Range("A65536").End(xlUp).Offset(1)
If x <> "" Then
Exit Sub
Else
x.Copy
z.PasteSpecial Paste:=xlPasteAll, Operation:=xlAdd
Application.CutCopyMode = False 'Kill copy mode
End If
x.ClearContents 'Back to normal
End Sub
Sub FormatFixedNumber()
Dim i As Long
Application.ScreenUpdating = False
For i = 1 To lastCol 'replace 10 by the index of the last column of your spreadsheet
With Columns(i)
.NumberFormat = String(.Cells(2, 1), "0") 'number length is in second row
End With
Next i
Application.ScreenUpdating = True
End Sub
1. First code
At the moment you are working on all the cells on a sheet with z. You can reduce this to the UsedRange - ignoring the first three rows by
forcing the UsedRange to update before using it (to avoid redunant cells)
testing if the z exceeds 3 rows
if so resize z by three rows using Offset and Resize
Sub psAdd()
Dim x As Range 'Just a blank cell for variable
Dim z As Range 'Selection to work with
ActiveSheet.UsedRange
Set z = ActiveSheet.UsedRange
If z.Rows.Count > 3 Then
Set z = z.Cells(1).Offset(3, 0).Resize(z.Rows.Count - 3, z.Columns.Count)
End If
'using Rows is better than hard-coding 65536 (bottom of xl03 - but not xl07-10)
Set x = Cells(Rows.Count,"A").End(xlUp).Offset(1)
If x <> "" Then
Exit Sub
Else
x.Copy
z.PasteSpecial Paste:=xlPasteAll, Operation:=xlAdd
Application.CutCopyMode = False 'Kill copy mode
End If
x.ClearContents 'Back to normal
End Sub
2. Second code
Run a simple test on each header cell to proceed if it doesn't equal 0. Assuming that the header cell is in row 1 then
Sub FormatFixedNumber()
Dim i As Long
Application.ScreenUpdating = False
For i = 1 To lastCol 'replace 10 by the index of the last column of your spreadsheet
If Cells(1, i) <> 0 Then
With Columns(i)
.NumberFormat = String(.Cells(2, 1), "0") 'number length is in second row
End With
End If
Next i
Application.ScreenUpdating = True
End Sub