VBA - excel neglects comma when pasting external data - vba

I'm trying to write a vba code using the DDE method. The code aims to copy a set of columns of an excel table and paste it in a parametric table in the EES (Engineering Equation Solver) software. Then an EES code is run to solve de table, generating columns of output data. This data is then copied and pasted back in the excel file that contains the input data.
Since I'm new to vba, I've used the example provided by EES (Executing EES Macro Commands from EXCEL) as a guideline.
The problem occurs when the data is pasted back in the excel spreadsheet: the code seems to be neglecting the decimal separator! Both my excel and EES are set to work with the comma as the decimal separator and when I manually copy the results from EES and paste then to excel the number is pasted normally, with the comma (also the numbers from excel are correctly pasted into ESS).
However, when I set the code to perform this task numbers such as "15,47" are pasted in excel as "1,55E+12" or "1547421377050". The code is shown below:
Private Sub cmdDDE_Click()
Dim ChNumber As Integer
Dim myShell As String
ChNumber = -1
myShell = frmEESDDE.txtApp.Text
On Error Resume Next
'Copy selected rows into clipboard
Range("B2:G1401").Select
Selection.Copy
Shell_R = Shell(myShell, 1)
If Shell_R <> "" Then
'Initiate DDE
ChNumber = Application.DDEInitiate(app:="ees", topic:="")
If ChNumber <> -1 Then
'Open EES
Application.DDEExecute ChannelNumber, "[Open C:\EES\Tablesolve.ees]"
'Paste data
Application.DDEExecute ChannelNumber, "[Paste Parametric 'Table 1' R1 C1]"
'Solve parametrictable
Application.DDEExecute ChannelNumber, "[SOLVETABLE 'TABLE 1' Rows=1..1400]"
'Copy results
Application.DDEExecute ChannelNumber, "[COPY ParametricTable 'Table 1' R1 C7:R1400 C14]"
'Choose separators
Application.DecimalSeparator = ","
Application.ThousandsSeparator = "."
Application.UseSystemSeparators = False
'Paste results from EES into EXCEL
Application.Paste Destination:=Worksheets("Sheet1").Range("H2:O1440")
Application.UseSystemSeparators = True
'Quit EES and Terminate DDE
DDEExecute ChNumber, "QUIT"
Application.DDETerminate ChNumber
Else
MsgBox "Unable to initiate connection to EES", vbExclamation, "EES DDE"
End If
frmEESDDE.Hide
Else
MsgBox "The application, " & myShell & ", was not found", vbExclamation, "EES DDE"
End If
PS = As you can see I've tried to set the decimal separator to "," as suggested in this link: Pasting decimal numbers in excel / comma and point decimal separator but it didn't work either!
I appreciate your help!

Problem solved!
I also posted the question in the portuguese speaking community of stackoverflow and got a very helpful answer. With little adjustments it solved my problem!
The link to the solution in portuguese follows:
https://pt.stackoverflow.com/questions/74860/vba-excel-n%C3%A3o-reconhece-v%C3%ADrgula-de-dados-externos
But for those who would prefer the english version I'll try to summarize what was done to fix the code:
1- declare range variables:
Dim interval As Range 'represent the cells in which info was pasted
Dim Cell As Range 'to allow cell format to be changed
2- after copying the results from the esternal program and before pasting:
Set interval = Worksheets("Sheet1").Range("H2:O1440") 'set interval to paste the results
interval.NumberFormat = "#" 'set format to text
3- after pasting:
interval.NumberFormat = "General" 'set format to general
For Each Cell In interval
Cell.Value = FormatNumber(CDbl(Cell.Value), 2) 'set only 2 decimal places
Cell.Value = CDbl(Cell.Value) 'set to double
Next
The rest of the code stays as it is.
Special thanks to Cantoni who helped with the solution in the pt version.

Instead of pasting with application.paste, try to paste only the values. ie: Instead of
Application.Paste Destination:=Worksheets("Sheet1").Range("H2:O1440")
Use
Range("H2:O1440").PasteSpecial xlPasteValues
If that doesn't work, parse the output as a string.

You can also try this:
Worksheets("Sheet1").Range("H2").PasteSpecial xlPasteValuesAndNumberFormats

Related

EPPlus fails to set formulas. Instead, it corrupts the formula XML

When I try to set cell formulas in an existing Excel file via EPPlus, the excel document is corrupted. Excel throws "We found a problem with some content in 'Excel.xlsx'. Do you want us to try to recover as much as we can? If you trust the source of this workbook, click Yes." dialog box, then says, "Removed Records: Formula from /xl/worksheets/sheet1.xml part"
If I comment out the formula set operations, the error goes away, but it fills in with formulas I didn't ask for anywhere in my code.
I have an excel file with several sheets. On one sheet, I want to set a value in column L and set formulas in columns I, J, and M. If I do this manually within Excel, everything works without error. But when I try to automate it, I Get the error messages and lose the formulas.
intended formulas:
Formula for column I: =IFNA(VLOOKUP([#[SQL Server]],SqlVersions!$C:$R,12, TRUE),"--")
Formula for column J: =IFNA(VLOOKUP([#[SQL Server]],SqlVersions!$C:$S,17,TRUE),"--")
Formula for column M: =IFNA(VLOOKUP([#[SQL Server]],SqlVersions!$C:$R,8,TRUE), "--")
Dim Hdr As String = ""
dim serverData as New List (of string) 'a list of data like A1||ServerName
' SNIP <get list data from database.> /SNIP
Dim fInfo As New FileInfo(excelFile)
Using ePack As New ExcelPackage(fInfo)
Dim mySheet As ExcelWorksheet = Nothing
'find the sheet we need.
For Each sheet As ExcelWorksheet In ePack.Workbook.Worksheets
If sheet.Name = ExcelServers Then
mySheet = sheet
Exit For
End If
Next
If IsNothing(mySheet) Then Throw New Exception("Server sheet not found.")
For Each serverRow in ServerData
If IsNothing(serverRow) OrElse InStr(serverRow, "||") = 0 Then Continue For 'skip "blank" rows
Dim Cell() As String = Split(serverRow, "||")
Dim CellAddress As String = Cell(0) 'A1..A50
Dim CellValue As String = Trim(Cell(1)) 'ServerName or table header
Dim CellAddressCol As String = Left(CellAddress, 1) ' Will always be A
Dim CellAddressRow As Integer = CellAddress.Substring(1) 'number, 1-50
If CellValue = "Oracle Server" Then
Hdr = "Ora" 'we've found a list of Oracle servers
Continue For 'skip ahead to the next value
ElseIf CellValue = "SQL Server" Then
Hdr = "Sql" 'we're done with Oracle, moving on to SQL Server servers
Continue For 'skip ahead to the next value
ElseIf CellValue = "Non-DB Servers" Then
Exit For 'we're done with all of our work.
End If
If Hdr = "Ora" Then
If Len(CellValue) < 2 Then
mySheet.Cells("L" & CellAddressRow).Value = ""
Else
mySheet.Cells("L" & CellAddressRow).Value = "P"
End If
ElseIf Hdr = "Sql" Then
If Len(CellValue) < 2 Then
mySheet.Cells("I" & CellAddressRow).Value = ""
mySheet.Cells("J" & CellAddressRow).Value = ""
mySheet.Cells("L" & CellAddressRow).Value = ""
mySheet.Cells("M" & CellAddressRow).Value = ""
ElseIf CellValue = "Cluster1" Or CellValue = "Cluster2" Then
mySheet.Cells("I" & CellAddressRow).Value = ""
mySheet.Cells("J" & CellAddressRow).Value = ""
mySheet.Cells("L" & CellAddressRow).Value = "C"
mySheet.Cells("M" & CellAddressRow).Value = ""
Else 'data row.
mySheet.Cells("I" & CellAddressRow).Formula = "IFNA(VLOOKUP([#[SQL Server]],SqlVersions!$C:$R,12, TRUE),""--"")"
mySheet.Cells("J" & CellAddressRow).Formula = "IFNA(VLOOKUP([#[SQL Server]],SqlVersions!$C:$S,17,TRUE),""--"")"
mySheet.Cells("L" & CellAddressRow).Value = "V"
mySheet.Cells("M" & CellAddressRow).Formula = "ifNA(VLOOKUP([#[SQL Server]],SqlVersions!$C:$R,8,FALSE),""--"")"
End If ' /empty row? Cluster row? other server row?
End If ' /Oracle or SQL?
Next
ePack.Save()
End Using
I expect to get a series of rows where the rows after "Oracle" get a "P" in column L and the rows after "SQL Server" have lookup formulas in columns I, J, and M, with a "V" in column L.
If I leave the .Formula = code in place, I get the errors. If I comment out the .Formula lines, I instead get the formula "=70+65" for Oracle rows and "=159+799" for SQL Server rows.
The end result should look something like this:
(Note that the Oracle rows and two header rows are just text and aren't modified by this code.)
Oracle Server,,,,,,,,Version,Patch,,P V or C, End of Life
Oracle1,,,,,,,,12.2.0.1,27937914,,P,
Oracle,,,,,,,,12.2.0.1,27937914,,P,
,,,,,,,,
Sql Server,,,,,,,,Version,Patch,,P V or C,End of Life
Cluster1,,,,,,,,,,,C,7/14/2026
Cluster2,,,,,,,,,,C,
Sql1,,,,,,,2016 Ent 13.0.5337,SP2 CU7 Up,,V,10/12/2027
Sql2,,,,,,,2017 Ent 14.0.3223,CU16,,V,7/14/2026
[...]
sql32,,,,,,,2016 Ent 13.0.5426,SP2 CU8,,V,7/14/2016
,,,,,,,,
Non-DB Servers,,,,,,,,
But what I'm getting, after I accept the error message request to repair is:
Oracle Server,,,,,,,,Version,Patch,,P V or C, End of Life
Oracle1,,,,,,,,12.2.0.1,27937914,,135,
Oracle,,,,,,,,12.2.0.1,27937914,,135,
,,,,,,,,,,,135
Sql Server,,,,,,,,Version,Patch,,P V or C,End of Life
Cluster1,,,,,,,,,,958,#N/A
Cluster2,,,,,,,,,,958,#N/A
Sql1,,,,,,,,,,958,10/12/2027
Sql2,,,,,,,,,,958,7/14/2026
[...]
sql32,,,,,,,,,,958,7/14/2016
,,,,,,,,,,958,#N/A
Non-DB Servers,,,,,,,,
I have no idea where those formulas are coming from at all, as they are nowhere in my code, ever.
Edit
Here is the Excel file (scrubbed of actual server names) as it should be.
And here is the Excel file (also scrubbed) as this code leaves it.
When I open and save() the sample you provided, without doing any edit whatsoever, it always shows me the problem with some content error (tried on Windows 10 with Office 365 and .NET 4.7.2). Because of this I cannot be certain of the cause in your specific situation.
However, I notice EPPlus has a problem when 'translating' formulae when using a Table within Excel. As an example a simple vlookup:
=VLOOKUP(A2,Data!A:B,2,FALSE)
When the above formula is used in a Table, it is changed after being saved with EPPlus and is now erroneous (showing #NAME?) because of the A:B:B:
=VLOOKUP(A2,Data!A:B:B,2,FALSE)
Finding out if this is a bug in EPPlus will require some extensive debugging, with the ExcelCellBase.Translate method being a good start. Also, someone else might already have found it (EPPlus has an relatively large list of open issues.
Sorry if this does not help. I think what I showed is a bug in EPPlus, but I do now know if it it the cause for your problem.

Copy and Paste Error : '1004'

I am using VBA to help manage a set of data. I will have Monthly Data for 50 months and I wish to categorize it into different sheets based on the FIRST word within a cell. Here is what I done so far;
I created a workbook with 2 sheets,
Sheet1(Employee Inventory)
Sheet2(PB)
and my code is written and saved in this Workbook.
Sub myCode()
Dim OldString As String
Dim NewString As String
Set i = Sheets("Employee Inventory")
Set PB = Sheets("PB")
Dim counterPB
counterPB = 2
Dim d
Dim j
d = 1
j = 2
Do Until IsEmpty(i.Range("D" & j))
OldString = i.Range("D" & j)
NewString = Left(OldString, 2)
If NewString = "PB" Then
i.Rows(j).EntireRow.Copy
PB.Range("A" & counterPB).Select
PB.Paste
counterPB = counterPB + 1
End If
j = j + 1
Loop
End Sub
Apologies for the code as it looks weird. This code looks at Sheet1 and scans column "D" and looks for the first word starting with "PB". Once it does find it, it will copy and paste the whole row into another sheet called Sheet2(PB).
When I am in Microsoft Visual Basic window AND I have the Excel Spreadsheet with Sheet1(Employee Inventory) tab opened and when I click Run Sub I get the following error: Run-time error '1004': Application-defined or object-defined error. When I click on "PB" tab, nothing is being copy and pasted in there.
HOWEVER, when I click on the PB tab and then I click Run Sub, the codes executes and any rows containing the first word "PB" will be copied and pasted in the "PB" tab.
My question is, why does it only work when I have the Sheet2 opened and not when I have Sheet1 Opened?
when use range.select its parent worksheet must be selected, so we can use PB.Activate or not use .select at all.
Try to replace this:
i.Rows(j).EntireRow.Copy
PB.Range("A" & counterPB).Select
PB.Paste
with this line:
i.Rows(j).Copy PB.Rows(counterPB)
Why don't you just select the second sheet at the beginning of the code?
Try the following
ActiveWorkbook.Sheets("Sheet2").Activate
If it really works when this sheet is selected, then it should work with this.

Excel headers/footers won't change via VBA unless blank

Disclaimer: It's been a few years since I worked (a lot) with VBA, so this might be an issue caused by confusing myself with what is essentially a very different language from what I usually deal with.
So; I've got a workbook (Excel 2010) with multiple sheets (20+), most of whom are multi-page. To make things easier when printing everything, I want to add some sheet-specific headers with amongst others the name of the sheet, number of pages and so on.
I've written a tiny function that should (in theory) do this for me by iterating over all the sheets setting the header. However, for some reason it only works if the header is empty; if it already has a value it refuses to overwrite for some unknown reason.
Dim sheetIndex, numsheets As Integer
sheetIndex = 1
numsheets = Sheets.Count
' Loop through each sheet, but don't set any of them to active
While sheetIndex <= numsheets
Dim sheetname, role, labeltext As String
sheetname = Sheets(sheetIndex).name
role = GetRole(mode)
labeltext = "Some text - " & sheetname & " - " & role
With Sheets(sheetIndex).PageSetup
.LeftHeader = labeltext
.CenterHeader = ""
.RightHeader = "Page &[Page] / &[Pages]"
.LeftFooter = "&[Date] - &[Time]"
.CenterFooter = ""
.RightFooter = "Page &P / &N"
End With
sheetIndex = sheetIndex + 1
Wend
I found a solution that seems to work for replacing text. For whatever reason, in the macro, you need to include the header/footer format character codes in order for it to work properly.
This code worked to replace existing header text with new information:
Sub test()
Dim sht As Worksheet
Set sht = Worksheets(1)
sht.PageSetup.LeftHeader = "&L left text"
sht.PageSetup.CenterHeader = "&C center Text"
sht.PageSetup.RightHeader = "&R right text"
End Sub
Without the &L, &C, and &R codes before the text, I could not get it to work.
Some interesting behavior I found is that if you use the following code:
.CenterHeader = "&L some text"
it will actually put the some text in the LeftHeader position. This led me to believe that the formatting codes were very important.
The line Application.PrintCommunication = False (which is added by the macro recorder) before doing PageSetup screws up the formating via VBA.
If your code has got this line in it, try removing it. That solved my problem with setting the header and footer via VBA.
I've read StackOverflow for years and this is the first time I've actually been able to post a solution ... hope it helps someone!! Also, you need to remember, I am a CPA not a programmer ;-)
I am reading some values from the ActiveSheet to populate the header. The application is a tax election that will be sent with a tax return so it must have the taxpayer's name and social security number at the top.
Sub PrintElection()
' Print preview the MTM Election
If Range("Tax_Year").Value = Range("First_MTM_year").Value Then
ActiveSheet.PageSetup.LeftHeader = Format(Worksheets("Election").Range("Taxpayer_Name").Value)
ActiveSheet.PageSetup.RightHeader = Format(Worksheets("Election").Range("Taxpayer_SSN").Value)
ActiveWindow.SelectedSheets.PrintPreview
Else
MsgBox "The 'Effective For Tax Year' date must EQUAL the 'First MTM year' date", vbOKOnly, "Check Years"
Sheets("Roadmap").Select
Range("First_MTM_year").Select
End If
End Sub
It checks to see if the Mark-to-Market election year is the same as the election form then formats the election page.
I split the sheet print setup into 2 loops. First loop with Application.PrintCommunication = False I run the non-header/footer setup. I then set Application.PrintCommunication = True and run the header/footer setup in a second loop. Appears to run faster than in XL2003, and applies the header/footer correctly. Until MS fixes this bug, that works fine for me.

Trying to copy data from a .xls workbook into a .xlsm one while generating data

I am trying to loop through one column of a .xls workbook. Each row of that one column has data that needs to be copied over to the new .xlsm workbook while auto-generating strings I've made (name, descriptions, etc). I tried my solution which is listed below, but I get a 1004 error and I can't figure out how to proceed. I am quite new to VBA so any pointers would be appreciated.
Some problems that I see or might need to be solved are as follows;
Error 1004 (app defined or object defined error). The error is occurring inside the if statement < .Range(Cells((x+1) etc. >
When I copy over the data from one row in the .xls workbook it fills
up two rows (on purpose) for the new .xlsm workbook. So I need to be
able to accommodate an extra row every time I copy data. That's why I
have x = x + 1 in the for loop.
For some of the data in the rows of the .xls workbook that I'm
copying over, they have 2 or 3 pieces of data that need to be parsed
into subsets of 2. So for most of the workbook it's 1 piece of data
that gets turned into 2 rows in the new doc., but if it's 2 pieces of
data > 4 rows, etc.
TL;DR - How do I get past this error and how can I make my code better to successfully copy the data over from the other workbook when iterating through a single column.
Anyways, here is the code:
Sub TestThis()
Dim wb As Workbook
Dim x As Integer
Application.ScreenUpdating = False
Set wb = Workbooks.Open("C:\Users\blah\Documents\blah\Week 02\old file.xls", True, True)
With ThisWorkbook.Worksheets("template")
NumRows = wb.Sheets(1).Range("T9:T1116").Rows.Count
Range("T9:T1116").Select
For x = 1 To NumRows
If ActiveCell.Formula <> "" Then
.Range(Cells(x, 2)).Formula = "field 1"
.Range(Cells(x, 5)).Formula = "field 2"
.Range(Cells(x, 7)).Formula = "a sentence is here but is replaced"
.Range(Cells(x, 9)).Formula = "1"
.Range(Cells(x, 10)).Formula = "blah blah blah data"
.Range(Cells(x, 11)).Formula = "blah blah blah more data"
.Range(Cells((x + 1), 9)).Formula = "2"
.Range(Cells((x + 1), 10)).Formula = "Data in " + ActiveCell.Formula + " is stored in blah"
.Range(Cells((x + 1), 11)).Formula = "Data is stored in blah"
End If
x = x + 1
ActiveCell.Offset(1, 0).Select
Next
End With
wb.Close False
Set wb = Nothing
Application.ScreenUpdating = True
End Sub
I would start by not iterating through all the cells in the column oddly enough. Get the data inside vba, then loop and manipulate from there. So something like;
Dim aInVar As Variant
'This captures all the data inside an input variant in one hit
aInVar = Sheets(1).Range("T9:T1116")
You can also create an output variant to pass stuff into as you parse the input variant:
Dim aOutVar As Variant
'This resizes it to twice the amount of rows as the original
ReDim aOutVar(1 To UBound(aInVar, 1) * 2, 1 To 1)
Once its in there, you can loop through the variant much easier. So;
Dim i As Integer
'Loop through the in variant, doing whatever to its values
For i = 1 To UBound(aInVar, 1)
'test each field looking for whatever.
Select Case aInVar(i, 1)
Case "field 1"
'do something here
aOutVar(i * 2 - 1, 1) = aInVar(i, 1)
Case "field 2"
'do something different here, eg
aOutVar(i * 2 - 1, 1) = Replace(aInVar(i, 1), "replaceStr", "replacementStr")
End Select
Next i
Finally, you can just output the output variant you've created in one hit:
Sheets(2).Range(Cells(1, 1), Cells(UBound(aOutVar, 1), 1)) = aOutVar
Manipulating data inside of vba is miles quicker than looping and testing cells as you go- and its easier to control what you are doing to it. Plus, brings out my OCD when I see people looping through cells using 'Select' / 'Activate' :)
None of that is tested, but hopefully enough to get you going with a different approach.
why not use ADO and treat the source datasheet as a db table. This would avoid a loop entirely and you could still auto-generate strings
References:
MS Technet [Office Space]: Using ADO to Query an Excel Spreadsheet
MS Knowledge Base: How To Use ADO with Excel Data from Visual Basic or VBA
MSDN Library (Scripting Clinic): Much ADO About Text Files
Essentially, you connect to your Excel file using ADO and OLE DB Jet Driver:
Dim cn as ADODB.Connection
Set cn = New ADODB.Connection
With cn
.Provider = "Microsoft.Jet.OLEDB.4.0"
.ConnectionString = "Data Source=C:\MyFolder\MyWorkbook.xls;" & _
"Extended Properties=Excel 8.0;"
.Open
End With
Next, now that you have an an ADO Connection you can use it to create an ADO Recordset:
objRecordset.Open "Select * FROM [Sheet1$]", _
objConnection, adOpenStatic, adLockOptimistic, adCmdText
N.B Notice the [SHEET NAME$] - each sheet is a table!
Your Query: You can customize your query to include column/fields names and auto-generate your strings, a Where clause and even add derived columns that put formulas into the worksheet.
Alternatively you could dump the data in, then use VBA to add your formulas programmatically and for hundreds or throusands of rows in one step.
Once you have your recordset open, you can then use the CopyFromRecordset method of the Range Object to dump your recordset into a cell in your target worksheet in one step

Requirement for an Excel Macro to copy data from excel into power point using VBA

I'm not familiar with VBA and I needed help with this, I don't know how long it would take and what I need to do so any help would be appreciated.
Summary - Basically requirement for an excel macro to loop through certain excel sheets which would be specified and paste the data from each of these sheets into either an existing power point presentation or create a new presentation and paste each of the sheet data as picture on an individual slide.
Key Details are as follows:
1). Each Excel worksheet would either contain 1 excel table or Excel chart.
2). The Excel table or chart will have a print area set around them in Excel. This is how the VBA code will know what to copy on each sheet. It needs to copy the set print area on each sheet and paste in a separate power point slide as picture.
3). In version 1 it will just create a new power point slide and paste into an individual slides. We can specify the height and width requirements to determine the size of picture when pasted into power point. In this version we can specify a generic height and width requirement for the pasted picture.
4). Code needs to work with Excel and PowerPoint 2010. I believe 2007 is very similar and the code written for those versions would work on 2010 also.
Thanks for the help in advance. :)
Option Compare Database
Private Sub Command3_Click()
Call findField(Text1.Value)
End Sub
Public Function findField(p_myFieldName)
Dim db As Database, _
tb As TableDef, _
fd As Field
Set db = CurrentDb
''''''Clearing the contents of the table
DoCmd.RunSQL " Delete from Field_Match_Found"
For Each tb In db.TableDefs
For Each fd In tb.Fields
If fd.Name = p_myFieldName Then
'MsgBox ("Table " & tb.Name & " has the field " & fd.Name)
strsql = "INSERT INTO Field_Match_Found Values (""" & tb.Name & """, """ & fd.Name & """)"
DoCmd.RunSQL strsql
End If
Next fd
Next tb
Set fd = Nothing
Set tb = Nothing
Set db = Nothing
''''''''Checking if any match found for the specified field or not
If DCount("Table_name", "Field_Match_Found") = 0 Then
MsgBox ("No match found in your database")
Else
MsgBox ("Check Table Field_Match_Found for your output")
End If
'''''''''''clearing the text box for the next time
Me.Text1.Value = ""
End Function
Private Sub Form_Load()
Me.Text1.Value = ""
End Sub