Examining MS Access Database Keys using VB6 - ms-access

how to check how many primary key, composite key in existing table using Visual basic 6.0 and ms access as a database?

One table have only one primary key, that may be simple or composite key.

Add reference ADOX and ADODB library.
Function ShowKeys(tbl As String) As String
'Add reference ADOX library: Microsoft ADO Ext. 2.8 for DDL and Security.
'Add reference ADODB library: Microsoft ActiveX Data Objects
Dim cat As New ADOX.Catalog
Dim tbl As ADOX.Table
Dim idx As ADOX.Index
Dim col As ADOX.Column
Dim cnn As New ADODB.Connection
On Error GoTo errh
cnn.Open "Provider='Microsoft.Jet.OLEDB.4.0';" & _
"Data Source= 'Northwind.mdb';"
Set cat.ActiveConnection = cnn
For Each tbl In cat.Tables
If tbl.Name = tbl Then
If tbl.Indexes.Count <> 0 Then
For Each idx In tbl.Indexes
With idx
If .PrimaryKey Then
For Each col In .Columns
ShowKeys = col.Name & ", " & ShowKeys
Next
End If
End With
Next
End If
End If
Next
errh:
If Err <> 0 Then
MsgBox Err.Number & ": " & Err.Description, vbOKOnly, "Error"
End If
Set cat = Nothing
Set tbl = Nothing
Set idx = Nothing
Set col = Nothing
Set cnn = Nothing
End Function

Related

Create Access Database in Visual C++

Currently I need to find a method to create an Access database in Visual C++ 2008, so that:
I can create the Access database in different formats, including Access 95/97 format, 2000 format, and 2007 accdb format.
I can create not only tables, but also other objects, including queries, reports, forms and macros in the Access database.
When adding a large volume of records into the tables, the method has a better performance.
I have searched online, and have found resourced such as this which lists some methods, however, as far as I know, DAO seems to be deprecated.
How about the other methods?
Thanks
As I have understood, you want to create database, objects in it, via calling some function and procedures. Best approach to my mind is to use DAO Library. Here is VBScript example:
Sub CreateDatabaseFile(ByVal strDbPath)
Dim wspDefault 'As Workspace
Dim dbs ' As Database
Dim dbEngine ' DAO DB Engine
Dim dbLangGeneral
dbLangGeneral = ";LANGID=0x0409;CP=1252;COUNTRY=0"
Set dbEngine = CreateObject("DAO.DBEngine.120")
Set wspDefault = DBEngine.Workspaces(0)
Set dbs = wspDefault.CreateDatabase(strDbPath, dbLangGeneral)
Dim s
s="CREATE TABLE tblCustomers (CustomerID INTEGER CONSTRAINT PK_tblCustomers PRIMARY KEY, " _
& " [Last Name] TEXT(50) NOT NULL, [First Name] TEXT(50) NOT NULL, Phone TEXT(10), Email TEXT(50), " _
& " Address TEXT(40)) "
dbs.execute s
dbs.Close
Dim AccessApp
Set AccessApp = CreateObject("Access.Application")
AccessApp.OpenCurrentDatabase strDbPath
Dim frm 'As Form
Dim ctlLabel 'As Control
Dim ctlText 'As Control
Dim intDataX 'As Integer, intDataY As Integer
Dim intDataY
Dim intLabelX 'As Integer, intLabelY As Integer
Dim intLabelY
' Create new form with tblCustomers table as its record source.
Set frm = AccessApp.CreateForm
'frm.Name = "MyForm"
frm.RecordSource = "tblCustomers"
' Set positioning values for new controls.
intLabelX = 100
intLabelY = 100
intDataX = 1000
intDataY = 100
' Create unbound default-size text box in detail section.
Dim acTextBox
acTextBox = 109
Set ctlText = AccessApp.CreateControl(frm.Name, acTextBox, , "", "", _
intDataX, intDataY)
ctlText.ControlSource = "Last Name"
Dim acLabel
acLabel = 100
' Create child label control for text box.
Set ctlLabel = AccessApp.CreateControl(frm.Name, acLabel, , _
ctlText.Name, "NewLabel", intLabelX, intLabelY)
Dim acButton
AccessApp.DoCmd.Save, frm.Name
' Restore form.
AccessApp.DoCmd.Restore
AccessApp.DoCmd.Quit
End Sub
Call CreateDatabaseFile("c:\test\a test database file.mdb")

How can I get the value from a control using the name of the control source?

I am trying to write some code to audit changes made via a form. I have a function that works to do this:
Function WriteChanges()
Dim f As Form
Dim c As Control
Dim user As String
Dim db As DAO.Database
Dim cnn As ADODB.Connection
Dim MySet As ADODB.Recordset
Dim tbld As TableDef
Dim recsource As String
Set f = Screen.ActiveForm
Set db = CurrentDb
Set cnn = CurrentProject.Connection
Set MySet = New ADODB.Recordset
recsource = f.RecordSource
Set tbld = db.TableDefs(recsource)
pri_key = fFindPrimaryKeyFields(tbld)
Debug.Print "pri_key: "; pri_key
user = Environ("username")
MySet.Open "Audit", cnn, adOpenDynamic, adLockOptimistic, adCmdTable
For Each c In f.Controls
Select Case c.ControlType
Case acTextBox, acComboBox, acListBox, acOptionGroup
If c.Value <> c.OldValue Then
With MySet
.AddNew
![EditDate] = Now
![user] = user
![SourceTable] = f.RecordSource
![SourceField] = c.ControlSource
![BeforeValue] = c.OldValue
![AfterValue] = c.Value
.update
End With
End If
End Select
Next c
MySet.Close
Set MySet = Nothing
Set f = Nothing
Set db = Nothing
End Function
I use this function on the before update property of various forms and it populates the Audit table with the details of the changes to values in each of the controls. I need to also get the value from the primary key field to add to the Audit table. I can use the following code to identify the name of the primary key within the form's record source:
Function fFindPrimaryKeyFields(tdf As TableDef) As String
Dim idx As Index
On Error GoTo HandleIt
For Each idx In tdf.Indexes
If idx.Primary Then
fFindPrimaryKeyFields = Replace(idx.Fields, "+", "")
GoTo OutHere
End If
Next idx
OutHere:
Set idx = Nothing
Exit Function
HandleIt:
Select Case Err
Case 0
Resume Next
Case Else
Beep
MsgBox Err & " " & Err.Description, vbCritical + vbOKOnly, "Error"
fFindPrimaryKeyFields = vbNullString
Resume OutHere
End Select
End Function
How can I use this to get the value from the control (text box) that has the identified primary key as its control source.
Please forgive any silly errors in my code as I'm a relative novice. Thanks in advance for any help.
I'm not 100% sure what you want exactly, but if you have the name of the field, you can use the following:
Dim primaryKeyValue As Variant
Dim primaryKeyColumnName As String
primaryKeyColumnName = fFindPrimaryKeyFields(TableDefs!MyTable)
Dim f as Form
'Get the form somehow
Dim c As Control
On Error GoTo NextC 'Escape errors because lots of controls don't have a control source
For Each c In f.Controls
If c.ControlSource = primaryKeyColumnName Then
primaryKeyValue = c.Value
End If
NextC:
Next c
On Error GoTo 0
If the primary key column is part of the form record source, you can simply read it by:
Debug.Print "PK value: " & f(pri_key)
Every column of the record source is a form property at runtime, independent of whether there is a control with the same name.
Note: your whole construct will stop working if you have a form that is based on a query that joins multiple tables.

How do I programmatically retrieve the values from a linked table's property sheet?

I am working in MS Access. All the tables and views are linked to a SQL Server database. I want to write a procedure that will retrieve and store all of the formatting information about these objects. A lot of this information is available from the property sheet (I open a table in Design View, and hit F4 for the property sheet). Eg:
Filter
Order By
Filter On Load
Order by On Load
Order by On
How do I retrieve these properties programmatically? I only see them listed for Reports.
Note that I need to retrieve the values, not just set them. I know about the SetFilter method, and that's not what I need.
The linked table exists as a DAO.TableDef in your database's TableDefs collection. So you can check the TableDef.Properties collection for those 5 properties.
However beware that both Filter and OrderBy are user-created instead of default properties, which means they are not included in the Properties collection unless you've assigned them values. Attempting to retrieve one which doesn't exist triggers error 3270, "Property not found". You can trap that error, respond to it as you wish, and continue on for the other properties you're interested in. Or you could first determine whether the property exists and only attempt to retrieve its value when it does exist.
This code sample uses the first approach (trap the error):
Const cstrTable As String = "YourLinkedTableNameHere"
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim strMsg As String
Dim varProp As Variant
Dim varProperties As Variant
On Error GoTo ErrorHandler
varProperties = Array("Filter", "FilterOnLoad", "OrderBy", _
"OrderByOn", "OrderByOnLoad")
Set db = CurrentDb
Set tdf = db.TableDefs(cstrTable)
For Each varProp In varProperties
Debug.Print varProp, tdf.Properties(varProp).Value
Next
ExitHere:
Exit Sub
ErrorHandler:
Select Case Err.Number
Case 3270 ' Property not found.
strMsg = "Property '" & varProp & "' not found."
'MsgBox strMsg
Debug.Print strMsg
Resume Next
Case Else
strMsg = "Error " & Err.Number & " (" & Err.Description & ")"
MsgBox strMsg
Resume ExitHere
End Select
How about something like this? (I've defined "table2" to have two fields, "PropertyName" and "PropertyValue"..."table1" is a placeholder for any of your existing tables)
Dim i As Integer
Dim j As Integer
Dim RS As DAO.Recordset
On Error Resume Next
Set RS = CurrentDb.OpenRecordset("select * from table2")
j = CurrentDb.TableDefs("table1").Properties.Count
For i = 0 To j - 1
RS.AddNew
RS!PropertyName = CurrentDb.TableDefs("table1").Properties(i).Name
RS!PropertyValue = Nz(CurrentDb.TableDefs("table1").Properties(i).Value, "-")
RS.Update
Next i

MS Access Metadata

I'm performing a data cleansing operation on an access database. I have several duplicate records in a table that I want to consolidate down into one single record. In doing this I will need to update all references to the records that I will be consolidating.
If I know the column name that holds the record id is there a way to find all of the tables in access that contain this column?
You can examine the TableDefs collection and determine which tables contain a field with a given name.
Public Sub TablesWithField(ByVal pName As String)
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim strMsg As String
Dim strName As String
On Error GoTo ErrorHandler
Set db = CurrentDb
For Each tdf In db.TableDefs
strName = vbNullString
'ignore system and temporary tables '
If Not (tdf.name Like "MSys*" Or tdf.name Like "~*") Then
strName = tdf.Fields(pName).name
If Len(strName) > 0 Then
Debug.Print tdf.name & ": " & pName
End If
End If
Next tdf
ExitHere:
On Error GoTo 0
Set tdf = Nothing
Set db = Nothing
Exit Sub
ErrorHandler:
Select Case Err.Number
Case 3265 'Item not found in this collection. '
Resume Next
Case Else
strMsg = "Error " & Err.Number & " (" & Err.description _
& ") in procedure TablesWithField"
MsgBox strMsg
GoTo ExitHere
End Select
End Sub
Short answer: Yes. And there are many ways to skin that cat. Two ideas:
(1) Via VBA, make use of: Application.CurrentDb.TableDefs(i).Fields(j).Name
(2) Via Tools==>Analyze==>Documenter, make a report and then search its output (Publish it with MS Word).
Sorry, but Access isn't built like MS SQL Server or DB2 - the MSys* tables really aren't set up for querying table schemas like that. However, others have VBA based solutions that look useful.
You can use Schemas, not exactly a query, but similar:
Function ListTablesContainingField(SelectFieldName) As String
'Tables returned will include linked tables
'I have added a little error coding. I don't normally do that
'for examples, so don't read anything into it :)
Dim cn As New ADODB.Connection
Dim rs As ADODB.Recordset
Dim strTempList As String
On Error GoTo Error_Trap
Set cn = CurrentProject.Connection
'Get names of all tables that have a column called <SelectFieldName>
Set rs = cn.OpenSchema(adSchemaColumns, _
Array(Empty, Empty, Empty, SelectFieldName))
'List the tables that have been selected
While Not rs.EOF
'Exclude MS system tables
If Left(rs!Table_Name, 4) <> "MSys" Then
strTempList = strTempList & "," & rs!Table_Name
End If
rs.MoveNext
Wend
ListTablesContainingField = Mid(strTempList, 2)
Exit_Here:
rs.Close
Set cn = Nothing
Exit Function
Error_Trap:
MsgBox Err.Description
Resume Exit_Here
End Function

How to save an ADO recordset into a new local table in Access 2003?

I'm trying to import tables from a FoxPro 9.0 database into Access 2003. So far, from Google searches and many trials, the only way for me to connect to the tables is through an OLE DB connection programatically. I have set up 3 ODBC connections with different configurations but none of them work: I get "unspecified errors" that I can't find any information on.
With OLE DB I can succesfully connect to the FoxPro database, and import tables in ADO recordsets. The problem is that I can't save the recordset into new table in the local database using SQL. The ADO recordsets behave differently than tables, so I can't query them. The code below gives me a "type mismatch" error at DoCmd.RunCommand ("select * from " & rst & " INTO newClients").
Sub newAdoConn()
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim strSQL As String
Dim decision As Integer
Set cnn = New ADODB.Connection
cnn.ConnectionString = "Provider=vfpoledb;" & _
"Data Source=s:\jobinfo\data\jobinfo.dbc;" & _
"Mode=ReadWrite|Share Deny None;" & _
"Collating Sequence=MACHINE;" & _
"Password=''"
strSQL = "Select * from Jobs"
cnn.Open
Set rst = cnn.Execute("Select * from clients")
If rst.EOF = False Then
Do While Not rst.EOF
decision = MsgBox(rst.Fields!ID & " " & rst.Fields!fname & " " & rst.Fields!lname & vbCrLf & vbCrLf & "Continue?", vbYesNo)
If decision = vbYes Then
rst.MoveNext
Else
Exit Do
End If
Loop
End If
DoCmd.RunCommand ("select * from " & rst & " INTO newClients")
rst.Close
Set rst = Nothing
cnn.Close
Set cnn = Nothing
End Sub
I finally worked out a decent solution. It involves saving the ado recordset from memory to an excel file using the copyFromRecordset function, and then linking the file programmatically to a table in excel using the TransferSpreadsheet()...
Sub saveToExcel()
Dim cnn As ADODB.Connection
'declare variables
Dim rs As ADODB.Recordset
Dim strSQL As String
Dim decision As Integer
Dim colIndex As Integer
' Dim fso As New FileSystemObject
' Dim aFile As File
'set up connection to foxpro database
Set cnn = New ADODB.Connection
cnn.ConnectionString = "Provider=vfpoledb;" & _
"Data Source=s:\jobinfo\data\jobinfo.dbc;" & _
"Mode=ReadWrite|Share Deny None;" & _
"Collating Sequence=MACHINE;" & _
"Password=''"
cnn.Open
Set rs = cnn.Execute("Select * from clients")
'Create a new workbook in Excel
Dim oExcel As Object
Dim oBook As Object
Dim oSheet As Object
Set oExcel = CreateObject("Excel.Application")
Set oBook = oExcel.Workbooks.Add
Set oSheet = oBook.Worksheets(1)
oSheet.Name = "clients"
' Copy the column headers to the destination worksheet
For colIndex = 0 To rs.Fields.Count - 1
oSheet.Cells(1, colIndex + 1).Value = rs.Fields(colIndex).Name
Next
'Transfer the data to Excel
oSheet.Range("A2").CopyFromRecordset rs
' Format the sheet bold and auto width of columns
oSheet.Rows(1).Font.Bold = True
oSheet.UsedRange.Columns.AutoFit
'delete file if it exists - enable scripting runtime model for this to run
'If (fso.FileExists("C:\Documents and Settings\user\Desktop\clients.xls")) Then
' aFile = fso.GetFile("C:\Documents and Settings\user\Desktop\clients.xls")
' aFile.Delete
'End If
'Save the Workbook and Quit Excel
oBook.SaveAs "C:\Documents and Settings\user\Desktop\clients.xls"
oExcel.Quit
'Close the connection
rs.Close
cnn.Close
MsgBox ("Exporting Clients Done")
'link table to excel file
DoCmd.TransferSpreadsheet acLink, acSpreadsheetTypeExcel5, "clientsTest", "C:\Documents and Settings\user\Desktop\clients.xls", True
End Sub
What you will have to do is open the FoxPro table as a recordset and open the local table as another recordset. You can then loop through the FoxPro recordset and do something like this
Do until FoxProRst.EOF
LocatRst.AddNew
LocalRst!SomeField1=FoxProRst!SomeField1
LocalRst!SomeField2=FoxProRst!SomeField2
LocalRst!SomeField3=FoxProRst!SomeField3
LocalRst.Update
FoxProRst.MoveNext
Loop
It might not be the quickest way but it will work
Let me just sketch another approach with SQL queries, that could simplify:
'...
'not required for first time test:
'cnn.Execute("DROP TABLE MyNewTable")
'...
'create the new table in the destination Access database
cnn.Execute("CREATE TABLE MyNewTable (MyField1 int, MyField2 VARCHAR(20), MyField3 Int)")
'insert data in the new table from a select query to the original table
Dim sSQL as string, MyOriginalDBPath as String
sSQL = "INSERT INTO MyNewTable (MyField1, MyField2, MyField3) SELECT OriginalField1, OriginalField2, OriginalField3 FROM [" & MyOriginalDBPath & ";PWD=123].clients"
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
rs.Open sSQL, cnn, adOpenForwardOnly, adLockReadOnly, adCmdText
'...
Note: this 'draft' idea assumes that the connection string is made to the Access database and the connection to the original database would be inside the SQL string, but i have not idea about the correct sintaxis. I have only tested this approach with different access databases.
Note that this is for Access: ...[" & MyOriginalDBPath & ";PWD=123]...
The Jet database engine can reference external databases in SQL statements by using a special syntax that has three different formats:
[Full path to Microsoft Access database].[Table Name]
[ISAM Name;ISAM Connection String].[Table Name]
[ODBC;ODBC Connection String].[Table Name]
...
You can use an ODBC Data Source Name (DSN) or a DSN-less connection string:
DSN: [odbc;DSN=;UID=;PWD=]
DSN-less: [odbc;Driver={SQL Server};Server=;Database=;
UID=;PWD=]
Some references:
Querying data by joining two tables in two database on different servers
C# - Join tables from two different databases using different ODBC drivers
Why not use ODBC to link to the table? http://support.microsoft.com/kb/225861