I Have a database that many people across my workplace have excel files with linked tables etc.
There are times where it is critical I have exclusive access to the DB and it is not feasible to track down hundreds of possible excel files with links that do not properly break and revamp them; especially when people are makign new files all the time.
I found the following code that allows me to see whether someone is connected o the front end of the database:
Sub ShowUserRosterMultipleUsers()
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim i, j As Long
Set cn = CurrentProject.Connection
' The user roster is exposed as a provider-specific schema rowset
' in the Jet 4.0 OLE DB provider. You have to use a GUID to
' reference the schema, as provider-specific schemas are not
' listed in ADO's type library for schema rowsets
Set rs = cn.OpenSchema(adSchemaProviderSpecific, _
, "{947bb102-5d43-11d1-bdbf-00c04fb92675}")
'Output the list of all users in the current database.
Debug.Print rs.Fields(0).Name, "", rs.Fields(1).Name, _
"", rs.Fields(2).Name, rs.Fields(3).Name
While Not rs.EOF
Debug.Print rs.Fields(0), rs.Fields(1), _
rs.Fields(2), rs.Fields(3)
rs.MoveNext
Wend
End Sub
is there any code that will do the same thing as this to give me back end connections? As in who has an open excel file that is linked and locking the DB to Read- Only?
1) You can open a connection to any database. You've used "CurrentProject.Connection", but you can use:
set cn=Server.CreateObject("ADODB.Connection")
cn.Provider="Microsoft.Jet.OLEDB.4.0"
cn.Open "c:/webdata/northwind.mdb"
2) If method (1) is not suitable, you can use ODBC to query WMI and get a list of everyone connected to any particular file.
Related
Hi I currently have two worksheets in an excel file with one of them acting as a database of all the products we sell, with the columns Product ID, Product Code, and Description (sample below).
I have another worksheet that acts as a product finder tool, where you would paste multiple Product IDs in the first column and it would return the Product code and Description in the adjacent columns (image below).
I currently use an INDEX search to make this happen, but the database sheet has become too big to manage in the same file, leading to severe slow downs. What would be the easiest solution for this? I was thinking of separating the database sheet as an Excel or AccessDB file but I think I will need a lot of VBA manipulation if I do that. Any help would be much appreciated.
You can access your data in Microsoft Access using ADO and doing a SQL query to gather data.
Could you tell me if it's possible to give a cell range to the WHERE clause?
Yes, there is a trick. SQL commands are plain text, you just need to build it with your parameters. Use the operator IN in the WHERE clause.
I made a fake dataset as example. Here's my Excel Product Finder (a table named Table1):
Notice I want the info only of products 6,3 and 2. Now my fake database:
The code to query those specific products:
Sub TEST()
Dim cnn As Object
Dim RST As Object
Dim DatabasePath As String
Dim i As Long
Dim Allid As String
Dim Arrayid As Variant
Dim SQLQuery As String
DatabasePath = "C:\Temp\temp.accdb" 'path to database
'Create a connection object.
Set cnn = CreateObject("ADODB.Connection")
'Create recordset object
Set RST = CreateObject("ADODB.Recordset")
'Open a connection using the OLE DB connection string.
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DatabasePath & ";Persist Security Info=False;"
'merge all ID into one single string
Arrayid = Range("Table1[PRODUCT ID]").Value
For i = LBound(Arrayid) To UBound(Arrayid) Step 1
Allid = Allid & Arrayid(i, 1) & ","
Next i
Allid = Left(Allid, Len(Allid) - 1) 'get rid of last comma
Erase Arrayid 'clean array variable
'specify query
SQLQuery = "SELECT PRODUCT_TABLE.[Product Id], PRODUCT_TABLE.[Product Code], PRODUCT_TABLE.Description FROM PRODUCT_TABLE " & _
"WHERE PRODUCT_TABLE.[Product Id] In (" & Allid & ") ORDER BY PRODUCT_TABLE.[Product Id]"
'Open a recordset using the Open method
'and use the connection established by the Connection object.
RST.Open SQLQuery, cnn
'copy all data into cells. This will bring full query without headers
Range("A6").CopyFromRecordset RST
'close and clean variables
RST.Close
cnn.Close
Set RST = Nothing
Set cnn = Nothing
End Sub
After executing code I get this:
NOTICE that the output is not sorted as we had before. We asked the products in order 6,3,2 but the output is 2,3,6!
This is because my SQL query got the operator ORDER BY that sorts by ID field. If there is no ORDER BY clause the output will be sorted as it is in the database stored, not as your Excel.
If you really really really need the output to be exactly in the same order that your Product Finder, you can create an UDF function to query each single id once and return a single row for each product but if you work with a lot of data this can consume a lot of time. So think carefully how to approach this part.
By the way, make sure you use the right connection string. You can find many on Access connection strings
Is there any way to link tables in an Access database to Excel without importing the entire table? I need to reference/lookup cells in the Access table but don't want to import the whole table into the excel workbook (tables are too big).
My second option is to export the Access tables into a separate excel workbook, then just reference this new workbook instead of the Access database itself. When I try to do this only around 65,000 rows of data from any Access table actually export to Excel, as the rest 'couldn't be copied to the clipboard'. Is there a simple way around this? (I want to actually have a connection between the excel/access files, so the data can be refreshed, not just copy and paste the rows over)
See this ancient article, which should help you get the data you actually need rather than everything:
http://dailydoseofexcel.com/archives/2004/12/13/parameters-in-excel-external-data-queries/
You can work with Access database tables from Excel without importing the table into an Excel worksheet:
Dim cnn As ADODB.Connection ' Needs a reference to the Microsoft ActiveX
Dim rs As ADODB.Recordset ' Data Objects Library
Set cnn = CreateObject("ADODB.Connection")
cnn.Open "DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=database-path\Data.accdb;"
Set rs = cnn.Execute("SELECT * FROM MyTable")
While Not rs.EOF
Debug.Print rs(1)
rs.MoveNext
Wend
You may need the Microsoft Access Database Engine 2010 Redistributable which you should install with the /passive option if you are using a x86 Access version on a x64 OS.
Try the following script. This should give you what you want.
Option Compare Database
Private Sub Command0_Click()
Dim InputFile As String
Dim InputPath As String
InputPath = "C:\your_path_here\Desktop\"
InputFile = Dir(InputPath & "*.xlsx")
Do While InputFile <> ""
DoCmd.TransferSpreadsheet acLink, , InputFile, InputPath & InputFile, True '< The true is for column headers
InputFile = Dir
Loop
End Sub
I want to run recursively through a directory of *.mdb files and search them to see which ones have a specific linked table.
These files are secured using several *.mdw files. I did not write any of them, but I am their maintainer.
I've found a way to do this, but it's too interactive; I need it to be non-interactive; since some of these *.mdbs I'm searching use an Autoexec macro.
From what I understand executing an Autoexec macro can be avoided if one holds the SHIFT key while opening them; however I use the command line in my macro to open these files, and there doesn't seem to be a way to hold the shift key.
I've found another example, which does allow you to hold down the shift key to avoid the Autoexec macro (see Bypassing Startup Settings When Opening a Database), but which does not allow you to unlock the database with an *.mdw file, because the OpenCurrentDatabase() method does not have a parameter for an *.mdw file
If your goal is simply to check whether a db file contains a specific linked table, you can use the ADO OpenSchema method. With that approach, you don't need to open the db file in an Access application session, so the AutoExec macro does not run.
Below is an example using late binding. I left comment notes in case you prefer early binding. Change the Provider if your Access version is older than 2007.
Since you're using Access user-level security, you will also have to adapt the connection string to include the path to your MDW and supply the Access security user name and password. Here is an example connection string (using the Jet 4 provider) from ConnectionStrings.com. I split the single-line string on the semicolons for readability:
Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=C:\mydatabase.mdb;
Jet OLEDB:System Database=system.mdw;
User ID=myUsername;
Password=myPassword;
Public Function HasLinkedTable(ByVal pDb As String, _
ByVal pTable As String) As Boolean
Const adSchemaTables = 20&
Dim cn As Object ' ADODB.Connection
Dim rs As Object ' ADODB.Recordset
Dim strConnect As String
Dim blnReturn As Boolean
strConnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & pDb & ";"
'Set cn = New ADODB.Connection
Set cn = CreateObject("ADODB.Connection")
cn.Open strConnect
Set rs = cn.OpenSchema(adSchemaTables)
With rs
Do While Not .EOF
If !TABLE_NAME = pTable And !TABLE_TYPE = "LINK" Then
'Debug.Print !TABLE_NAME, !TABLE_TYPE
blnReturn = True
Exit Do
End If
.MoveNext
Loop
.Close
End With
cn.Close
Set cn = Nothing
HasLinkedTable = blnReturn
End Function
I'm working on an excel application that requires a database back end. My preference is to use SQLite 3 and to make this as seamless and portable as possible for the end user.
Recently I have learned that an Excel 2007 file is simply a zip archive with a xlsm extension. My question is this, can I store my back-end SQLite 3 database in the Zip archive and use ODBC to interact with the database. If so, can anyone point me to some background information, articles, guidance on achieving this objective. Are there any downsides to this approach or a better alternative I should know about.
Thanks for your input.
Some notes. So far, no one has complained that the file does not open. Note that the Excel file is saved before the ADO code is run.
Very hidden:
ThisWorkbook.Worksheets("Courses").Visible = xlVeryHidden
ThisWorkbook.Worksheets("System").Visible = xlVeryHidden
A snippet of code:
Const gCN = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
<...>
Set rs = CreateObject("ADODB.Recordset")
Set cn = CreateObject("ADODB.Connection")
Set fs = CreateObject("Scripting.FileSystemObject")
scn = gCN & ThisWorkbook.FullName _
& ";Extended Properties=""Excel 8.0;HDR=Yes;"";"
cn.Open scn
''If they do not have an ID, they do not exist.
sSQL = "SELECT ID,FirstName,LastName, " _
& "CourseName,AdditionalText,Format(ExpiryDate,'dd/mm/yyyy') As ExpiryDate " _
& "FROM [Applicants$] WHERE DateCancelled Is Null AND ID Is Not Null " _
& "AND (FirstName Is Null OR LastName Is Null Or CourseName Is Null " _
& "Or ExpiryDate Is Null) " & sWhere
rs.Open sSQL, cn
References:
Excel ADO
Connection strings
Most of the methods available to Jet can be used with Excel
Fundamental Microsoft Jet SQL for Access 2000
Intermediate Microsoft Jet SQL for Access 2000
Advanced Microsoft Jet SQL for Access 2000
Edit re Comments
I did not find the leak particularly bad, but I did not run many iterations, and this is quite a good machine.
The code below uses DAO, which does not cause a memory leak.
'Reference: Microsoft Office 12.0 Access Database Engine Object Library
Dim ws As DAO.Workspace
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim sDb As String
Dim sSQL As String
sDb = ActiveWorkbook.FullName
Set ws = DBEngine.Workspaces(0)
Set db = ws.OpenDatabase(sDb, False, True, "Excel 8.0;HDR=Yes;")
sSQL = "SELECT * FROM [Sheet1$];"
Set rs = db.OpenRecordset(sSQL)
Do While Not rs.EOF
For i = 0 To rs.Fields.Count - 1
Debug.Print rs.Fields(i)
Next
rs.MoveNext
Loop
rs.Close
db.Close
ws.Close
'Release objects from memory.
Set rs = Nothing
Set db = Nothing
Set ws = Nothing
Acknowledgement: http://www.ozgrid.com/forum/showthread.php?t=37398
Here is an alternative.
1) At Open (EVENTs in VBA) unzip from Excel .xlsm, sqlite and dbFile.
2) Process what you .....
3) At save (EVENTs in VBA) the book an then attach the Excel .xlsm ,sqlite , dbFile in Excel .xlsm.
Excel rewrites the file every time it is saved, so your own added file would be deleted.
Furthermore, there is no SQLite driver that can access database files inside of zip archives.
You would have either to ship the database file alongside with the Excel file, or to recreate the database with a list of SQL commands when your application detects that the DB file is missing.
This still requires that some SQLite (ODBC) driver is installed on the user's machine.
The most seamless and portable way to store data in an Excel file is to store it in an Excel sheet, as mentioned by Remou. However, it's possible that the ADO driver will refuse to open the file when it's already open in Excel, so that you have to use Excel functions to access the data.
Try using http://code.google.com/p/pyinex/
this embed the Python interpreter in Excel
Hey all, have been working on designing a new database for work. They have been using Excel for their daily reports and all the data is stored in there, so I decided to have the back-end of the database in Access and the front-end in Excel, so any analytical work can be easily performed once all the data has been imported into Excel.
Now I'm fairly new to VBA, slowly getting used to using it, have written some code to transfer one of the calculated tables from Access to Excel:
Option Explicit
Public Const DataLocation As String = "C:\Documents and Settings\Alice\Desktop\Database\TestDatabase21.accdb"
Sub Market_Update()
Call ImportFromAccessTable(DataLocation, "Final_Table", Worksheets(2).Range("A5"))
End Sub
Sub ImportFromAccessTable(DBFullName As String, TableName As String, TargetRange As Range)
Dim cn As ADODB.Connection, rs As ADODB.Recordset, intColIndex As Integer
Set TargetRange = TargetRange.Cells(1, 1)
' open the database
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" & DBFullName & ";"
Set rs = New ADODB.Recordset
With rs
' open the recordset
' .Open TableName, cn, adOpenStatic, adLockOptimistic, adCmdTable
' all records
.Open "SELECT * FROM Final_Table", cn, , , adCmdText
' filter records
For intColIndex = 0 To rs.Fields.count - 1 ' the field names
TargetRange.Offset(0, intColIndex).Value = rs.Fields(intColIndex).Name
Next
TargetRange.Offset(1, 0).CopyFromRecordset rs ' the recordset data
End With
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
Sub Company_Information()
Dim companyName As String
On Error GoTo gotoError
companyName = Application.InputBox(Prompt:="Enter Company Name", _
Title:="Company Name", Type:=2)
Exit Sub 'Don't execute errorhandler at end of routine
gotoError:
MsgBox "An error has occurred"
End Sub
The above code works fine and pulls up the desired calculated table and places it in the right cells in Excel.
I've got two problems that I'm having trouble with; firstly I have some cell-formatting already done for the cells where the data is going to be pasted into in Excel; I want it to apply the formatting to the values as soon as they are pasted in Excel.
Secondly; I have an add-on for Excel which updates some daily Stock Market values; these values need to be transferred into Access at the end of each working day, to keep the database maintained, I tried some code but have been having some problems with it running.
The code for this part can be seen following:
Sub UPDATE()
Dim cnt As ADODB.Connection
Dim stSQL As String, stCon As String, DataLocation As String
Dim stSQL2 As String
'database path - currently same as this workbook
DataLocation = ThisWorkbook.Path & DataLocation
stCon = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & DataLocation & ";"
'SQL code for GL Insert to Access
stSQL = "INSERT INTO Historical_Stock_Data SELECT * FROM [Portfolio] IN '" _
& ThisWorkbook.FullName & "' 'Excel 8.0;'"
'set connection variable
Set cnt = New ADODB.Connection
'open connection to Access db and run the SQL
With cnt
.Open stCon
.CursorLocation = adUseServer
.Execute (stSQL)
End With
'close connection
cnt.Close
'release object from memory
Set cnt = Nothing
End Sub
I get the following error with this.
Run-time Error '-2147467259 (80004005)'
The Microsoft Jet database engine cannot open the file 'Cocuments and Settings\Alice\Desktop\Database'. It is already opened exclusively by another user or you need permission to view its data.
I'm fairly new to databases, VBA and Access so any help would be greatly appreciated.
Also I have been told that the above method of having an Excel front-end and Access back-end is not recommended but alot of the analysis they conduct is done through Excel, and the charts feature in Excel is much better than Access in my experience atleast; and that is also one of the requirements for this project.
Thank you advance!
Solution to your first problem:
Sorry to be the bearer of bad news, but your entire first module is unnecessary. Instead, try:
Go to Data->Import External Data->Import Data, select your Access file, select your table, and presto! done!
Right-click on your new "External Data Range" to see a number of options, some related to formatting. You can even keep the original cell formatting and just update the values. I do this all the time.
To update the Excel data table later, there is a "External Data Range" toolbar that allows you to refresh it as well as a "refresh all" option to refresh every table in the Excel file. (You can also automate this thru code. It'll take some trial and error, but you're definitely up to the task)
Regarding your second problem
I've never used it, but there is also a "New Web Query" option in there as well. I assume it can be manipulated and updated the same way.
And lastly
Your choice of the Excel front-end and the Access back-end sounds good for your needs. It gets the data to your analysts in a medium they are familiar with (Excel) while keeping the calculations out of the way in Access. Technically, you could try putting all your calculations in Excel, but that might the Excel file much bigger and slower to open.
Do the data entry/updating/reviewing in Access. One of Access' strengths is using forms that allow you to update the tables without any code. Then allow the users to easily export the data to Excel such as by clicking on some command buttons.
Modules: Sample Excel Automation - cell by cell which is slow
Modules: Transferring Records to Excel with Automation
nothing wrong in principle with the excel/access pairing. I'm not familiar with ADO (I use DAO), but your error message seems to be indicating that the path to the datasource is not fully formed; or you already have it opened and hence are locking it.