Export values not formulas with VBA - vba

I am using the script below to export a worksheet as a CSV:
Sub Button14_Click()
'
' export Macro
Dim LR As Long
LR = Range("A" & Rows.Count).End(xlUp).Row
Range("A2:M" & LR).SpecialCells(xlCellTypeConstants, 23).Select
Selection.Copy
Workbooks.Add
ActiveSheet.Paste
ActiveWorkbook.SaveAs Filename:= _
"C:\upload\19meat-kl.csv" _
, FileFormat:=xlCSV, CreateBackup:=False
Application.DisplayAlerts = False
ActiveWorkbook.Close
Application.DisplayAlerts = True
End Sub
I am a novice at VBA scripting and I actually got this code from another post.
For the most part it does what I want but if I try to use a formula it exports the formula rather than the result. What do I need to change so that the cell contents are what is exported?

Further to the comment by #Mat'sMug you need to use PasteSpecial xlValues and not just Paste.
Try this example code below - it does what your original macro does but with some best practices:
Use Option Explicit to prevent issues with badly defined variables
Set references to source data and target data e.g. source worksheet (wsSource), source range (rngToCopy), target workbook (wbTarget) and
target worksheet (wsTarget) - this is better than using ActiveSheet or Something.Select and so forth, which is not best practice
Do the paste immediately after the copy to prevent issues with clipboard persistence
Code:
Option Explicit
Sub SaveRangeDataAsValuesOnNewWorkbook()
' set-up your variables
Dim strFileToSave As String
Dim wsSource As Worksheet
Dim lngLastRow As Long
Dim wbTarget As Workbook
Dim wsTarget As Worksheet
Dim rngToCopy As Range
' where you want to save
strFileToSave = "C:\upload\19meat-kl.csv"
' get a worksheet reference
Set wsSource = ThisWorkbook.Worksheets("Sheet1") '<~~ set to your worksheet
' get last row in column A - you need to reference a worksheet to do this properly
lngLastRow = wsSource.Range("A" & wsSource.Rows.Count).End(xlUp).Row
' now - add a workbook and get its reference
Set wbTarget = Application.Workbooks.Add
' get the first worksheet in the new workbook
Set wsTarget = wbTarget.Worksheets(1)
' get a reference to your source range
Set rngToCopy = wsSource.Range("A2:M" & lngLastRow).SpecialCells(xlCellTypeConstants, 23)
' copy the source range
rngToCopy.Copy
' paste it to the target worksheet in the new workbook - you need to PasteSpecial to a Range
wsTarget.Range("A1").PasteSpecial xlValues
' save the new workbook
wbTarget.SaveAs Filename:=strFileToSave, FileFormat:=xlCSV, CreateBackup:=False
' close the new workbook
Application.DisplayAlerts = False
wbTarget.Close
Application.DisplayAlerts = True
End Sub

Related

my code merging all workbooks into seperate sheets. i need to merge all in 1 same sheet

I tried to merge the workbooks by browsing and selecting multiple workbooks time and getting all data in current workbook. I need all data of selected workbooks in 1 sheet.But my code gives in different sheets of current workbook. sheets.Copy after:=mainWorkbook.Sheets(mainWorkbook.Worksheets.Count) as per this line,syntax allowing me to opt either after or before but not giving current. pls help me out
Dim files, i As Integer
Dim dailogbox As FileDialog
Dim mainWorkbook, sourceWorkbook As Workbook
Dim sheets As Worksheet
Set mainWorkbook = Application.ActiveWorkbook
Set dailogbox = Application.FileDialog(msoFileDialogFilePicker)
dailogbox.AllowMultiSelect = True
files = dailogbox.Show
For i = 1 To dailogbox.SelectedItems.Count
Workbooks.Open dailogbox.SelectedItems(i)
Set sourceWorkbook = ActiveWorkbook
For Each sheets In sourceWorkbook.Worksheets
sheets.Copy after:=mainWorkbook.Sheets(mainWorkbook.Worksheets.Count)
Next tempWorkSheet
sourceWorkbook.Close
Next i
As you have discovered, Sheets.Copy will copy or move the entire sheet. It will not merge the data into another sheet. You will have to copy the cells of the sheet you want to copy,
dim dest as Range
For i = 1 To dailogbox.SelectedItems.Count
Workbooks.Open dailogbox.SelectedItems(i)
Set sourceWorkbook = Workbooks.Open(dailogbox.SelectedItems(i))
For Each aSheet In sourceWorkbook.Worksheets '
set dest = mainWorkbook.Sheets(mainWorkbook.Worksheets.Count)
aSheet.Cells.Copy dest.Cells
Next sheets ' NOT "tempWorkSheet"
sourceWorkbook.Close
Next i
Also: "Sheets" is a reserved word. You can't use it as a variable. I changed it to "aSheet".
EDIT: To copy the formatting after copying the text, add this after aSheet.Cells.Copy dest.Cells:
dest.PasteSpecial Paste:=xlPasteFormats
This will open a file dialog allowing you to select multiple files, it will then cycle through each sheet on the work books, copy the data from A2 to the bottom right corner of your data, and paste it in the workbook that hosts this code.
Things you will need to modify or amend for:
1) The sheet name of your book that hosts this code
2) The Col span (A-Z right now)
3) If your import books have multiple sheets, you need to set a criteria for which sheets you want to import since this will grab every sheet from every selected workbook.
4) This assumes Col A does not have any blanks (to determine last row (what range to copy) you need to pick a column that is least likely to have blanks so you dont miss data.
Option Explicit
Sub Consolidation()
Dim CurrentBook As Workbook
Dim WS As Worksheet
Set WS = ThisWorkbook.Sheets("SHEETNAME?")
Dim IndvFiles As FileDialog
Dim FileIdx As Long
Dim i As Integer, x As Integer
Set IndvFiles = Application.FileDialog(msoFileDialogOpen)
With IndvFiles
.AllowMultiSelect = True
.Title = "Multi-select target data files:"
.ButtonName = ""
.Filters.Clear
.Filters.Add ".xlsx files", "*.xlsx"
.Show
End With
Application.DisplayAlerts = False
Application.ScreenUpdating = False
For FileIdx = 1 To IndvFiles.SelectedItems.Count
Set CurrentBook = Workbooks.Open(IndvFiles.SelectedItems(FileIdx))
For Each Sheet In CurrentBook.Sheets
Dim LRow1 As Long
LRow1 = WS.Range("A" & WS.Rows.Count).End(xlUp).Row
Dim LRow2 As Long
LRow2 = CurrentBook.ActiveSheet.Range("A" & CurrentBook.ActiveSheet.Rows.Count).End(xlUp).Row
Dim ImportRange As Range
Set ImportRange = CurrentBook.ActiveSheet.Range("A2:Z" & LRow2)
ImportRange.Copy
WS.Range("A" & LRow1 + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Next
CurrentBook.Close False
Next FileIdx
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
maybe you're after this (explanations in comments):
Option Explicit
Sub CopySheets()
Dim files As Variant, i As Long
Dim dailogbox As FileDialog
Dim mySheet As Worksheet, targetSheet As Worksheet
Set targetSheet = ActiveSheet ' set the sheet you want to collect selecte workbooks worksheets data into
Set dailogbox = Application.FileDialog(msoFileDialogFilePicker)
dailogbox.AllowMultiSelect = True
files = dailogbox.Show
For i = 1 To dailogbox.SelectedItems.Count
With Workbooks.Open(dailogbox.SelectedItems(i)) ' open and reference current workbook
For Each mySheet In .Worksheets ' loop through current workbook worksheets
mySheet.UsedRange.Copy targetSheet.Cells(targetSheet.Rows.Count, 1).End(xlUp).Offset(1) ' copy current worksheet "used" range and paste them into target sheet from its column A first empty cell after last not empty one
Next
.Close False ' cloe current workbook, discarding changes
End With
Next
End Sub

VBA doesn't work when looping through files (subscript out of range)

I just have started using vba.
Googled for a long time to find an answer.
I have written code for copying cells from one sheet into new one.
I have to do it for every file in a folder.
So I try to use looping. However in a middle of a process error occurs (subscript out of range)
Here is my code that works for one file.
Sub add()
Sheets.add.Name = "Good"
GetBook = ActiveWorkbook.Name
Sheets("Good").Range("A1") = GetBook
Sheets("Report Details").Range("E6:E8").Copy
With Sheets("Good").Range("B1")
.PasteSpecial Paste:=xlPasteValues, Transpose:=True
End With
Sheet2.Activate
Range(Range("A1").End(xlDown), Range("H1").End(xlDown)).Copy
With Sheets("Good").Range("E1")
.PasteSpecial Paste:=xlPasteValues
.PasteSpecial Paste:=xlPasteFormats
End With
End Sub
Here I try to loop it but it doesn't work, problem occurs here in the first code when looping
With Sheets("Good").Range("E1")
Looping code
FolderPath = "C:\Users\Maxim Osipov\Documents\Mckinsey\BorisT\Project 3(Smart city solutions)\VBA collecting" 'change to suit
If Right(FolderPath, 1) <> "\" Then FolderPath = FolderPath + "\"
Filename = Dir(FolderPath & "*.xlsx")
Do While Filename <> ""
Application.ScreenUpdating = False
Set wb = Workbooks.Open(FolderPath & Filename)
'Call a subroutine here to operate on the just-opened workbook
Call add
Filename = Dir
Loop
Application.ScreenUpdating = True
End Sub
Try this slight variation:
Sub add()
'Sheets.add.Name = "Good"
Sheets("Good").Range("A1") = ActiveWorkbook.Name
Sheets("Report Details").Range("E6:E8").Copy
Sheets("Good").Range("B1").PasteSpecial Paste:=xlPasteValues, Transpose:=True
Sheets("Sheet2").Range(Range("A1").End(xlDown).Address, Range("H1").End(xlDown).Address).Copy
Sheets("Good").Range("E1").PasteSpecial Paste:=xlPasteValues
Sheets("Good").Range("E1").PasteSpecial Paste:=xlPasteFormats
End Sub
See also:
Microsoft : Range Object (Excel)
10 ways to reference Excel workbooks and sheets using VBA
MSDN : Refer to Sheets by Name
MSDN : How to Reference Cells and Ranges
MSDN : Range.Copy Method
I was having some trouble figuring out which workbook some of your sheets were in - the ones being opened, or the one being pasted to.
This code will loop through the xlsx files in your folder and copy the ranges to the workbook holding the VBA code.
I added a function to check if the Good worksheet already exists and use that if it does.
Public Sub Main()
Dim FolderPath As String
Dim FileName As String
Dim WB As Workbook
Dim WS As Worksheet
FolderPath = "C:\Users\Maxim Osipov\Documents\Mckinsey\BorisT\Project 3(Smart city solutions)\VBA collecting\"
FileName = Dir(FolderPath & "*.xls*")
Do While FileName <> ""
Set WB = Workbooks.Open(FolderPath & FileName, False, True) 'Not updating links & is read-only.
'You can't create two sheets with the same name,
'so check if it exists first.
If WorkSheetExists("Good") Then
Set WS = ThisWorkbook.Worksheets("Good")
Else
'Add a worksheet to the workbook holding this code.
Set WS = ThisWorkbook.Worksheets.Add
WS.Name = "Good"
End If
'Pass the workbook and worksheet references to the procedure.
Add WB, WS
WB.Close SaveChanges:=False
FileName = Dir
Loop
End Sub
Public Sub Add(WrkBk As Workbook, wrkSht As Worksheet)
Dim LastCell As Range
Dim LastRow As Long
With wrkSht
'Find the last cell.
'You could use "LastRow = .Cells(.Rows.Count, "B").End(xlUp).Row"
'but not sure how much data is in the Sheet2.
Set LastCell = .Cells.Find("*", _
After:=.Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
If LastCell Is Nothing Then
LastRow = 1
Else
LastRow = LastCell.Row + 1
End If
.Cells(LastRow, 1) = WrkBk.Name
WrkBk.Worksheets("Report Details").Range("E6:E8").Copy
.Cells(LastRow, 2).PasteSpecial Paste:=xlPasteValues, Transpose:=True
With WrkBk.Worksheets(2)
.Range(.Cells(1, 1), .Cells(.Rows.Count, "H").End(xlUp)).Copy
End With
With .Cells(LastRow, "E")
.PasteSpecial Paste:=xlPasteValues
.PasteSpecial Paste:=xlPasteFormats
End With
End With
End Sub
Public Function WorkSheetExists(SheetName As String, Optional WrkBk As Workbook) As Boolean
Dim wrkSht As Worksheet
If WrkBk Is Nothing Then
Set WrkBk = ThisWorkbook
End If
On Error Resume Next
Set wrkSht = WrkBk.Worksheets(SheetName)
WorkSheetExists = (Err.Number = 0)
Set wrkSht = Nothing
On Error GoTo 0
End Function
If you can only use the Sheet2 reference in the workbook being opened this function will find it:
Public Function GetWorkSheet(sCodeName As String, Optional wrkBook As Workbook) As Worksheet
Dim wrkSht As Worksheet
If wrkBook Is Nothing Then
Set wrkBook = ThisWorkbook
End If
For Each wrkSht In wrkBook.Worksheets
If wrkSht.CodeName = sCodeName Then
Set GetWorkSheet = wrkSht
Exit For
End If
Next wrkSht
End Function
To use it just change this line at the bottom of the Add procedure:
With WrkBk.Worksheets(2)
to
With GetWorkSheet("Sheet2", WrkBk)
It's best practice (and warmly recommended) not to use Activate/ActiveXXX/Select/Selection pattern and take advantage of fully qualified range reference up to workbook one
so you could refactor your add() sub as follows (explanations in comments):
Option Explicit
Sub add(ws As Worksheet)
Dim repDetRngToCopy As Range, sht2RngToCopy As Range
With ws 'reference passed worksheet
Set repDetRngToCopy = .Parent.Worksheets("Report Details").Range("E6:E8") 'set needed range in "Report Details" worksheet of the same workbook the currently referenced sheet (i.e. the passed one) belongs to
With .Parent.Worksheets(2) 'reference Sheet2 worksheet of the same workbook the currently referenced sheet belongs to
Set sht2RngToCopy = .Range(Range("A1").End(xlDown), .Range("H1").End(xlDown)) 'set needed range in currently referenced sheet (i.e. Sheet2)
End With
'now start filling cells of referenced sheet (i.e. the passed one)
.Range("A1") = .Name
repDetRngToCopy.Copy 'copy from the range previously defined in "Report Details"
.Range("B1").PasteSpecial Paste:=xlPasteValues, Transpose:=True ' paste in currently referenced sheet
sht2RngToCopy.Copy 'copy from the range previously defined in Sheet2
.Range("E1").PasteSpecial Paste:=xlPasteValues + xlPasteFormats 'paste in currently referenced sheet
.Name = "Good" ' name currently referenced sheet
End With
End Sub
and consequently slightly change your "main" sub where you call it as follows:
Do While Filename <> ""
'Call a subroutine here to operate on the just-opened workbook
With Workbooks.Open(FolderPath & Filename) ' open and reference a new workbook
add .Sheets.add ' call add passing it a reference to a new sheet in referenced workbook (i.e. the newly opened one)
.Close True ' close referenced workbook saving changes
End With
Filename = Dir
Loop

Copy All values VBA script failing

I am trying to create a VBA script that copies all data in a whole workbook as pastes as values, then saves as a new workbook, thus removing all formulas.
Here is my code:
Sub MakeAllVals()
Dim wSheet As Worksheet
For Each wSheet In Worksheets
With wSheet
.UsedRange.Copy
.PasteSpecial xlValues
End With
Next wSheet
Application.Dialogs(xlDialogSaveAs).Show
End Sub
I'm getting a runtime error 1004 on the .PasteSpecial xlValues command but I can't work out why.
How can I accomplish the goal of pasting all data as values and saving as a new workbook?
You just need to paste to a range in the new sheet. Currently you are not pasting within the new book and you are not pasting within a range.
Sub MakeAllVals()
Dim oldBook As Workbook, oldSheet As Worksheet
Dim newBook As Workbook, newSheet As Worksheet
Set oldBook = ThisWorkbook ' Set to the formula workbook you want to copy from
Set newBook = Workbooks.Add ' Make the new workbook you want only values in
For Each oldSheet In oldBook.Sheets ' Loop through all of the sheets in the formula book
Set newSheet = newBook.Sheets.Add ' Make a new sheet in the newbook to add the values to
newSheet.Name = oldSheet.Name & " Values"
oldSheet.UsedRange.Copy
newSheet.Range("A1").PasteSpecial xlValues ' Paste in a range on the new sheet as Values
Next oldSheet
Application.Dialogs(xlDialogSaveAs).Show ' Show Save As Dialog window
End Sub
You were close just have to move UsedRange up next to wSheet
Sub MakeAllVals()
Dim wSheet As Worksheet
For Each wSheet In ActiveWorkbook.Worksheets
With wSheet.UsedRange
.Copy
.PasteSpecial xlValues
End With
Next wSheet
Application.Dialogs(xlDialogSaveAs).Show
End Sub

Code working in specific workbook but not in Personal Workbook

I have a workbook named Test and wrote a macros with the code below. It worked fine, but when I added it to my personal workbook, the code gave an error on line Set ws = ThisWorkbook.Sheets("Sheet1").
Subscript out of range.
I moved the code from a module to the Sheet1 on the Personal Workbook and then to the ThisWorkbook. Nothing helped. If you could give any sort of advice of what I could try that would be greatly appreciated.
Sub KeepOnlyAtSymbolRows()
Dim ws As Worksheet
Dim rng As Range
Dim lastRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
lastRow = ws.Range("E" & ws.Rows.Count).End(xlUp).Row
Set rng = ws.Range("E1:E" & lastRow)
' filter and delete all but header row
With rng
.AutoFilter Field:=1, Criteria1:="<>*#*"
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
' turn off the filters
ws.AutoFilterMode = False
End Sub
Do you specifically wish to refer to the sheet "Sheet1" in the currently open workbook?
If so, use the line below
Set ws = ActiveWorkbook.Worksheets("Sheet1")
And if you simply wish to refer to the current sheet, use
Set ws = ActiveSheet
And if you wish to simply target the first sheet, whatever its name,
Set ws = ActiveWorkbook.Worksheets(1)
The way the code is currently written, it seems to be referring to "Sheet1" in the personal workbook and not necessarily the one currently active with the user.

Copying range to new workbook

I have come across some code to copy a range to a new workbook, but I'm not sure why it works.
Worksheets("Short Form").Copy
Set wb = ActiveWorkbook
How does this copy the worksheet 'Short Form' to a new workbook when all that the code says is assign the active workbook to the reference 'wb'? It doesn't even employ the .add method. Right now I want to paste values only to this new workbook, but not quite sure how to do so because I don't understand this block of code.
Try this - as the following manual steps are the same as your code snippet:
1.Open a blank workbook
2.Press record macro
3.Right click the Sheet1 workbook tab
4.Select "Move or Copy"
5.In the "To book" combo select (new book)
6.Check the "Create a copy" box so that the window now looks like this:
7.Stop the recorder
8.Go and find your recorded code ...and voila....mine looks like this
Option Explicit
Sub Macro1()
'
' Macro1 Macro
'
'
Sheets("Sheet1").Select
Sheets("Sheet1").Copy
End Sub
Your code is the same as what these manual steps describe.
You must have a line Dim wb as workbook somewhere or it would not run.
This line Set wb = ActiveWorkbook will then make the object wb equal to the new workbook that you have copied into, as it is active, so you can do further operations on it. You can easily switch the workbook that wb is pointed at:
Sub Macro1()
Dim wb As Workbook
ThisWorkbook.Sheets("Sheet1").Copy
Set wb = ActiveWorkbook
MsgBox wb.Name
ThisWorkbook.Activate
Set wb = ActiveWorkbook
MsgBox wb.Name
End Sub
BUT
In my production code I generally never use Set x To ActiveWorkbook I always name the workbook and then use Set x To Workbooks("DefiniteName")
WITHOUT USING CLIPBOARD
If you want to avoid using the clip board then the following example shows how to move values-only data without using paste:
Sub WithoutPastespecial()
Dim firstRange As Range
Set firstRange = ThisWorkbook.Worksheets("Short Form").Range("S4:S2000") 'can change S4:S2000 to the range you want to copy
Dim newBk As Workbook
Dim secondRange As Range
Set newBk = Workbooks.Add
Set secondRange = newBk.Worksheets("Sheet1").Range("A1")
With firstRange
Set secondRange = secondRange.Resize(.Rows.Count, .Columns.Count)
End With
secondRange.Value = firstRange.Value
End Sub
Note this is not copying a Range rather the entire worskheet :)
If you use the method:
Worksheets("Short Form").Cells.Copy
Then you will copy only the cells, not the entire worksheet, and this method will NOT create a new workbook. You can tell it to add a workbook when necessary.
Here is an example:
Option Explicit
Sub CopyNew()
Dim wbNew As Workbook
Dim wb As Workbook
Set wb = ThisWorkbook 'It is a good idea to explicitly control workbooks using either a defined variable like "wb" or the "ThisWorkbook" object, instead of using "ActiveWorkbook" or referring to files by name.
Application.CutCopyMode = False
wb.Sheets("Short Form").Cells.Copy
'Add a new workbook for the values:
Set wbNew = Workbooks.Add
wbNew.Sheets(1).Cells.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub