Fix missing Reference? - vba

I have an Excel Application that when a user clicks a button the below line of code fires to copy the entire Excel Workbook with a new name to a new folder location:
' Save a copy of workbook to Archive folder
ActiveWorkbook.SaveCopyAs (CreateObject("WScript.Shell").specialfolders("Desktop") & "\Inspections\Archive\FeedSampleReport-" & Environ$("Username") & "-" & Strings.Format(Now(), "mmddyyyy") & ".xlsm")
On my system everything works fine, but on theirs Environ$ flags with Compile error: Can't find project or library. When I checked references of both machines, I found that they have one marked MISSING: Microsoft ActiveX Data Object 6.1 Library.
How do I fix this, and what can I do to ensure new users have necessary references?
EDIT: More information. The issue is only on users with Windows XP machines. My development machine is running Windows7, and the few end-users that are also up to using Windows7 do not have the issue either.

to late bind, instead of declaring objects as a specific type (like ADODB.Connection) you declare them as Object and use
Dim cn as Object
Set cn = CreateObject("ADODB.Connection")
rather than
Dim cn as ADODB.Connection
Set cn = New ADODB.Connection
to instantiate them. you will also have to declare any constants you use from the referenced library (or replace them with a literal value) so for example you might add
Const adOpenStatic As Long = 3
Const adCmdText As Long = 1
Const adLockReadOnly As Long = 1
because without the reference to ADO set those would have no values to VBA.

Related

Running SQL Within An Open Workbook

I'm trying to use VBA to perform some SQL operations within an open workbook. If I open the file as a read only (i.e. from an email) the code runs without issue, but if I save it locally to my desktop I get a run-time error "Cannot update. Database or object is read-only". Below is a snippet of the code I'm trying to run
Set CSVconn = New ADODB.Connection
CSVconn.ConnectionString = _
"Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & ThisWorkbook.FullName & ";" & _
"Extended Properties='Excel 12.0 Xml;HDR=yes';"
CSVConn.Open
tmprs.ActiveConnection = CSVconn
tmprs.Source = "SELECT DISTINCT [X] FROM [Range]"
tmprs.Open
Range(X).CopyFromRecordset tmprs
CSVconn.Close
I believe the problem lies with the "ThisWorkbook.FullName" portion of the connection string since the code works on my coworkers' PCs and off our company drive. The file is saved locally and the "Files On Demand" setting for OneDrive is turned off, but the file path is still listed as running through https://sharepoint.com. I've used the split function to rebuild the SharePoint address as a local C drive one (which will open the workbook if I paste the address in file explorer), but running it in VBA throws an error that the file path is not valid. I've tried switching the connection to a GUID, but Windows shut down the Scriptlet.TypeLib function as a security measure and I can't seem to get their workaround code to run. Anyone know how to fix the CSVConnection issue or how to assign a randomly generated GUID to an open workbook using VBA?

How to use the relative path in SQL - ODBC?

I have a problem with Excel (ODBC / Access). I would like to refresh data from any folder in my computer. I have file which I use from Desktop, but I would like to refresh data from the same file when it will be move to documents, etc. Please could you provide what I should do?
I have a file connection as below:
DSN=Excel Files;DBQ=C:\Users\User\Desktop\Task1\SalesBudget2018.xlsx;DefaultDir=C:\Users\User\Desktop\Task1;DriverId=1046;MaxBufferSize=2048;PageTimeout=5;
Thank you.
EDIT1: Thank you. I tried use your solution and I received error: "run time error 2147467259 Database or object is read-only", my code below. The bug is related to ".Open" line:
Sub RefreshData()
Dim CreateNew As Object
Dim RunSELECT As Object
Dim Data As String
Dim SQL As String
FolderPath = ActiveWorkbook.path
Path = Left(FolderPath, InStrRev(FolderPath, "\") - 1)
Set CreateNew = CreateObject("ADODB.Connection")
With CreateNew
.Provider = "Microsoft.ACE.OLEDB.12.0"
.ConnectionString = "Data Source=" & Path & "\SalesBudget2018.xlsx" & ";" & "Extended Properties=""Excel 12.0 Xml;HDR=YES;"";"
.Open
End With
'Run SQL
SQL = "SELECT * FROM [twRynki$]"
Set RunSELECT = cn.Execute(SQL)
Do
output = output & RunSELECT(0) & ";" & RunSELECT(1) & ";" & RunSELECT(2) & vbNewLine
Debug.Print RunSELECT(0); ";" & RunSELECT(1) & ";" & RunSELECT(2)
rs.Movenext
Loop Until rs.EOF
End Sub
Your path actually is not relative at all. But ACE/JET data engine does not support relative paths anyway.
A relative path would be
\Data\mydb.mdb
So, above would be one folder up called data from current location. And one folder down using relative would be:
..\Data\mydb.mdb
However, with ACE/Access relative paths are not supported. However, what we do when we want software to work say from the current folder? We simple get and use the full path name ON APPLICATION start up. So, you can get/grab the current folder. In Excel VBA you can use this:
ActiveWorkbook.Path
So above will give you the current path. And thus you use that in code to set the connection string. So, even in access, if we want the software to work in any folder? We simply get/grab the full path name on startup. As a result, the software works in any folder and you effective get relative address in that you "don't care" where the software is placed, since you always get/grab the full path name anyway. So, with above, you could append a folder name called data
ActiveWorkbook.Path & "\Data\Mydb.accdb"
So, from the current workbook location, you could always have a folder called data, and inside that folder you can have your database. So, in effect you do get relative addressing, but you always pulling the full path name of the current workbook as per above.
The end result is you don't miss not having some form of relative addressing since you don't need to with this approach.
The above is for Excel VBA. To get current path from Access VBA? You can use this:
currentproject.Path
So, your connection string to Excel could be this:
dim strExcelPath as string
strExcelPath = CurrentProject.Path & "\Task1\SalesBudget2018.xlsx"
It not clear if the access application is in the SAME folder as task1?
Assuming yes, then this would work:
strExcelPath = CurrentProject.Path & "\SalesBudget2018.xlsx"
So, now the folder can be on the desktop, my documents - it will not matter. You can thus use above as part of your connection string. It not clear if you linking to Excel (linked table), or you using VBA and say ADO code. However, it really don't matter. On application startup, you get the above connection string, check it against the linked table -- if same then do nothing. If different, then you re-link that one table. Thus you ONLY re-link one time if the folder been moved. And no matter where you move the folder? As long as you assume the Excel sheet is in the same folder as the access app, then you good to go. And as noted, you could add a sub folder say ExcelSheets to above. And once again, no matter where you move this folder with the Access part, as long as the sub folder is in the same dir/folder, then this will work - despite you not having relative addressing.

How do I override the Header for field naming?

Using SQL to query an Excel worksheet without a header row echos the information I have found in all my research. But that isn't what I am getting. Has there been a change in Excel 2016, or is my implementation wrong?
Sub vndrrst()
Dim cn As Object
Set cn = CreateObject("adodb.connection")
strfilename = ThisWorkbook.Path
cn.ConnectionString = _
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strfilename & _
";Extended Properties=""text;HDR=NO;imex=1"";"
cn.Open
Set rs = cn.Execute("select * from My_Text_File.txt where F2='04-62425'")
Set rs = Nothing
Set cn = Nothing
End Sub
The error message reads "No value given for one or more required parameters." at the Set rs statement. When I change F2 to MFGID (the actual field name given in the header of this text file), it both runs and gives accurate output in the debug window... even though HDR=No.
So, how can I use the F field names if the file has a header this time? The reason this becomes interesting is because I have many text/csv/delimited files sent to my FTP, some have headers, some don't, and some have headers sometimes.
Edit: the schema.ini file reads
[My_Text_File.txt]
Format=TabDelimited
in case it matters.
A different related question is ADO Recordset to Excel spreadsheet opens properly in Excel 2007, has a missing parameter in Excel 2013, but the motivation/project of the OP is different, and therefore the answer is irrelevant.

How to connect VBA to postgreSQL and run query

I am trying to run a query from an Microsoft excel application and have not been able to connect successfully.
I have PostgreSQL 9.3 on my local machine, and am running 64 bit windows 7. I have a sample database name dvdrental which is a demo database.
I simply need to connect to the database, run a query, and view the output in my worksheet(or immediate window, either one resolves the connection issue).
Here is what I have so far which is not working.
Option Explicit
Public objConnection As ADODB.Connection
Public strConnection As String
Public Sub TestPostgresConnection()
Dim strConnection As String
strConnection = "Driver={PostgreSQL Unicode};Server=localhost;Port=5432; Database=dvdrental;UID=sa;PWD=wrox;"
Set objConnection = New ADODB.Connection
Set objRecordSet = New ADODB.Recordset
objConnection.Open strConnection
With objRecordSet
.ActiveConnection = objConnection
.Open "SELECT * FROM actor"
End With
Do While Not objRecordSet.EOF
Debug.Print objRecordSet.Fields(0).Value
objRecordSet.MoveNext
Loop
objRecordSet.Close
objConnection.Close
Set objRecordSet = Nothing
Set objConnection = Nothing
End Sub
Here is a list of my references;
Visual Basic For Applications
Microsoft Excel 14.0 Object Library
OLE Automation
Microsoft Office 14.0 Object Library
Microsoft Forms 2.0 Object Library
Microsoft Access 14.0 Object Library
Microsoft ADO Ext. 6.0 for DOL and Security
Microsoft ActiveX Data Objects 2.8 Library
Microsoft Windows Common Confrols 6.0 (SP6)
When I execute this test method TestPostgresConnection, I get "[Miscrosoft][ODBC Driver Manager] Data source name not found and no default driver specified"
My setup of postgres has been standard and I have simply followed the directions on their website for creating a local RDBMS for testing.
Can anyone tell me why I am not able to connect and run a query?
None of the solutions have worked so far. Thanks.
My answer is a general answer. Giving back to the community. So be nice. I had a similar question and I used the following to set it up.
Note: I suggest using DSN instead of the driver then you can use a named connection that has the password already, rather than having the password in your code.
These instructions were a huge help generally:
http://www.dashbay.com/2011/03/working-with-postgres-on-windows-via-odbc/
The download link in the link above didn't work for me. I found the ODBC downloads here:
https://www.postgresql.org/ftp/odbc/versions/msi/
I think I downloaded this one:
psqlodbc_09_05_0400-x86.zip
I used Konstantin's answer to get %WINDIR%\SysWOW64\odbcad32.exe from this link:
PostgresSQL ODBC Drivers on Windows 7 not showing up
I also downloaded MS Power Query here which I found helpful:
https://www.microsoft.com/en-us/download/details.aspx?id=39379
I am happy to edit my answer if I should add clarification.
Below is the sub for the query and below that is a sub that demonstrates how you use it.
Sub CcQueryPg(sSql As String, Optional sOdbcName As String = "ConnectionNameHere")
'Declare a Connection object
Dim cnDB As New ADODB.Connection
'Declare a Recordset Object
Dim rsRecords As New ADODB.Recordset
'Open the ODBC Connection using this statement
cnDB.Open sOdbcName
rsRecords.Open sSql, cnDB
'Close everything and set the references to nothing
rsRecords.Close
Set rsRecords = Nothing
cnDB.Close
Set cnDB = Nothing
End Sub
Sub SendQuery()
Call CcQueryPg("COPY sometablenamehere FROM '/mnt/somepathhere/somefilename.csv' DELIMITER ',' CSV HEADER;")
End Sub
The above file reference is to a file on a Linux machine. Your path format may differ.

Are Access 2010 databases not accessible with Excel if password protected using default encryption (High Security)?

I am currently supporting an Excel 2010 spreadsheet and Access 2010 database that were written by business users. One of the requirements of the Access database is that it be encrypted. It was encrypted with the default encryption settings "Use default encryption(Higher security)" which can be set in Options -> Client Settings.
Now that the database is password protected and encrypted, I am unable to connect to the database through Excel. My testing revolves around importing data into Excel, but what I really need to do is create a row in a log table. I am trying both to import directly to the sheet using the "Data" tab and "From Access" selection and through VBA code. Using the Excel interface, the password dialog box comes up and will never accept the correct password. Using VBA and ADO, the Open statement throws a "not a valid password" error. Both methods work fine if I encrypt the database using the "Use legacy encryption" setting.
I thought it also may be my setup, I'm using Windows 7 32-bit and Office 2010. I have also tried with Windows 8.1 64-bit using Office 2013 with the same results. It works with legacy encryption, but not with default encryption. I didn't try anything earlier. The default higher security encryption was introduced with Office 2010 and Windows 7.
My research has led me to this Technet thread and this Stackoverflow question, both suggesting that Excel cannot interact with Access using the default encryption method. I haven't found a whole lot more discussing this exact issue.
My question to you is does password protecting an Access 2010 database using the default settings really prevent Excel 2010 from importing data (when using the password)? Something about that doesn't sound right to me since sharing data between the two applications is a pretty basic function. I also think that if it were an issue, Google would have turned up more information about it. My guess at this point is that Excel and Access are using the Next Generation encryption engine by default, but that the ADO library has not been updated to use it.
I've attached the connection code for review. For testing I am doing a simple Now() command and emitting the results. The connection fails on the open with a "not a valid password" error even when using the correct password. Works with legacy encryption, not with default encryption.
Sub ADOCNGConnect()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim ds As String
'setting up connection
Set cn = New ADODB.Connection
With cn
.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source='FILEPATH'" & _
";Jet OLEDB:Database Password=password"
.Open
End With
'setup recordset object
Set rs = New ADODB.Recordset
'retrieve new number
rs.Open "SELECT Now() AS qryTest", cn, adOpenKeyset
MsgBox rs!qryTest
rs.MoveLast
'close ADO object vars
rs.Close: Set rs = Nothing
cn.Close: Set cn = Nothing
End Sub
According to ConnectionStrings.com, the ACE provider doesn't work with the new stronger Access 2010 db encryption:
"Note! Reports say that a database encrypted using Access 2010 - 2013 default encryption scheme does not work with this connection string. In Access; try options and choose 2007 encryption method instead. That should make it work. We do not know of any other solution."
However, that doesn't tell the whole story. Your code worked as an Access VBA procedure and successfully connected to another ACCDB which had the stronger Access 2010 encryption. But I could not find any way to make similar code work as an Excel VBA procedure.
Eventually I abandoned that effort. Since your goal seems to be to make an ADO recordset containing Access data available to Excel, I decided to automate Access and use its CurrentProject.Connection.Execute method to load the recordset.
This may seem kind of clunky, but it works ...
Const cstrPath As String = "C:\Users\hans\Documents\a2010_DbPass_foo.accdb"
Const cstrPwd As String = "foo"
Dim objAccess As Object ' Access.Application
Dim rs As Object ' ADODB.Recordset
Dim strSelect As String
Set objAccess = CreateObject("Access.Application")
objAccess.Visible = True
objAccess.OpenCurrentDatabase cstrPath, , cstrPwd
'strSelect = "SELECT Now() AS qryTest"
strSelect = "SELECT some_text AS qryTest FROM tblFoo"
Set rs = objAccess.CurrentProject.Connection.Execute(strSelect)
MsgBox rs!qryTest
rs.Close
Set rs = Nothing
objAccess.Quit
Set objAccess = Nothing
Note when I used "SELECT Now() AS qryTest" for strSelect, Access crashed at .Quit I don't understand why that happened. But the code worked trouble-free in Excel 2010 as written.