VBA Copy Cells vs Rows - excel

I don't use VBA much at all. I found some code online that has me moving in the right direction, however, I'm struggling how to copy just the values in column "A" rather than copying all the rows. The bold/italic area is where I believe the problem lies.
`For i = 2 To a
If Sheets(Range("O1").Value).Cells(i, 9).Value = "False" Then
***Sheets(Range("O1").Value).Rows(i).Copy***
Worksheets("Product_Lookup").Activate
B = Worksheets("Product_Lookup").Cells(Rows.Count, 1).End(xlUp).Row
Worksheets("Product_Lookup").Cells(B + 1, 1).Select
ActiveSheet.Paste
Worksheets("Product_Lookup").Activate`

Using Variables
By using variables, your code will become more readable (understandable).
Activating and selecting often leads to mistakes and it severely slows down the operation. Avoiding this is
illustrated in this post.
The following illustrates the Workbook-Worksheet-Range hierarchy.
' The usual approach is e.g.:
'Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
'Dim iws As Worksheet: Set iws = wb.Worksheets("Sheet1")
' Note that 'iws' could actually be 'dws', we don't know!
Dim iws As Worksheet: Set iws = ActiveSheet ' unknown worksheet?
Dim wb As Workbook: Set wb = iws.Parent
Dim sws As Worksheet
On Error Resume Next ' check if the worksheet exists
Set sws = wb.Worksheets(CStr(iws.Range("O1").Value)) ' it may be empty!
On Error GoTo 0
If sws Is Nothing Then Exit Sub ' the worksheet doesn't exist
Dim dws As Worksheet: Set dws = wb.Worksheets("Product_Lookup")
Dim dCell As Range
Set dCell = dws.Cells(dws.Rows.Count, "A").End(xlUp).Offset(1)
For i = 2 To a
If CStr(sws.Cells(i, "I").Value) = "False" Then
sws.Cells(i, "A").Copy dCell
' If you only need values then the following is more efficient:
'dCell.Value = sws.Cells(i, "A").Value
Set dCell = dCell.Offset(1)
End If
Next i

Related

Paste Special breaking VBA Module

I have been trying to figure out why I am not able to paste values only in this VBA module. Can anyone spot my issue? I have tried many different combinations, and still getting compile errors
Sub Merge_Sheets()
'Set Master sheet for consolidation
Set mtr = Worksheets("Master")
Set wb = ThisWorkbook
'loop through all sheets
For Each ws In wb.Worksheets
'except the master sheet from looping
If ws.Name <> "Master" Then
ws.Activate
Range("A5:P20").Copy _
mtr.Range("A" & mtr.Cells(Rows.Count, 1).End(xlUp).Row + 1).PasteSpecial xlPasteValues
End If
Next ws
Worksheets("Master").Activate
End Sub
Does anyone have any ideas for the issue on this? Thanks in advance!
Append Range Values From All Worksheets
Option Explicit
Sub AppendRangeValues()
Const SRC_RANGE As String = "A5:P20"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = wb.Sheets("Master")
Dim dfCell As Range
Set dfCell = dws.Cells(dws.Rows.Count, "A").End(xlUp).Offset(1)
Dim drg As Range, rCount As Long
With dws.Range(SRC_RANGE)
rCount = .Rows.Count
Set drg = dfCell.Resize(rCount, .Columns.Count)
End With
Dim sws As Worksheet
For Each sws In wb.Worksheets
If Not sws Is dws Then
drg.Value = sws.Range(SRC_RANGE).Value
Set drg = drg.Offset(rCount)
End If
Next sws
MsgBox "Range values appended.", vbInformation
End Sub

Very slow execution of VBA code during getting the list of all worksheet names in an Excel Workbook

I need to work on the workbook in Excel that contains hundreds of specific worksheets. I created this simple code to get the list of names of all these worksheets in the one called "Spis faktur".
The code runs well but is horribly slow. It seems like it executed the one name of specific worksheet in 0,3 second so it takes ages before it finishes to executed the of all names of worksheets.
Sub ListSheets()
Dim sh As Worksheet
Const txt = "Spis faktur"
Set sh = Sheets(txt)
For i = 1 To Worksheets.Count
sh.Cells(i + 1, 1) = ThisWorkbook.Sheets(i).Name
Next i
End Sub
Would be grateful for any piece of advice what could be wrong with this code.
List All Worksheet Names
Option Explicit
Sub ListWorkSheets()
Const dName As String = "Spis faktur"
Const dfCellAddress As String = "A2"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim wsnCount As Long: wsnCount = wb.Worksheets.Count
Dim WorksheetNames() As String: ReDim WorksheetNames(1 To wsnCount, 1 To 1)
Dim sws As Worksheet
Dim n As Long
' Write to array.
For Each sws In wb.Worksheets
n = n + 1
WorksheetNames(n, 1) = sws.Name
Next sws
' Write to range.
Dim dfCell As Range: Set dfCell = dws.Range(dfCellAddress)
Dim drg As Range: Set drg = dfCell.Resize(wsnCount)
drg.Value = WorksheetNames
' Clear below.
Dim dclrrg As Range: Set dclrrg _
= drg.Resize(dws.Rows.Count - drg.Row - wsnCount + 1).Offset(wsnCount)
dclrrg.ClearContents ' or dclrrg.Clear
End Sub

Values are not copied to new Sheet

The final code is this
Sub Unique_Values_Worksheet_Variables()
'1 Code + Sub splitByChars
Const Chars As Long = 4
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets("export")
Dim dws As Worksheet:
Set dws = wb.Worksheets.Add(After:=wb.Sheets(wb.Sheets.Count))
sws.Range("C:C").AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=dws.Range("A:A"), _
Unique:=True
dws.Columns("A:J").EntireColumn.AutoFit
Dim rng As Range:
Set rng = dws.Range("A1:B1", dws.Cells(dws.Rows.Count, 1).End(xlUp))
rng.Borders(xlDiagonalDown).LineStyle = xlNone
rng.HorizontalAlignment = xlCenter
Unfortunately this was just focused on one part which has to be copied, the values for these columns were in another column so i try to switch the code
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets("export")
Dim dws As Worksheet:
Set dws = wb.Worksheets.Add(After:=wb.Sheets(wb.Sheets.Count))
sws.Range("C:C").AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=dws.Range("A:A"), _
Unique:=True
to this. I used the macro reader for it.
Sub Test()
'
' Test Makro
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.ActiveSheet
Dim dws As Worksheet:
Set dws = wb.Worksheets.Add(After:=wb.Sheets(wb.Sheets.Count))
Application.ScreenUpdating = False
sws.Columns("C:C").AdvancedFilter Action:=xlFilterInPlace, Unique:=True
Columns("D:H").EntireColumn.Hidden = True
Columns("C:J").Select
Selection.Copy Destination:=dws.Range("A1")
End Sub
what works:
the code recognizes the part with the new worksheet dws.
it filters in sws the column C:C, what means
it also recognizes sws
what does not work:
by copy paste the range no values are hand over.
I have to use the advanced filter on C:C by avoiding duplicates, then i have data which i do not want to handover in column "D:I". The only thing what i want to hand over is column C & J. So i tried it with hiding the columns in between but it does not work.
Has anybody an idea?
i also tried it with .Delete what actually would be not that nice.
Is it a problem that i just assigned A1 for pasting it?
Selection.Copy Destination:=dws.Range("A1")
Copy Columns (Unique)
About Your Solution
Your solution is pretty cool. You probably meant to hide D:I though, which is a minor issue.
After hiding and filtering you might consider unhiding the columns and removing the filter to bring the source worksheet to the initial state.
I prefer using a worksheet with a name instead of ActiveSheet, but it's no big deal if you know what you're doing.
I don't like the references to the whole columns i.e. letting Excel (VBA) decide which range should be processed.
About the following
I first wrote the second code which is kind of more efficient but comes with the cost of not being able to control the order of the columns (due to Union) to be copied, hence the first code is recommended.
You can easily replace the source worksheet (Worksheets(sName)) with ActiveSheet if necessary.
It is assumed that the source data (table (one row of headers)) starts in cell A1. Otherwise, you may need to create the source range reference in a different way.
Adjust (play with) the values in the constants section.
Option Explicit
Sub copyColumnsUnique()
' Source
Const sName As String = "Sheet1"
Const sUniqueColumn As String = "C"
Const sCopyColumnsList As String = "C,J" ' exact order of the columns
' Destination (new worksheet)
Const dFirst As String = "A1"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sCopyColumns() As String: sCopyColumns = Split(sCopyColumnsList, ",")
Dim dCell As Range: Set dCell = wb.Worksheets _
.Add(After:=wb.Sheets(wb.Sheets.Count)).Range(dFirst)
Application.ScreenUpdating = False
Dim srg As Range
With wb.Worksheets(sName).Range("A1").CurrentRegion
.Columns(sUniqueColumn).AdvancedFilter xlFilterInPlace, , , True
Dim n As Long
For n = 0 To UBound(sCopyColumns)
.Columns(sCopyColumns(n)).Copy dCell
Set dCell = dCell.Offset(, 1)
Next n
.Parent.ShowAllData
End With
Application.ScreenUpdating = True
End Sub
Sub copyColumnsUniqueAsc()
' Source
Const sName As String = "Sheet1"
Const sUniqueColumn As String = "C"
Const sCopyColumnsList As String = "C,J" ' forced ascending order of columns
' Destination (new worksheet)
Const dFirst As String = "A1"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sCopyColumns() As String: sCopyColumns = Split(sCopyColumnsList, ",")
Application.ScreenUpdating = False
Dim srg As Range
With wb.Worksheets(sName).Range("A1").CurrentRegion
.Columns(sUniqueColumn).AdvancedFilter xlFilterInPlace, , , True
' Using 'Union' will force the resulting columns be in ascending order.
' If 'sCopyColumnsList' is "C,J,D", the order will be "C,D,J".
Dim n As Long
For n = 0 To UBound(sCopyColumns)
If srg Is Nothing Then
Set srg = .Columns(sCopyColumns(n))
Else
Set srg = Union(srg, .Columns(sCopyColumns(n)))
End If
Next n
End With
srg.Copy wb.Worksheets.Add(After:=wb.Sheets(wb.Sheets.Count)).Range(dFirst)
srg.Parent.ShowAllData
Application.ScreenUpdating = True
End Sub
Thanks to #Tragmor
for everyone who has same kind of problems, this could solve it
Sub Test()
'
' Test Makro
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.ActiveSheet
Dim dws As Worksheet:
Set dws = wb.Worksheets.Add(After:=wb.Sheets(wb.Sheets.Count))
Application.ScreenUpdating = False
With sws
.Columns("C:C").AdvancedFilter Action:=xlFilterInPlace, Unique:=True
.Columns("D:H").EntireColumn.Hidden = True
.Columns("C:J").Copy Destination:=dws.Range("A1")
End With
End Sub

Paste into next empty column in different sheet

my code aims to copy the same range from multiple sheets and paste the data from each sheet into the next empty column in a Combined sheet. My code copies from each sheet correctly, but pastes into the same column and overwrites the preceding paste.
Could someone please point out my error?
Many thanks!
Sub CopyToNextCol()
Dim Sh As Worksheet
Dim NextCol As Long
For Each Sh In ThisWorkbook.Worksheets
If Sh.Name <> "Master" And Sh.Name <> "Lists" And Sh.Name <> "Combined" Then
NextCol = Sheets("Combined").Cells(, Columns.Count).End(xlToLeft).Column + 1
Sh.Range("B2:B44").Copy Sheets("Combined").Cells(, NextCol)
End If
Next Sh
End Sub
Copy Same Ranges From Multiple Worksheets
The following example will copy the worksheet names ("I am planning to use a different column header" in the comments) in the first row and each range below it.
s - Source, d - Destination.
A Quick Fix
Option Explicit
Sub CopyToNextCol()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = wb.Worksheets("Combined")
Dim dCell As Range
Set dCell = dws.Cells(1, dws.Columns.Count).End(xlToLeft).Offset(, 1)
Dim sws As Worksheet
Dim srg As Range
For Each sws In wb.Worksheets
Select Case sws.Name
Case "Master", "Lists", "Combined"
' Skip (do nothing)
Case Else
Set srg = sws.Range("B2:B44")
dCell.Value = sws.Name
srg.Copy dCell.Offset(1)
Set dCell = dCell.Offset(, 1)
End Select
Next sws
'wb.Save
End Sub

Copying content of one spreadsheet into another

I have 2 different excel files, stored in C:\Test:
Book1.xlsx, with Sheet1 (data in the Sheet1 is changing, not constant data-range, but always starts from A1 cell)
Book2.xlsm, with Sheet2 (empty)
Every time after opening Book2, I need data from Sheet1 of Book1 to be automatically copied into Sheet2 of Book2.
Update:
I tried the following vba code (researched online from Excel Forum)
Private Sub Workbook_Open()
Application.EnableEvents = False
Dim swb As Workbook, Lr As Long, LC As Long, sws As Worksheet
Dim dCell As Range, srg As Range, dwb As Workbook, dws As Worksheet
Set swb = Workbooks.Open("C:\Test\AAA\Book1.xlsx")
Set sws = swb.Worksheets("Sheet1")
Lr = sws.Cells(Rows.Count, 1).End(xlUp).Row
LC = sws.Cells(1, Columns.Count).End(xlToLeft).Column
Set srg = sws.Range(Cells(1, 1), Cells(Lr, LC))
Set dwb = ThisWorkbook
Set dws = dwb.Worksheets("Sheet2")
Set dCell = dws.Range("A1")
srg.Copy dCell
swb.Close SaveChanges:=False
dwb.Save
Application.EnableEvents = True
End Sub
But, the problem with this - that if I delete a few records after the 1st one from Sheet1 of Book1, then - these deleted records still appear in the Sheet2 of Book2!
I am not great in vba, it's just a part of my whole project
Sorry for these questions
Update 2:
When I have the following in Sheet1, Book1:
Then, after opening Sheet2, Book2, I see (which is correct, what I expected):
But, if I'll delete records in Sheet1, Book1 (starting from the 2nd):
Then, after opening Sheet2, Book2 I will still see those deleted from Book2 records (while I expect them to be gone):
When the destination sheet has more data than the source sheet, you will need to clear it before you copy over the data. You could do it with the Range-method ClearContents:
Set dws = dwb.Worksheets("Sheet2")
dws.Usedrange.ClearContents
Set dCell = dws.Range("A1")
srg.Copy dCell
As it seems that you are copying the data of the whole sheet, an alternative could be to remove the sheet in ThisWorkbook and copy the sheet itself:
' Delete Sheet2 (if present)
On Error Resume Next
Application.DisplayAlerts = False
ThisWorkbook.Sheets("Sheet2").Delete
Application.DisplayAlerts = True
On Error GoTo 0
' Copy Sheet from sourceWorkbook
sws.Copy after:=ThisWorkbook.Sheets(1)
ActiveSheet.Name = "Sheet2" ' Copied sheet gets the active sheet automatically.
Clear Range Below Copied Data
Private Sub Workbook_Open()
Application.EnableEvents = False
Dim swb As Workbook, sws As Worksheet, srg As Range, LR As Long, LC As Long
Dim dwb As Workbook, dws As Worksheet, dCell As Range
Set swb = Workbooks.Open("C:\Test\AAA\Book1.xlsx")
Set sws = swb.Worksheets("Sheet1")
LR = sws.Cells(sws.Rows.Count, 1).End(xlUp).Row
LC = sws.Cells(1, sws.Columns.Count).End(xlToLeft).Column
Set srg = sws.Range(sws.Cells(1, 1), sws.Cells(LR, LC))
Set dwb = ThisWorkbook
Set dws = dwb.Worksheets("Sheet2")
Set dCell = dws.Range("A1")
srg.Copy dCell
With dCell.Resize(, srg.Columns.Count)
.Resize(.Worksheet.Rows.Count - .Row - srg.Rows.Count + 1) _
.Offset(srg.Rows.Count).Clear
End With
swb.Close SaveChanges:=False
dwb.Save
Application.EnableEvents = True
End Sub

Resources