Excel Shift Data down after Insert - vba

Hopefully someone can help me out here :(
In a sequence of workbooks (never a good idea :)), a user runs a macro which copies data from Workbook1 and inserts it using Insert Shift:=xlDown in Workbook2.
The problem is this: there is taller rows and a grouped textbox below the destination, and instead of shifting these down, the macro leaves the row size large and the textbox doesn't move.
I have set the textbox group to Move and size with cells and tried CopyOrigin:=xlFormatFromLeftOrAbove but it seems to make no difference.
Can somebody help please?
Thanks
EDIT
Here is the full code: (commented out original idea, added suggestion below)
Sub MakeQuote2()
Application.ScreenUpdating = False
Dim sourceRange As Range, loopRange As Range
Dim targetRange As Range
Dim FRow As Long
Dim m As Long
Dim p As Long
m = Sheets("Workbook1").Rows.Count
FRow = Sheets("Workbook1").Range("A" & m).End(xlUp).Row
Set sourceRange = ActiveSheet.Range("A9:E" & FRow)
Set targetRange = Workbooks.Open("C:\Users\j\Documents\Trial1.xltm").Sheets("Workbook2").Range("A4")
sourceRange.Copy
Sheets("Workbook2").Rows("4:4").EntireRow.Insert 'Select
'Selection.Insert 'Shift:=xlDown
p = FRow + 5
Sheets("Workbook2").Rows("4:" & p).Copy
Sheets("Workbook2").Rows("4:4").PasteSpecial xlPasteValues
Sheets("Workbook2").Range("A2").Select
Application.CutCopyMode = False
Workbooks("Copy.xlsm").Close SaveChanges:=False
Application.ScreenUpdating = True
End Sub
Thanks!

If you want below text boxes to move and size with the cells above then it does not suffice to use
.Insert Shift:=xlDown
Instead you need to use
.EntireRow.Insert

If you copy entire rows, paste will shift everything down. If your copy source has only several columns, the data shifts down but no rows format or objects shift with it. This is true in Excel, not only in VBA.
This code works for me (I changed some of the references to test it in my environment):
Set sourceRange = Sheets("Sheet2").Range("A9:E" & FRow).EntireRow '<-- Added EntireRow here.
Set targetRange = Sheets("Sheet1").Range("A4") '<-- This is never used.
sourceRange.Copy
Sheets("Sheet1").Rows("4:4").EntireRow.Insert
The only addition I made is to add EntireRow to the source range to copy. If you need only columns A:E I would suggest you insert blank rows according to FRow - 9, and then copy and paste A:E in the added rows.
Note that you are mixing up references Sheets("Workbook1"), ActiveSheet in your original code, and you never use targetRange.
Addition
As mentioned in the first note, to add blank rows before you paste only the relevant columns, you can use something like this code:
Sheets("Sheet1").Rows("4:" & FRow - 9 + 4).EntireRow.Insert
Set sourceRange = Sheets("Sheet2").Range("A9:E" & FRow)
Set targetRange = Sheets("Sheet1").Range("A4")
sourceRange.Copy
targetRange.PasteSpecial

Related

Macro VBA to Copy Column based on Header and Paste into another Sheet

Background: This is my first time dealing with macros. I will have two worksheets that I’ll be using. The first sheet, ‘Source’ will have data available. The second sheet, ‘Final’ will be blank and is going to be where the macro will be pasting the data I’d like it to collect from the ‘Source’ sheet.
* I want the macro to find the specified header in the ‘Source’ sheet, copy that cell containing the header all the way down to the last row of existing data (instead of the entire column), and paste it onto the ‘Final’ sheet in a specified column (A, B, C, etc.). *
The reason why I have to specify which headers to find is because the headers in the ‘Source’ sheet won’t always be in the same position, but the ‘Final’ sheet’s headers will always be in the same position – so I CAN’T just record macros copying column A in ‘Source’ sheet and pasting in column A in ‘Final’ sheet. Also, one day the ‘Source’ sheet may have 170 rows of data, and another day it may have 180 rows.
Although, it would probably be best to copy the entire column since one of the columns will have a few empty cells rather than to the last row of existing data. I’m assuming it would stop copying when it reaches the first empty cell in the column chosen which would leave out the remaining data after that empty cell in the column – correct me if I’m wrong. If copying the entire column is the best way, then, please provide that as part of the possible solution. I’ve attached an example of the before & after result I would like accomplished:
Example of Result
Find Header=X, copy entire column -> Paste into A1 in ‘Final’ sheet
Find Header=Y, copy entire column -> Paste into B1 in ‘Final’ sheet
Etc..
I’m sorry if my wording isn’t accurate – I tried to explain the best I could. It’d be awesome if someone could help me out on this! Thanks!
u can try with this. i think its clear and step-by-step. it can be very optimized, but to start with vba i think its better this way.
the name of the column must be the same in both sheets.
Sub teste()
Dim val
searchText = "TEXT TO SEARCH"
Sheets("sheet1").Select ' origin sheet
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
x = Selection.Columns.Count ' get number of columns
For i = 1 To x 'iterate trough origin columns
val = Cells(1, i).Value
If val = searchText Then
Cells(1, i).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Sheets("sheet2").Select ' destination sheet
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
y = Selection.Columns.Count ' get number of columns
For j = 1 To y 'iterate trough destination columns
If Cells(1, j).Value = searchText Then
Cells(1, j).Select
ActiveSheet.Paste
Exit Sub
End If
Next j
End If
Next i
End Sub
good luck
I modified an answer I gave to another user with similar problem for your case,
I use dictionary function in most of my data sheets so that I can shift columns around without breaking the code, the below code you can shift your columns around and it will still work
the only main restriction is
1. your header names must be unique
2. your header name of interest must be exactly the same.
i.e. your source header of interest is PETER then your Data table should have a header with PETER and it must be unique.
Sub RetrieveData()
Dim wb As Workbook
Dim ws_A As Worksheet
Dim ws_B As Worksheet
Dim HeaderRow_A As Long
Dim HeaderLastColumn_A As Long
Dim TableColStart_A As Long
Dim NameList_A As Object
Dim SourceDataStart As Long
Dim SourceLastRow As Long
Dim Source As Variant
Dim i As Long
Dim ws_B_lastCol As Long
Dim NextEntryline As Long
Dim SourceCol_A As Long
Set wb = ActiveWorkbook
Set ws_A = wb.Worksheets("Sheet A")
Set ws_B = wb.Worksheets("Sheet B")
Set NameList_A = CreateObject("Scripting.Dictionary")
With ws_A
SourceDataStart = 2
HeaderRow_A = 1 'set the header row in sheet A
TableColStart_A = 1 'Set start col in sheet A
HeaderLastColumn_A = .Cells(HeaderRow_A, Columns.Count).End(xlToLeft).Column 'Get number of NAMEs you have
For i = TableColStart_A To HeaderLastColumn_A
If Not NameList_A.Exists(UCase(.Cells(HeaderRow_A, i).Value)) Then 'check if the name exists in the dictionary
NameList_A.Add UCase(.Cells(HeaderRow_A, i).Value), i 'if does not exist record name as KEY and Column number as value in dictionary
End If
Next i
End With
With ws_B 'worksheet you want to paste data into
ws_B_lastCol = .Cells(HeaderRow_A, Columns.Count).End(xlToLeft).Column ' Get number of DATA you have in sheet B
For i = 1 To ws_B_lastCol 'for each data
SourceCol_A = NameList_A(UCase(.Cells(1, i).Value)) 'get the column where the name is in Sheet A from the dictionaary
If SourceCol_A <> 0 Then 'if 0 means the name doesnt exists
SourceLastRow = ws_A.Cells(Rows.Count, SourceCol_A).End(xlUp).Row
Set Source = ws_A.Range(ws_A.Cells(SourceDataStart, SourceCol_A), ws_A.Cells(SourceLastRow, SourceCol_A))
NextEntryline = .Cells(Rows.Count, i).End(xlUp).Row + 1 'get the next entry line of the particular name in sheet A
.Range(.Cells(NextEntryline, i), _
.Cells(NextEntryline, i)) _
.Resize(Source.Rows.Count, Source.Columns.Count).Cells.Value = Source.Cells.Value
End If
Next i
End With
End Sub

Why does my VBA loop paste incorrect values?

I have created a loop where data is copied from a worksheet and pasted into another, however I am having problems with the paste function – sometimes the wrong data gets pasted, seemingly randomly. My current code is:
Sub ACCPR_LOOP()
Dim wsACC_PR As Worksheet
Set wsACC_PR = ThisWorkbook.Sheets("ACC PR")
Dim wsPR_CALC As Worksheet
Set wsPR_CALC = ThisWorkbook.Sheets("PR - CALC")
Dim MyRange As Range
Dim MyCell As Range
Set MyRange = Range("A2:A145")
Application.ScreenUpdating = False
Columns("B:C").ClearContents
For Each MyCell In MyRange
MyCell.Copy
wsPR_CALC.Range("A1").PasteSpecial xlPasteValues
Application.CutCopyMode = False
wsPR_CALC.Range("B226,B228").Copy
MyCell.Offset(0, 1).PasteSpecial Paste:=xlPasteValuesAndNumberFormats, Transpose:=True
Next MyCell
End Sub
What the code is doing is in Col A are a bunch of dates, it copies the date in A, then pastes it into another worksheet to update a drop-down date selector and change the data. Two of the cells are then copied and pasted back into the original worksheet with an offset of 1 column. For some reason sometimes, the data from the previous date in A is pasted. For example, the date in A17 is copied and pasted into the date selector, the correct data is then pasted into B17, but on the next step, the data relating to A17 is pasted into the next row down at B18.
If a repeat the line:
MyCell.Offset(0, 1).PasteSpecial Paste:=xlPasteValuesAndNumberFormats, Transpose:=True
the code works but this seems rather inefficient. Any ideas what’s going on in my code and how I can fix it?
In the Set MyRange = Range("A2:A145") you should declare the corresponding worksheet as well. E.g.:
Set MyRange = Worksheets("MyNameIsWhat").Range("A2:A145")
Otherwise, it would take the ActiveWorksheet and the MyRange would be assigned to it.
The same goes to Columns("B:C").ClearContents.
It should be Worksheets("TsakaTsakaSlimShaddy").Columns("B:C").ClearConents
I always try to avoid the copy/paste function in VBA. It's processor intensive and functions ... arcanely.
Try this instead:
For Each MyCell In MyRange
wsPR_CALC.Range("A1").Value = MyCell.Value
Application.Calculate
MyCell.Offset(0, 1).Value = wsPR_CALC.Range("B226,B228").Value
Next MyCell
You'll lose the number formatting, but there are other ways of doing that.
I also added an Application.Calculate line, because it looks like you're copying from a formula in the second step, and it's good to make sure that value gets updated. You can also try Application.CalculateFull if plain .Calculate isn't cutting it.
Also, to echo Vit, if you're working with multiple sheets, declaring your sheet as often as possible will help as well.

Error by copy pasting ranged due to merged cells

SOLVED, SEE CODE BELOW
I'm working on a code for filtering data and pasting the filtered data to the "destination" sheet.
In the "review" sheet there is a long list with data that can be subdivided in certain categories. In cell F9 off the coversheet I can select a category.
After pressing a button the data in the "review" sheet needs to be filtered and the data that is left after filtering should be pasted in the "destination" sheet. the "destination" sheet is a blank new sheet.
The filtering part works, however the copy paste part is giving some errors. Because the "review" sheet has some merged cells in it. I am able to paste the formatting and the columnwidths, but the values give an error due to merged cells. Is there some way to work around this??
In addition to this, when pasting the formatting, this is pasted to the same number of rows as in the "review" sheet before filtering. I want the formatting to be applicable on only the numer of rows left after filtering.
I hope someone can help me out.
See my source code below:
Dim wksCVP As Worksheet
Dim wksReview As Worksheet
Dim wksNew As Worksheet
Set wksReview = Worksheets("REVIEW")
Set wksCVP = Worksheets("COVER PAGE")
Set wksNew = ThisWorkbook.Worksheets.Add
wksReview.Cells.Copy wksNew.Cells
wksNew.Cells.UnMerge
Dim LastRow As Long
With wksNew
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Select Case wksCVP.Range("F9").Value
Case "Instrumentation"
kolom = "J"
Case "Equipment"
kolom = "K"
Case "Design / Fabrication"
kolom = "L"
Case "Inspection & Testing"
kolom = "M"
Case "General / Other"
kolom = "N"
End Select
If wksCVP.Range("F9").Value <> "" Then
For i = 5 To LastRow
If wksNew.Range(kolom & i).Value <> "X" Then
wksNew.Rows(i).EntireRow.Hidden = True
End If
Next i
End If
wksNew.Activate
ActiveSheet.Range("A5", "Z" & LastRow + 1).SpecialCells(xlCellTypeVisible).Copy
With Sheets("DESTINATION").Range("A1")
.PasteSpecial Paste:=xlPasteAll
End With
wksNew.delete
For the Formats and the ColumnWidths being in a merged cell, which is only partially copied, the easiest way is to add a new worksheet, to copy the initial values there and to unmerge it. Then do something like this:
Option Explicit
Sub TestMe()
Dim wksTheNew As Worksheet
Dim wksReview As Worksheet
Dim wksDestination As Worksheet
Set wksReview = Worksheets("Review")
Set wksDestination = Worksheets("Destination")
Set wksTheNew = ThisWorkbook.Worksheets.Add
wksReview.Cells.Copy wksTheNew.Cells
wksTheNew.Cells.UnMerge
'now copy the formats and the values from wksTheNew
'it will not give an error, because it is unmerged
Application.DisplayAlerts = False
wksTheNew.Delete
Application.DisplayAlerts = True
End Sub
Once you are ready with your actions, you may simply delete the new worksheet.
Just change your sequence:
With Sheets("DESTINATION").Range("A1")
.PasteSpecial Paste:=xlPasteValues
.PasteSpecial Paste:=xlPasteFormats
.PasteSpecial Paste:=xlPasteColumnWidths
End With
Pasting values first shouldn't trigger an error.

Select Method of Worksheet Class Failed

I have this sub in Excel 2010 which is supposed to filter through all the cells in a sheet until it finds a match to Proj No, then paste a field from this row into another field.
When I try to run the sub, it gives me an error 1004: Select Method of Worksheet Class Failed. I've marked the line where this occurs. Any assistance would be greatly appreciated.
Option Explicit
Private Sub btnNext_Click()
Dim ProjNo As String
Dim Col As String
Dim Row As String
Dim cell As Range
Unload Dialog
formWait.Show
Sheets("Sheet7").Activate
ProjNo = Worksheets("Sheet1").Range("D6").Value
Col = Cells(Rows.Count, "A").End(xlUp).Row
For Each cell In Range("A2:A" & Col) 
If cell.Value = ProjNo Then
Row = Row & cell.Row
End If
Next cell
Workbooks("Form.xlsm").Sheets("Sheet7").Range("Row, 6").Copy Destination:=Sheets("Sheet1").Range("19, 5") ‘Error
Unload formWait
End Sub
I don't know what GWP is, but I think you want to use ProjNo there. The Range property doesn't accept an argument like that. Unless you have a named range of "Row,6" which you don't because it's not a legal name, you have to supply Range with a valid range reference, like A6 or D2:D12, for example.
Also, you can't concatenate rows and use them in a Range reference to get a larger range. You would have to copy each row inside the loop, union the ranges as you go, or better yet, filter on the value that you want and copy the visible rows.
Try this:
Private Sub btnNext_Click()
With ThisWorkbook.Worksheets("Sheet7")
'filter for the project id
.Range("A1", .Cells(.Rows.Count, 1).End(xlUp)).Resize(, 6).AutoFilter 1, "=" & .Range("D6").Value
'copy the visible rows
.Range("F2", .Cells(.Rows.Count, 6).End(xlUp)).SpecialCells(xlCellTypeVisible).Copy _
ThisWorkbook.Worksheets("Sheet1").Cells(19, 5)
'get rid of the filter
.AutoFilterMode = False
End With
End Sub
There are a few confusing items in your code above, so I wanted to place them long-form here. Let's get started:
Dim Col As String
Dim Row As String
It looks like your design expects these to be of type Long rather than type String. Even if these variables were meant to be strings, I would recommend adjusting their names -- when your fellow developer attempts to review your design, he or she is likely to see names like "Col" or "Row" and think "these are numbers". Easy fix:
Dim Col As Long, Row As Long
The next issue comes up here:
Col = Cells(Rows.Count, "A").End(xlUp).Row
The structure above is a common method for identifying the last ROW, not column. (It also appears that you have switched the "A" and number, which is another easy fix). While it is perfectly acceptable syntactically to name the variable for last row "Col", human users are likely to find this confusing. Identifying the last row (and the last col, which you use in the For Each loop), as explained in fantastic detail here, would be better handled like this:
Dim SheetSeven As Worksheet, SheetOne As Worksheet
Dim LastRow As Long, LastCol As Long
Set SheetSeven = ThisWorkbook.Worksheets("Sheet7")
Set SheetOne = ThisWorkbook.Worksheets("Sheet1")
With SheetSeven
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
LastCol = .Range("A" & .Columns.Count).End(xlToLeft).Column
End With
This should make your For Each loop look like this:
With SheetSeven
For Each cell in .Range("A2:A" & LastCol)
'... do you comparison and row incrementing here
Next cell
End With
Once you've identified your sheet as a variable, the Range.Copy action should be much easier as well:
With SheetSeven
.Range(.Cells(Row, 6)).Copy _
Destination:=SheetOne.Range(SheetOne.Cells(19, 5))
End With
Also one other thing you may wish to check is the status of Application.ScreenUpdating.
With the release of Office 2013 and later, a SDI (Single Document Interface) was introduced. If Application.ScreenUpdating is False and the workbook is not active, the implied call to Workbook.Activate will fail. Check the status of ScreenUpdating and set it to True if needed. You can set it back to False after the first Activate call for that workbook is made.
See this article:
https://support.microsoft.com/en-us/help/3083825/excel-workbook-is-not-activated-when-you-run-a-macro-that-calls-the-wo
In my case the error came as the sheet was hidden.
so I check if I am not working with the hidden sheet. Or you need to unhide the sheet before you try to select or activate sheet.
For Each sh In ThisWorkbook.Sheets
If Left(sh.Name, 8) <> "Template" Then
sh.Select
sh.Range("A1").Select
End If
Next

Copy multiple rows from one worksheet to another worksheet using macro/vba

I've looked around the forum and played with various options but not found a clear match for my problem:
My task is to copy data from a worksheet (called “workorders”) to a second worksheet (called “Assignments”). The data to be copied is from the “workorders” worksheet starting at cell range “E2, P2:S2”; and also copied from each row (same range) until column “P” is empty – (the number of rows to be copied can vary each time we need to run this macro so we can’t select a standard range) . Then pasted into the “Assignments” worksheet, starting at cell “A4”. I’ve used the forum so far to successfully copy a single row of date (from row 2) – I admit that’s the easy part, and I’ve used various versions of code to achieve this.
I’ve also tried some code (which I found via watching a youtube clip and modifying http://www.youtube.com/watch?v=PyNWL0DXXtQ )to allow me to run a loop which repeats the copy process for each required row in the “workorders” worksheet and then pastes the data into the “assignments” worksheet- but this is where I am not getting it right, I think I’m along the right lines and think I’m not far off but any help would be very useful.
Code examples below (first 2 only copy first row, 3rd example is where I’ve tried to loop and copy multiple rows:
Sub CopyTest1()
' CopyTest1 Macro
'copy data from workorders sheet
'Worksheets("workorders").Range("E2,P2,Q2,R2,S2").Copy
Worksheets("workorders").Range("E2, P2:S2").Copy
'paste data to assignments sheet
'sheets("assigments dc").Range("A4").Paste
Sheets("Assigments DC").Select
Range("A4").Select
ActiveSheet.Paste
Application.CutCopyMode = False
End Sub
Sub CopyTest2()
Sheets("workorders").Range("e2,p2,q2,r2,s2").Copy Sheets("assigments dc").Range("a4")
End Sub
Sub CopyTest3()
Dim xrow As Long
'Dim xrow As String
xrow = 2
Worksheets("workorders").Select
Dim lastrow As Long
lastrow = Cells(Rows.Count, 16).End(xlUp).Row
Do Until xrow = lastrow + 1
ActiveSheet.Cells(xrow, 16).Select
If ActiveCell.Text = Not Null Then
'Range("E2,P2,Q2,R2,S2").Copy
'Selection = Range("E2,P2,Q2,R2,S2").Copy
'Cells(xrow, 5).Copy
Cells(xrow, 5).Copy
Sheets("Assigments DC").Select
Range("A4").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Sheets("workorders").Select
End If
xrow = xrow + 1
Loop
End Sub
Try this:
Sub LoopCopy()
Dim shWO As Worksheet, shAss As Worksheet
Dim WOLastRow As Long, Iter As Long
Dim RngToCopy As Range, RngToPaste As Range
With ThisWorkbook
Set shWO = .Sheets("Workorders") 'Modify as necessary.
Set shAss = .Sheets("Assignments") 'Modify as necessary.
End With
'Get the row index of the last populated row in column P.
'Change accordingly if you want to use another column as basis.
'Two versions of getting the last row are provided.
WOLastRow = shWO.Range("P2").End(xlDown).Row
'WOLastRow = shWO.Range("P" & Rows.Count).End(xlUp).Row
For Iter = 2 to WOLastRow
Set RngToPaste = shAss.Range("A" & (Iter + 2))
With shWO
Set RngToCopy = Union(.Range("E" & Iter), .Range("P" & Iter & ":S" & Iter))
RngToCopy.Copy RngToPaste
End With
Next Iter
End Sub
Read the comments first and test.
Let us know if this helps.
From what I see, you are only copying the cell in Column E. You could correct this by replacing Cells(xrow, 5).Copy with
Union(Sheets("workorders").Cells(xrow,5),Sheets("workorders").Range(Cells(xrow,"P"),Cells(xrow,"S")).Copy
However, using Select and Copy are not ideal. Instead, you can assign the value of the range directly:
Sheets("Assignments DC").Range("A4").Value = Union(Sheets("workorders").Cells(xrow,5),Sheets("workorders").Range(Cells(xrow,"P"),Cells(xrow,"S")).Value
More info on the Union method and why using Select is bad.
Is it even possible to run a line like this?
Worksheets("workorders").Range("E2, P2:S2").Copy
Each time I try different ways to copy/select a range which contains in my case, A3 and the range A34:C40 ("A3, A34:C40").Copy i get an error saying theres to many parameters.. Could this be because I'm running excel 2007?
Any tips or help would be greatly apreciated! :)