Cut and Paste Blocks of Data underneath first block using VBA - excel

I have been trying to come up with/find a VBA code that copies blocks of data under my first block. Each block is 19 columns followed by a blank. The number of rows per block can vary.
See my screenshot below:
Therefore, I would like all my data continuous in the first columns A:S. Any help is highly appreciated.
I found the following code online, but this only pastes everything into the first column
Sub Column()
Dim iLastcol As Long
Dim iLastRow As Long
Dim jLastrow As Long
Dim ColNdx As Long
Dim ws As Worksheet
Dim myRng As Range
Dim ExcludeBlanks As Boolean
Dim mycell As Range
ExcludeBlanks = (MsgBox("Exclude Blanks", vbYesNo) = vbYes)
Set ws = ActiveSheet
iLastcol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
On Error Resume Next
Application.DisplayAlerts = False
Worksheets("Alldata").Delete
Application.DisplayAlerts = True
Sheets.Add.Name = "Alldata"
For ColNdx = 1 To iLastcol
iLastRow = ws.Cells(ws.Rows.Count, ColNdx).End(xlUp).Row
Set myRng = ws.Range(ws.Cells(1, ColNdx), _
ws.Cells(iLastRow, ColNdx))
If ExcludeBlanks Then
For Each mycell In myRng
If mycell.Value <> "" Then
jLastrow = Sheets("Alldata").Cells(Rows.Count, 1) _
.End(xlUp).Row
mycell.Copy
Sheets("Alldata").Cells(jLastrow + 1, 1) _
.PasteSpecial xlPasteValues
End If
Next mycell
Else
myRng.Copy
jLastrow = Sheets("Alldata").Cells(Rows.Count, 1) _
.End(xlUp).Row
mycell.Copy
Sheets("Alldata").Cells(jLastrow + 1, 1) _
.PasteSpecial xlPasteValues
End If
Next
Sheets("Alldata").Rows("1:1").EntireRow.Delete
ws.Activate
End Sub

Basic approach:
Sub Tester()
Dim c As Range, addr
Set c = ActiveSheet.Range("T1")
Do
Set c = c.End(xlToRight)
If c.Column = Columns.Count Then Exit Do
addr = c.Address 'strire the address since Cut will move c
c.CurrentRegion.Cut c.Parent.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
Set c = ActiveSheet.Range(addr) '<< reset c
Loop
End Sub

This is a little more basic than #TimWilliams
With ThisWorkbook.Sheets("Alldata")
Dim lRow As Long, lCol As Long, cpyrng As Range
lCol = Cells(1, Columns.Count).End(xlToLeft).Column
For i = 21 To lCol Step 20
If .Cells(1, i).Value <> "" And .Cells(1, i).Offset(, -1).Value = "" Then
lRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set cpyrng = .Cells(1, i).CurrentRegion
cpyrng.Cut
Sheets("Sheet2").Cells(lRow, 1).Offset(2).Insert Shift:=xlDown
End If
Next i
End With

Related

Insert Row when 2 conditions are met

I have created below code which works like IF Col"B" any cell <> "" And Col"L" any cell = "Leop" then add row below to the active cell.
I mean I'm trying to achieve is to insert single row after certain row which contain in column B any value, and if column L in same row contains value = "Leop". Then add the row after that certain row.
But an error is appear. Compile Error: Invalid use of property on xlDown
Your help will be appreciated to fix it.
From this:
to this:
Sub firstcondition()
Dim ws As Worksheet
Dim LRow As Long
Dim rng As Range
Dim rng2 As Range
Dim i As Long
Dim p As Long
Dim dat As Variant
Dim datt As Variant
Dim IRow As Long
Set ws = Thisworkbooks.Sheets("Sheet2")
With ws
LRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng = .Range("B2:B" & LRow)
Set rng2 = .Range("L2:L" & LRow)
dat = rng
datt = rng2
IRow = Selection.Row
For i = LBound(dat, 1) To UBound(dat, 1)
For p = LBound(datt, 1) To UBound(datt, 1)
If dat(i, 1) <> "" And datt(p, 1) = "Leop" Then
Rows(IRow + 1).Select
Selection.Insert Shift: xlDown
End If
End Sub
It will be like in formula:
IF(AND(B2<>"",L2="Leop"),"InsertRowBelow to Row 2 If condition is met","")
and will drag it down to the lastRow.
Thisworkbooks.Sheets("Sheet2") should be Thisworkbook.Sheets("Sheet2") and missing = in Selection.Insert Shift:= xlDown
Inserting or deleting rows will change the last row number so start at the bottom and work upwards.
Option Explicit
Sub firstcondition()
Dim ws As Worksheet, LRow As Long, r As Long
Dim n As Long
Set ws = ThisWorkbook.Sheets("Sheet2")
With ws
LRow = .Range("B" & .Rows.Count).End(xlUp).Row
For r = LRow To 2 Step -1
If .Cells(r, "B") <> "" And .Cells(r, "L") = "Leop" Then
.Rows(r + 1).Insert shift:=xlDown
n = n + 1
End If
Next
End With
MsgBox n & " rows inserted", vbInformation
End Sub
Try this with autofilter, you dont have to loop through each row. So it will work faster for larger data.
Option Explicit
Sub firstcondition()
Dim ws As Worksheet
Dim LRow As Long, cl As Range
Set ws = ThisWorkbook.Sheets("Sheet2")
LRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
ws.Range("L1:L" & LRow).AutoFilter 1, "Leop"
For Each cl In ws.Range("_FilterDatabase").SpecialCells(12).Cells
If ws.Range("B" & cl.Row) <> "" Then
cl.Offset(1).EntireRow.Insert Shift:=xlDown
End If
Next
ws.AutoFilterMode = False
End Sub

How to copy values from sheets to another sheet?

I'm trying to merge several sheets into one.
Configuration
DataSheet1 : First sheet
DataSheet2 : Second sheet
ConsolidatedSheet : Consolidated sheet
Code
Set consolidatedSheet = Worksheets("ConsolidatedSheet")
consolidatedSheet.Activate
startRow = 2
startCol = 1
Worksheets("DataSheet1").Activate
lastRow = Cells(Rows.Count, startCol).End(xlUp).row
lastCol = Cells(startRow, Columns.Count).End(xlToLeft).Column
Range(Cells(startRow, startCol), Cells(lastRow, lastCol)).Copy _
consolidatedSheet.Range("A" & consolidatedSheet.Cells(Rows.Count, 1).End(xlUp).row + 1)
Worksheets("DataSheet2").Activate
lastRow = Cells(Rows.Count, startCol).End(xlUp).row
lastCol = Cells(startRow, Columns.Count).End(xlToLeft).Column
Range(Cells(startRow, startCol), Cells(lastRow, lastCol)).Copy _
consolidatedSheet.Range("A" & consolidatedSheet.Cells(Rows.Count, 1).End(xlUp).row + 1)
Issue
Two arrays are created in the consolidated sheet. It means I can't sort on the consolidated sheet.
How do I copy data as values instead of arrays?
Sub consSheets()
Dim ws As Worksheet
With Worksheets("ConsolidatedSheet")
.Cells.Delete ' clear the assignment sheet first
For Each ws In Sheets(Array("DataSheet1", "DataSheet2"))
ws.Cells(2, 1).CurrentArray.Copy
.Cells(.Rows.Count, 1).End(xlUp).Offset(1).PasteSpecial Paste:=xlPasteValues
Next ws
End With
Application.CutCopyMode = False ' "clears" the clipboard
End Sub
Edit2: (not copy headers from DataSheet1 and DataSheet2 and keep existing header in ConsolidatedSheet)
Sub consSheets()
Dim ws As Worksheet
With Worksheets("ConsolidatedSheet")
.Rows("2:" & .UsedRange.Row + .UsedRange.Rows.Count).Delete ' clear (without header in Row 1) the assignment sheet first
For Each ws In Sheets(Array("DataSheet1", "DataSheet2"))
Set Rng = ws.Cells(2, 1).CurrentRegion
Set Rng = Intersect(Rng, Rng.Offset(1)) ' eliminate headers
If Not Rng Is Nothing Then
Rng.Copy
.Cells(.Rows.Count, 1).End(xlUp).Offset(1).PasteSpecial Paste:=xlPasteValues
End If
Next ws
End With
Application.CutCopyMode = False ' "clears" the clipboard
End Sub
I'm not sure what you mean by it creating arrays, and I don't think that code is actually the code using as it's not doing what you describe.
But here's something that does what your intending.
Option Explicit
Sub Test()
Dim cSht As Worksheet
Set cSht = Worksheets("ConsolidatedSheet")
Dim StartRow As Integer, StartCol As Integer
StartRow = 1
StartCol = 1
'Split out to a sub and don't need to repeat self
Call ConsolidateData(cSht, "DataSheet1", StartRow, StartCol, True)
Call ConsolidateData(cSht, "DataSheet2", StartRow, StartCol)
End Sub
Private Sub ConsolidateData(cSht As Worksheet, FromSheet As String, StartRow As Integer, StartCol As Integer, Optional IncludeHeader As Boolean)
Dim FromRow As Integer
If IncludeHeader Then
FromRow = StartRow
Else
FromRow = StartRow + 1
End If
With Worksheets(FromSheet)
lastrow = .Cells(.Rows.Count, StartCol).End(xlUp).Row
lastcol = .Cells(StartRow, .Columns.Count).End(xlToLeft).Column
'Just transfering value is faster then copy, but doesn't bring formatting
cSht.Cells(cSht.Rows.Count, 1).End(xlUp).Resize(lastrow - FromRow, lastcol - StartCol).Value2 = .Range(.Cells(FromRow, StartCol), .Cells(lastrow, lastcol)).Value2
End With
End Sub

Error 438"Object Doesn't Support This Property or Method"

Related to Excel VBA - I have a large dataset and would like to split it by Ratings. For a small dataset the code works perfectly, but for a large dataset (11,000 rows & 20 columns), it loops and either get "Restart Excel program" or a 438 error. Need some help to optimize/correct the code. Using Excel 2013
I tried Cut/paste instead of copy/paste - it does not work
Private Sub SplitData_Click()
a = Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To a
If Sheets("Sheet1").Cells(i, 2).Value = "AAA" Then
Sheets("Sheet1").Rows(i).Cut
Sheets("Sheet2").Activate
b = Sheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row
Sheets("Sheet2").Cells(b + 1, 1).Select
ActiveSheet.Paste
End If
If Sheets("Sheet1").Cells(i, 2).Value = "BBB" Then
Sheets("Sheet1").Rows(i).Cut
Sheets("Sheet3").Activate
c = Sheets("Sheet3").Cells(Rows.Count, 1).End(xlUp).Row
Sheets("Sheet3").Cells(c + 1, 1).Select
ActiveSheet.Paste
End If
If Sheets("Sheet1").Cells(i, 2).Value = "CCC" Then
Sheets("Sheet1").Rows(i).Cut
Sheets("Sheet4").Activate
d = Sheets("Sheet4").Cells(Rows.Count, 1).End(xlUp).Row
Sheets("Sheet4").Cells(d + 1, 1).Select
ActiveSheet.Paste
End If
Sheets("Sheet1").Activate
Next
Application.CutCopyMode = False
End Sub
I want to split the large data set into different groups (Sheets) based on the value - AAA, BBB or CCC. I have 10 such value flags.
Another approach:
Private Sub SplitData_Click()
Dim a As Long, i As Long, sht As Worksheet, sDest As String
Set sht = Sheets("Sheet1")
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
a = sht.Cells(sht.Rows.Count, 1).End(xlUp).Row
For i = a To 2 Step -1 'work from bottom up
sDest = ""
'need to cut this row?
Select Case sht.Cells(i, 2).Value
Case "AAA": sDest = "Sheet2"
Case "BBB": sDest = "Sheet3"
Case "CCC": sDest = "Sheet4"
End Select
'cut row to relevant sheet
If Len(sDest) > 0 Then
sht.Rows(i).Cut Sheets(sDest).Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
End If
Next i
Application.CutCopyMode = False
Application.Calculation = xlCalculationAutomatic
End Sub
NOTE: locating the "cut to" cell using xlUp relies on every previous row in the destination sheet having a value in ColA - if any are empty then rows could get overwritten by the next pasted row.
Try this. This should be faster as this doesn't involve ANY looping.
Logic
Use Autofilter to Copy the rows across in one go
Clear rows after copying
Delete blank rows in one go using Autofilter
Code
Dim wsInput As Worksheet
Sub SplitData_Click()
Dim wsOutputA As Worksheet
Dim wsOutputB As Worksheet
Dim wsOutputC As Worksheet
Set wsInput = ThisWorkbook.Sheets("Sheet1")
Set wsOutputA = ThisWorkbook.Sheets("Sheet2")
Set wsOutputB = ThisWorkbook.Sheets("Sheet3")
Set wsOutputC = ThisWorkbook.Sheets("Sheet4")
Dim lrow As Long
Dim rng As Range
With wsInput
.AutoFilterMode = False
lrow = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng = .Range("A1:A" & lrow)
'~~> Filter on AAA
HandleIt "AAA", rng, wsOutputA
'~~> Filter on BBB
HandleIt "BBB", rng, wsOutputB
'~~> Filter on CCC
HandleIt "CCC", rng, wsOutputC
'~~> Filter on blanks
With rng
.AutoFilter Field:=1, Criteria1:="="
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
.AutoFilterMode = False
End With
End Sub
Private Sub HandleIt(AFCrit As String, r As Range, wks As Worksheet)
Dim OutputRow As Long
Dim filteredRange As Range
With r
.AutoFilter Field:=1, Criteria1:=AFCrit
Set filteredRange = .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow
End With
If Not filteredRange Is Nothing Then
With wks
OutputRow = .Range("A" & .Rows.Count).End(xlUp).Row + 1
filteredRange.Copy .Rows(OutputRow)
filteredRange.ClearContents
End With
End If
wsInput.ShowAllData
End Sub
In Action
Note: The above code took 4 seconds on 21k rows x 31 columns data
Please see How to avoid using Select in Excel VBA.
Option Explicit
Private Sub SplitData_Click()
Dim i As Long
With Worksheets("Sheet1")
For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
Select Case .Cells(i, 2).Value
Case "AAA"
MoveToEndOf .Rows(i), Worksheets("Sheet2")
Case "BBB"
MoveToEndOf .Rows(i), Worksheets("Sheet3")
Case "CCC"
MoveToEndOf .Rows(i), Worksheets("Sheet4")
End Select
Next
End With
End Sub
Private Sub MoveToEndOf(ByVal what As Range, ByVal where As Worksheet)
what.Cut where.Cells(where.Rows.Count, 1).End(xlUp).Offset(1, 0)
End Sub
Here is an option without using copy/paste
Private Sub SplitData_Click()
Dim a As Long
Dim b As Long
Dim c As Long
Dim d As Long
Dim i As Long
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Dim ws4 As Worksheet
Set ws1 = ThisWorkbook.Sheets("Sheet1")
Set ws2 = ThisWorkbook.Sheets("Sheet2")
Set ws3 = ThisWorkbook.Sheets("Sheet3")
Set ws4 = ThisWorkbook.Sheets("Sheet4")
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
a = ws1.Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To a
If ws1.Cells(i, 2).Value = "AAA" Then
b = ws2.Cells(Rows.Count, 1).End(xlUp).Row + 1
ws2.Rows(b).Value = ws1.Rows(i).Value
End If
If ws1.Cells(i, 2).Value = "BBB" Then
c = Sheets("Sheet3").Cells(Rows.Count, 1).End(xlUp).Row + 1
ws2.Rows(c).Value = ws1.Rows(i).Value
End If
If ws1.Cells(i, 2).Value = "CCC" Then
d = Sheets("Sheet4").Cells(Rows.Count, 1).End(xlUp).Row + 1
ws2.Rows(d).Value = ws1.Rows(i).Value
End If
Next i
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End Sub

macro to copy and paste data from one Sheet to another when Header is matching

I am trying to create a macro to copy and paste data from one Sheet to another sheet when Header and Column A data is matching and want to paste into the specific cell.
below code is working fine for me when Row(headers) order is the same in both sheets. but I need a solution for when the row (Headers) are not in the order.
"I hope I was able to explain my problem"
Sub transfer()
Dim i As Long, j As Long, lastrow1 As Long, lastrow2 As Long
Dim myname As String
lastrow1 = Sheets("sheet1").Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lastrow1
myname = Sheets("sheet1").Cells(i, "A").Value
Sheets("sheet2").Activate
lastrow2 = Sheets("Sheet2").Range("A" & Rows.Count).End(xlUp).Row
For j = 2 To lastrow2
If Sheets("sheet2").Cells(j, "A").Value = myname Then
Sheets("sheet1").Activate
Sheets("sheet1").Range(Cells(i, "B"), Cells(i, "F")).Copy
Sheets("sheet2").Activate
Sheets("sheet2").Range(Cells(j, "D"), Cells(j, "H")).Select
ActiveSheet.Paste
End If
Next j
Application.CutCopyMode = False
Next i
Sheets("sheet1").Activate
Sheets("sheet1").Range("A1").Select
End Sub
if i understood your goal then may try something like (code is tested with makeshift data)
Sub test()
Dim SrcWs As Worksheet, TrgWs As Worksheet
Dim Col As Long, TrgLastRw As Long, SrclastRw As Long, SrcLastCol As Long, TrgLastCol As Long
Dim SrcRng As Range, TrgRng As Range, C As Range, Hd As String
Set SrcWs = ThisWorkbook.Sheets("Sheet1")
Set TrgWs = ThisWorkbook.Sheets("Sheet2")
SrcLastCol = SrcWs.Cells(1, Columns.Count).End(xlToLeft).Column
TrgLastCol = TrgWs.Cells(1, Columns.Count).End(xlToLeft).Column
For Col = 1 To SrcLastCol
Hd = SrcWs.Cells(1, Col).Value
If Hd <> "" Then
SrclastRw = SrcWs.Cells(Rows.Count, Col).End(xlUp).Row + 1
Set SrcRng = SrcWs.Range(SrcWs.Cells(2, Col), SrcWs.Cells(SrclastRw, Col))
With TrgWs.Range(TrgWs.Cells(1, 1), TrgWs.Cells(1, TrgLastCol))
Set C = .Find(Hd, LookIn:=xlValues) 'each column header is searched in trgWs
If Not C Is Nothing Then
TrgLastRw = TrgWs.Cells(Rows.Count, C.Column).End(xlUp).Row + 1
Set TrgRng = TrgWs.Cells(TrgLastRw, C.Column).Resize(SrcRng.Rows.Count, 1)
SrcRng.Copy Destination:=TrgRng
End If
End With
End If
Next Col
End Sub

VBA code to Insert a Column

I want to insert a column to the right if string"P018" is present in the third row of the sheet:
My code is :
Sub Insrt()
Dim Found As Range
Dim LR As Long
Dim I As Integer
I = 1
Do While Cells(4, I).Value <> ""
'If Cells(3, I).Value = "P018" Then
Set Found = Cells(3, I).Find(what:="P018", LookIn:=xlValues, lookat:=xlWhole)
If Found Is Nothing Then GoTo Label
Found.Offset(, 1).EntireColumn.Insert
Label:
Loop
End Sub
This going in an endless loop.
You want to use a standard for loop that loops backwards:
Sub insert()
Dim ws As Worksheet
Dim lastColumn As Long
Dim i As Long
Set ws = ActiveSheet
With ws
lastColumn = .Cells(4, .Columns.Count).End(xlToLeft).Column
For i = lastColumn To 1 Step -1
If .Cells(3, i) = "P018" Then Columns(i + 1).insert
Next i
End With
End Sub

Resources