Inserting data to other xls workbook via ADO & SQL – Data type error - sql

I am building a quite complex UserForm that uses ADO connection to connect to another Excel workbook that serves as a database and retrieve & insert data via SQL queries. Please note I am not allowed to use Access in this case.
I have already figured out how to use SELECT, but there is one particular error with INSERT I can't resolve. That bothers me a lot, I've put a lot of work to it.
First the connection (I use JET for retrieving data and ACE for saving data as I was not able to get JET to work for that):
Public Sub InsertDataToSheet(SQLCmd As String)
Dim cnx As Object
Set cnx = CreateObject("ADODB.Connection")
cnx.Open "Provider=Microsoft.ACE.OLEDB.12.0; Data Source='" & ThisWorkbook.Path & "\Database.xls'; Extended Properties=Excel 12.0;"
cnx.Execute SQLCmd
cnx.Close
End Sub
Then there is a subroutine linked to a Submit button that actually generates the Query as I need to save only filled out Textboxes and Combos to avoid Nulls:
Private Sub SaveRecord()
Dim SQL As String
SQL = "INSERT INTO [Report$A2:AM50000] ("
Dim i As Control
For Each i In Me.controls
If TypeName(i) = "TextBox" Or TypeName(i) = "ComboBox" Then
If i <> e Then SQL = SQL & i.Name & ","
End If
Next i
SQL = Mid(SQL, 1, Len(SQL) - 1) & ") VALUES(" ' Remove last space & comma
Dim j As Control
For Each j In Me.controls
If TypeName(j) = "TextBox" Or TypeName(j) = "ComboBox" Then
If j <> e Then
If j = "Unknown" Then MsgBox "Fire"
Select Case IsNumeric(j)
Case False
SQL = SQL & "'" & j & "'" ' Add single quotes around strings
Case True
SQL = SQL & j
End Select
SQL = SQL & ","
End If
End If
Next j
SQL = Mid(SQL, 1, Len(SQL) - 1) & ")" ' Remove last comma
' Connect
InsertDataToSheet (SQL)
End Sub
There are two particular textboxes in the form that work exactly the same. Normally, users enter numbers to them and everything saves fine (don't mind the '+' buttons):
Sometimes, however, users do not know the values but can't leave those empty. That's when they are supposed to tick the checkboxes to set the value(s) to 'Unknown':
Now there comes the funny part – for the Batch field, it saves fine. But when I set the Shipment ID to 'Unknown' (or any other string), it throws an error:
Note the fields are not Disabled, just Locked with some appearance changes. I was also unable to find any specific details about the error, but it seems there is some problem with the query:
(It says something like 'Incompatible data types in the expression'). The generated query is this:
Any ideas what goes wrong? I'd very much like to keep the functionality as it is know and solve the error rather than redesign it as it already took some effort and the fields can't stay empty.

Never used sql in xls workbooks, but I had this problem with SQL server already. There's nothing "wrong" with your query, the problem is that data type that's accepted on the field of the table you want to insert. Try to turn that field to use text values instead of numbers and it should work.

Related

Can I open a recordset using application-level features (user-defined functions, form-based parameters) in Access?

I want users to be able to provide a query they made in the GUI, using a combo box, and then load that query into a recordset to do further processing on it. This fails if the query contains a user-defined function or form-based parameter.
My code looks like this:
Private Sub cmbSelectionColumn_AfterUpdate()
Dim r As DAO.Recordset
Set r = CurrentDb.OpenRecordset("SELECT DISTINCT " & EscapeSQLIdentifier(Me.cmbSelectionColumn.Value) & " FROM " & EscapeSQLIdentifier(Me.cmbSelectionTable.Value))
Do While Not r.EOF
'Do stuff
r.MoveNext
Loop
End Sub
Where cmbSelectionColumn is a user-selected column, and cmbSelectionTable is a user-selected table or query, and EscapeSQLIdentifier is a function that escapes and adds brackets to ensure the field and tablename are safe. This mostly works fine, but it fails in multiple cases, such as involving pass-through queries, user-defined functions, and form-based parameters.
Is there a way I can create a recordset from any query that works in Access, without having to worry about this?
Yes, there is, but you will have to do some trickery.
Forms support these queries just fine. And forms have a .RecordsetClone property that allows us to retrieve the recordset.
To allow us to retrieve the recordset from code, we're going to create a new blank form, and add a module to it (in fact, any form with a module will do). We'll name it frmBlank.
Then, we can adjust the code to use this form to retrieve the recordset.
Private Sub cmbSelectionColumn_AfterUpdate()
Dim r As DAO.Recordset
Dim frm As New Form_frmBlank
frm.RecordSource = "SELECT DISTINCT " & EscapeSQLIdentifier(Me.cmbSelectionColumn.Value) & " FROM " & EscapeSQLIdentifier(Me.cmbSelectionTable.Value)
Set r = frm.RecordsetClone
Do While Not r.EOF
'Do stuff
r.MoveNext
Loop
End Sub
This allows us to retrieve the recordset. The form will not pop up (since we haven't set .Visible to True), and will close once the code is done running since there is no active reference to it. I haven't yet seen any tables or queries that do work in Access, but do not work with this approach, and the performance penalty is minor. It does make for odd code and an odd blank form with blank module that will cause your database to malfunction when deleted.
The following may present an alternative approach to opening DAO recordsets which reference form-based parameters:
Dim db As DAO.Database
Dim pr As DAO.Parameter
Set db = CurrentDb
With db.CreateQueryDef("", "SELECT DISTINCT " & EscapeSQLIdentifier(Me.cmbSelectionColumn.Value) & " FROM " & EscapeSQLIdentifier(Me.cmbSelectionTable.Value))
For Each pr In .Parameters
pr.Value = Eval(pr.Name)
Next pr
With .OpenRecordset
If Not .EOF Then
.MoveFirst
Do Until .EOF
' Do stuff
.MoveNext
Loop
End If
.Close
End With
End With
Here, since references to objects outside of the scope of the query (such as references to form controls) become query parameters whose parameter name matches the original reference, the parameter name is evaluated to yield the value held by the form control, and the parameter value is then updated to the result of this evaluation.

Attempting to dynamically pass parameters to a stored procedure from excel 2013 calling DB2 mainframe

I have a requirement to dynamically pass parameter to a called SP which pulls data from the mainframe.
My excel connection string is:
DRIVER={IBM DB2 ODBC DRIVER};UID=k9751x1;PWD=********;MODE=SHARE;DBALIAS=RISCTEST;
The command text is:
call K9751DB.SP_GETRTSDB_BYDBTSNOPTLIKEDTTM('', '', '','2017-10-01 23:25:59.999999','2')
Connection Properties, for reference
I'm attempting to pass the first 3 parameters: LPARSSID, DBNAME, TSNAME
I've created the following VBA code and assigned an activeX button. The code appears to debug fine. but when I click on the button noting appears to happen.
Private Sub CommandButton1_Click()
Dim LPARSSID As String 'Declare LPARSSID as String
Dim DBNAME As String 'Declare DBNAME As String
Dim TSNAME As String 'Declare TSNAME As String
LPARSSID = Sheets("RTSbyDBTSDTE").Range("B2").Value 'Pass value from cell B2 to LPARSSID variable
DBNAME = Sheets("RTSbyDBTSDTE").Range("B3").Value 'Pass value from cell B3 to DBNAME variable
TSNAME = Sheets("RTSbyDBTSDTE").Range("B4").Value 'Pass value from cell B4 to TSNAME variable`
Pass the Parameters values to the Stored Procedure used in the Data Connection
With ActiveWorkbook.Connections("RISCTEST - ParmPass").ODBCConnection
.CommandText = "call K9751DB.SP_GETRTSDB_BYDBTSNOPTLIKEDTTM('" & LPARSSID & "', '" & DBNAME & "', '" & TSNAME & "','2017-10-01 23:25:59.999999','2')"
ActiveWorkbook.Connections("RISCTEST - ParmPass").Refresh
End With
End Sub
Private Sub CommandButton21_Click()
End Sub
Not sure if ODBCConnection is correct.
I appreciate any suggestions you may have.
Tku,
Jeff A
I have a big Microsoft Access database that I use with our scary old bookkeeping system for running complex reports. It's Access 2007 with an iSeries v6, DB2 SQL, and AS400. I tried using Excel 2007 in thye beginning, but it couldn't handle it. But I'll take a stab anyways...
I'm not certain of the way you're using the With block and the Refresh method. I usually see With blocks used with a property or object. But looking at your With block, there's nothing in it. That may be why nothing happens. It just says...
With <yourcommand>.Refresh
'nothing here
End With
...so it may be doing something, but since the With block is empty, it doesn't do anything with any data that might be returned. And since I don't know what the SP is supposed to do, I can't say. And what I mean is, I'm assuming it is supposed to return some data, because if not and it just does something hidden on the server, you would know because you'd probably have other means to verify the activity.
Instead of using the With block, remove the Refresh command from that block and put the command on a line by itself:
...
Pass the Parameters values to the Stored Procedure used in the Data Connection
ActiveWorkbook.Connections("RISCTEST - ParmPass").ODBCConnection _
.CommandText = "call K9751DB.SP_GETRTSDB_BYDBTSNOPTLIKEDTTM('" & LPARSSID _
& "', '" & DBNAME & "', '" & TSNAME & "','2017-10-01 23:25:59.999999','2')" _
ActiveWorkbook.Connections("RISCTEST - ParmPass").Refresh
End Sub
Sorry; this is long. A second answer to your question, and extension of my first answer. My eyes were tired at the end. Please excuse any strange typos or seemingly missing sentences. If your eyes glaze over halfway through, there's actual working code (I hope) at the end.
Holy cow, this has been a bull to figure out. But I threw on a saddle, and I've been riding it since yesterday morning when I first replied to the OP. I think the issue isn't the strangeness of DB2 (as far as I can figure out yet, lol), but because of the way Excel implements ODBC, SQL, and queries.
I decided to make this a learning exercise. I work in Access w/VBA all day at work, with an occasional foray into Excel, but I never dove in to Excel queries before, and I'm much more familiar with Access VBA for this sort of thing. I've been wading through the No-Help file, VBA Object Explorer, and MSDN online documentation. But it was still monumentally confusing. Then I found this web page, which in the first few paragraphs, gives a perfectly coherent picture of the situation: https://www.cimaware.com/expert-zone/creating-basic-data-reports-with-listobjects-and-querytables
There are multiple layers of Excel UI bling involved, and the VBA object hierarchy for the associated collections & objects can take multiple, sometimes simultaneously abbreviated & parallel forms. It's a bit crazy how Excel throws things all over the place:
1) Excel > Workbook/s > Connections > WorkbookConnection > ODBCConnection
2) Excel > Workbook/s > Worksheet/s > ListObject/s > QueryTable/s
3) Excel > Workbook/s > Worksheet/s > QueryTable/s
4) ListObject > QueryTable > WorkbookConnection
5) QueryTable > WorkbookConnection
I'll explain all these items:
Excel, Workbooks, Workbook, Worksheets, and Worksheet are obvious.
Each Workbook contains the Connections collection for every Worksheet in it.
Connections can have connections of any type, whether it be file-based from TXT or XLS, web-based via HTTP, or the one we're looking at closely here: ODBC.
For some reason Microsoft broke the naming convention and called it a WorkbookConnection, rather than just Connection.
Then we arrive at the ODBCConnection, which has the gorey innards of the ODBC settings.
What can be confusing, all throughout these items, the ODBC connection string and SQL query string are repeated, and sometimes it's hard to tell what property/object links one item to another.
A QueryTable (QT) can be created in two places: contained within a ListObject (LO) or it can live independently right on a worksheet.
When a QT is contained in a LO (as introduced in Excel 2007), that's what gives us some of the bling I mentioned. Specifically, the Table Tools group and Design tab on the ribbon. This is where all the fancy settings & formatting come from, such as the alternating rows colors and dropdown boxes on the column headers.
When a QT is independent from a LO, the resulting query results & controls are simple and utilitarian. In fact they look and work just like they did in Excel 2003.
1) Excel > Workbook/s > Connections > WorkbookConnection > ODBCConnection
This is where the connection is stored. This is equivalent to the connections you see in the "Workbook Connections" window from the ribbon at Data > Connections.
2) Excel > Workbook/s > Worksheet/s > ListObject/s > QueryTable/s
This is what you get when you create a query from scratch in the Excel UI, by using any of the items in the "Get External Data" group that result in an ODBC connection to an SQL server. In my case I already have a collection of DSN files for DB2, so all during this experimentation I've only been using DSN files listed on the "Existing Connections" window.
3) Excel > Workbook/s > Worksheet/s > QueryTable/s
This is what you get if you use VBA to programmatically create a stand-alone QueryTable that's not contained in a ListObject. So far I haven't found any way to do this in the UI; I think no matter what's done, any queries created through the UI of Excel 2007 or later force containment within a ListObject.
4) ListObject > QueryTable > WorkbookConnection
This chain of objects is what you get from the UI. I found the WorkbookConnection need not be explicitly created in the Connections collection ahead of time. Any time a QueryTable is created, the connection is always created as a sort of side product.
5) QueryTable > WorkbookConnection
This is the simplest form, perhaps best described as the old way, and gives a query result and controls like those of Excel 2003 and 2000.
Now, after all this research, I think I understand what's happening in your code, and what you might do differently. The core bit is here:
With ActiveWorkbook.Connections("RISCTEST - ParmPass").ODBCConnection
.CommandText = "call K9751DB.SP_GETRTSDB_BYDBTSNOPTLIKEDTTM('" & LPARSSID & "', '" & DBNAME & "', '" & TSNAME & "','2017-10-01 23:25:59.999999','2')"
ActiveWorkbook.Connections("RISCTEST - ParmPass").Refresh
End With
Cleaned up perhaps like this (in my style of extensive subdivision):
Dim wb As Excel.Workbook
Dim conns As Excel.Connections
Dim conn As Excel.WorkbookConnection
Dim odbc As Excel.ODBCConnection
Dim connName As String
Dim connCmdText As String
Dim spName As String
Dim p1 As String
Dim p2 As String
Dim p3 As String
Dim p4 As String
Dim p5 As String
'Set up the parameter strings for everything.
connName = "RISCTEST - ParmPass"
spName = "K9751DB.SP_GETRTSDB_BYDBTSNOPTLIKEDTTM"
p1 = LPARSSID
p2 = DBNAME
p3 = TSNAME
p4 = "2017-10-01 23:25:59.999999"
p5 = "2"
'I use this trick to make quoted-strings within quoted-strings more
'readable. It's more lines of code, but easy to make with copy &
'paste, and when your eyes get blurry and tired and crossed and those
'double and single quotes start to look like triple single quotes
'and you can't tell quadruple single-quotes from double double-quotes,
'it can be a life saver. =-)
'This is the actual command.
connCmdText = "call spname('p1','p2','p3','p4','p5')"
'Now replace all the parameter codes with the real data. Be careful when
'choosing the names of the codes so they don't conflict with any correct
'strings already in the command string, or mayhem will result. Use goofy
'punctuation to make them more unique if necessary.
connCmdText = VBA.Replace(connCmdText, "spname", spName, , , vbTextCompare)
connCmdText = VBA.Replace(connCmdText, "p1", p1, , , vbTextCompare)
connCmdText = VBA.Replace(connCmdText, "p2", p2, , , vbTextCompare)
connCmdText = VBA.Replace(connCmdText, "p3", p3, , , vbTextCompare)
connCmdText = VBA.Replace(connCmdText, "p4", p4, , , vbTextCompare)
connCmdText = VBA.Replace(connCmdText, "p5", p5, , , vbTextCompare)
'Now to the business.
Set wb = Excel.ActiveWorkbook
Set conns = wb.Connections
Set conn = conns.Item(connName)
Set odbc = conn.ODBCConnection
odbc.CommandText = connCmdText
conn.Refresh
'The with block wasn't even needed. (I think.)
Now looking at that, I don't see a QT. Is there more to your code that includes one, which you didn't include in your OP..? If the code you posted is all you have, I don't see anything to tell Excel where to put the query result. But unless there's something outstandingly different, you've shown enough to allow some supposition for different code to get what you want.
Here's an actual working procedure for my DB2 system that I worked out today to figure out this issue. It posts a basic Excel 2003-style query result at A1 on Sheet1. I've only blotted out the user credentials and IP of the server for anonymity. This is the most basic implementation of a query in Excel VBA: the independent-QT.
Sub TestQT()
Dim connStr As String
Dim connCmdText As String
Dim destRangeAddr As String
Dim ws As Excel.Worksheet
Dim qts As Excel.QueryTables
Dim qt As Excel.QueryTable
Dim destRangeRng As Excel.Range
'Set up the connection string and other variables for the query.
destRangeAddr = "A1"
connCmdText = "SELECT * FROM VIPDTAB.BEERXT"
connStr = _
"ODBC;" & _
"DRIVER={iSeries Access ODBC Driver};" & _
"UID=********;" & _
"PWD=********;" & _
"SIGNON=1;" & _
"QRYSTGLMT=-1;" & _
"PKG=QGPL/DEFAULT(IBM),2,0,1,0,512;" & _
"LANGUAGEID=ENU;" & _
"DFTPKGLIB=QGPL;" & _
"DBQ=VIPDTAB;" & _
"SYSTEM=***.***.***.***;" & _
"FILEDSN=NOTHING;"
'In experiments I found FILEDSN doesn't need to be anything, it can
'simply be FILEDSN=DUMMY, if you wish to use a DSN-less connections,
'as I do. Also, obviously the password is visible and as such is a
'security issue.
'Define the sheet.
Set ws = ActiveSheet
'Clean up the sheet. Useful if the query is run repeatedly, and to avoid the
'runtime error that says "overlapping pivot table".
ws.Cells.Clear
ws.Cells.ColumnWidth = 8
'Now to business.
Set destRangeRng = ws.Range(destRangeAddr) 'Range object to paste the data.
Set qts = ws.QueryTables 'The QT collection.
Set qt = qts.Add(connStr, destRangeRng, connCmdText) 'Create the query
'Now run it. 'False makes Excel lock up during long queries, so True is best.
qt.Refresh BackgroundQuery:=True
End Sub
Now, to merge all these ideas together to solve your problem. Everything is nearly identical, except the last few lines. I have no way of testing this since of course I'm not on you system, but I did run the debugger on it to catch any blatant typos. So shout me back if you need more help:
Sub TestQuery2()
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
Dim qts As Excel.QueryTables
Dim qt As Excel.QueryTable
Dim conns As Excel.Connections
Dim conn As Excel.WorkbookConnection
Dim destRangeObj As Excel.Range
Dim destRangeTxt As String
Dim connName As String
Dim connDesc As String
Dim connStr As String
Dim spName As String
Dim connCmdText As String
Dim p1 As String
Dim p2 As String
Dim p3 As String
Dim p4 As String
Dim p5 As String
connName = "RISCTEST - ParmPass"
connDesc = "" 'set the description as/if desired
connStr = _
"DRIVER={IBM DB2 ODBC DRIVER};" & _
"UID=k9751x1;" & _
"PWD=********;" & _
"MODE=SHARE;" & _
"DBALIAS=RISCTEST;"
destRangeTxt = "$A$1"
'Set up the procedure call by replacing the parameters.
'It's much more readable than quotes within quotes.
connCmdText = "call spname('p1','p2','p3','p4','p5')"
spName = "K9751DB.SP_GETRTSDB_BYDBTSNOPTLIKEDTTM"
p1 = Sheets("RTSbyDBTSDTE").Range("B2").Value
p2 = Sheets("RTSbyDBTSDTE").Range("B3").Value
p3 = Sheets("RTSbyDBTSDTE").Range("B4").Value
p4 = "2017-10-01 23:25:59.999999"
p5 = "2"
'Replace all the parameters.
connCmdText = VBA.Replace(connCmdText, "spname", spName, , , vbTextCompare)
connCmdText = VBA.Replace(connCmdText, "p1", p1, , , vbTextCompare)
connCmdText = VBA.Replace(connCmdText, "p2", p2, , , vbTextCompare)
connCmdText = VBA.Replace(connCmdText, "p3", p3, , , vbTextCompare)
connCmdText = VBA.Replace(connCmdText, "p4", p4, , , vbTextCompare)
connCmdText = VBA.Replace(connCmdText, "p5", p5, , , vbTextCompare)
'Define the worksheet and destination.
Set ws = ActiveSheet
Set destRangeObj = ws.Range(destRangeTxt)
'Clean up the sheet. Useful if query is run repeatedly. If used as
'such, the .Clear has to happen before the .Add method, or a runtime
'error will ocurr due to the old query blocking the new one. I didn't
'save the message, it was something about "pivot table overlap".
ws.Cells.Clear 'wipe all values, formatting, conections, and queries
ws.Cells.EntireColumn.ColumnWidth = 8
'Something I noticed that's different between an LO/QT and independent-QT,
'with an LO/QT, the connection is attached to the table, literally. So the .Clear
'may not delete the connection if it was created by an independent-QT. The following
'bit of code should take care of that, by looping through the connections and
'deleting any connection that already exists with the same name.
Set wb = ws.Parent
Set conns = wb.Connections
For Each conn In conns
If conn.Name = connName Then
conn.Delete
Exit For
End If
Next
'Now the business.
Set qts = ws.QueryTables
Set qt = qts.Add(connStr, destRangeObj, connCmdText)
'Now both the query and connection have been created. The connection name, which
'appears in the Workbook Connections window, needs to be set. When the QT is created
'in the .Add procedure above, the connection is also created, but there's no way to
'specify its name, so it just uses the name "Connection". But that can be changed
'after the fact, as can the connection description, if desired.
Set conn = qt.WorkbookConnection
conn.Name = connName
conn.Description = connDesc
'And finally, the fireworks:
qt.Refresh True
End Sub
spinjector -
First off, let me say WOW... this is amazing stuff and I truly appreciate your taking the time to delve and share.
Secondly, (and quite honestly), you're skills in this area are far and above that of mine. While I've been using excel for many years to pull data from z/OS (my bailiwick as a DBA / SysProg) and have written a few (basic) macros, I've never gotten deep into the bowels as you quite apparently have... IMPRESSIVE.
The method I use to set up my connection is via Data, Other Sources, From MS Query, Choose Data Source, input the query / StoredProc, and assign a taget for the data (see below). Honestly pretty Excel 101, but works well and is fairly easy to implement.
However that being said, I like most techies, love to learn and share and will be attempting what you have shared as time allows. In addition, I'm looking to become more VBA savvy and have discussed some formal (or informal) training with my current management.
Again - your efforts and willingness to share are very much appreciated.
Tku,
Jeff A
To set up excel to use odbc
• Open excel
• Select data
• Select get external data
• Select from other sources
o From SQL Server (for SQL Server)
 Enter server name (ie for dbstatus: xxxxxxxx\xxxx)
 Connect
o From Microsoft Query (For DB2 LUW, z/OS, Oracle)
 Select the data source
 Create a new one if needed
• Name the data source
• Choose the driver type
 Connect
 Enter server name
o Select database / table
o Select view type / display location
o Optionally select properties
 In Command text box, enter query
o OK / OK to run

MS Access - SetFocus on multiple text boxes to check if data exists via SQL

The problem I'm facing:
I try to check if inserted text from multiple text boxes is already existing in a table before saving the records to avoid duplicates.
I created a form to enter new members and save them into a table. The key to avoid duplicates is to check the combination of given name, last name and birth date with existing records. (It's most likely that there won't be two person with all three criteria matching)
I have no problem to check the existence for only one text box by setting the focus on the desired box and use the SQL query IF EXISTS...
But since I would need to set focus on several text boxes(IMO) the problem occurs.
Is there a way to set focus on multiple text boxes?
The idea would be to use an IF EXISTS...AND EXISTS statement and I would need to implement the .SetFocus statement for each text box before checking its existence.
I hope you get my point and I would be glad if someone could share some knowledge. :)
Thanks in advance
There seems to be some missing information in order to find the best solution to your problem. so the below response will be based on assumptions as to how your form is working.
I'm assuming you are using an unbound form with unbound text boxes? if this is the case, then you must have a button that is the trigger for checking/adding this information to your table. lets say your command button is called "Save". You can use the following code without the need to .setfocus to any textbox.
Private Sub Save_Click()
Dim db as DAO.Database
Dim rst as DAO.Recordset
Dim strSQL as string
set db = currentdb 'This is the connection to the current database
'This is the SQL string to query the data on your table
strsql = "SELECT * " & _
"FROM [Yourtablename] " & _
"WHERE ((([YourTableName].[FirstName]) ='" & me.FormFirstNameField & "' AND ([YourTableName].[LastName]) ='" & me.FormLastNameField & "' AND ([YourTableName].[DOB]) =#" & me.FormDOBField & "#));"
set rst = db.openrecordset(strsql) 'This opens the recordset
if rst.recordcount <> 0 then
'Enter code to inform user information already exists
else
'Enter code if information does not exits
end if
rst.close 'Closes the recordset
set rst = nothing 'Frees memory
set db = nothing 'Frees Memory
End Sub
Let me know if this code works or if I need to make changes based on your scenario.

Schema changes not updated in MS Access front end linked to the database

I created a new table in SQL server using SQL Server Management Studio but the MS Access front end linked to the database was not updated.
I tried reopening Access but still the new tables cannot be found. Yet when I check the SQL Server database they are there.
My tables in Access are linked to the database so I assumed any table or changes made in the SQL server database would be reflected in the Access front end. When I run a query in Access looking for the tables nothing is found. Another bit of information is when I right click and press view dependencies it says unable to view dependencies because
"unable to cast object of type 'System.DBNull' to type
'System.string'"
Something is maybe wrong with the way i save the query but I am not sure.
Your assumption:
I assumed any table or changes made in the SQL server database would
be reflected in the Access front end
...is not correct. Access does not automatically re-link when the SQL Server's schema changes, and it really can't. You're expecting Access assumes the data models between SQL Server and Access are the same. Even if your table and column names are exactly the same there are still differences to deal with since the data types have some differences. So, even in the best-case scenario Access does not have enough info to automatically re-link.
When you modify the SQL Server db you have to re-link from Access. Here's an article with some code that will allow you to do that quickly but note that you still have to launch it manually. And beware, as mentioned above, linking isn't that straightforward. If you use an automated method for linking the process will have to make some decisions, some of which make take you by surprise.
I have found the management of linked tables in access to be administratively tedious. In order to make my life simpler I have used the functions below that can be called to update the linked tables in access. This will take care of updating the structure of any changed table in SQL. Adding values to the SetTableNames function will bring in new tables
Private mstrTableNames(100) As String
Private const gcSQLDB as string = "MySQLServer"
Private const gcUserID as string = "SQLUserName"
Private const gcUserPassword as string = "SQLPassword"
Private const gcLiveDSN as string = "DSN"
Private const gcEmpty as string = ""
Public Function LinkLiveTables() As Boolean
Dim tdfLinked As TableDef
Dim strConnect As String
Dim intLoop As Integer
'Remove all non system tables from the application:
' !!!NB Add other exclusions so as to not delete tables that are not linked!!!
For Each tdfLinked In CurrentDb.TableDefs
If Left(tdfLinked.Name, 2) <> "MS" Then
If Left(tdfLinked.Name, 7) <> "tblTemp" Then
CurrentDb.TableDefs.Delete tdfLinked.Name
End If
End If
Next
'Create a linked table that points to SQL Server
strConnect = "ODBC;DATABASE=" & gcSQLDB & ";UID=" & gcUserID & _
";PWD=" & gcUserPassword & ";DSN=" & gcLiveDSN
SetTablesNames
For intLoop = 1 To 100
If mstrTableNames(intLoop) = gcEmpty Then GoTo ProcExit
Set tdfLinked = CurrentDb.CreateTableDef(mstrTableNames(intLoop))
With tdfLinked
.Connect = strConnect
.SourceTableName = "dbo." & mstrTableNames(intLoop)
End With
CurrentDb.TableDefs.Append tdfLinked
Next
ProcExit:
MsgBox "Connection to the LIVE tables was successful.", vbInformation
Exit Function
ProcError:
MsgBox "Link to LIVE tables Failed." & vbCrLf & vbCrLf & _
"Error Number : " & Err.number & vbCrLf & _
"Error Description : " & Err.Description, vbCritical
End Function
Private Sub SetTablesNames()
mstrTableNames(1) = "tblMoistureHist"
mstrTableNames(2) = "tblRawMaterials"
' ... add the additional table that you need as mstrTableNames(n) = "tablename"
End Sub

Access 2007 VBA Query Shows Data in Query Analyzer But Not in VBA Coded Recordset

I have a function I've written that was initially supposed to take a string field and populate an excel spreadsheet with the values. Those values continually came up null. I started tracking it back to the recordset and found that despite the query being valid and running properly through the Access query analyzer the recordset was empty or had missing fields.
To test the problem, I created a sub in which I created a query, opened a recordset, and then paged through the values (outputting them to a messagebox). The most perplexing part of the problem seems to revolve around the "WHERE" clause of the query. If I don't put a "WHERE" clause on the query, the recordset always has data and the values for "DESCRIPTION" are normal.
If I put anything in for the WHERE clause the recordset comes back either totally empty (rs.EOF = true) or the Description field is totally blank where the other fields have values. I want to stress again that if I debug.print the query, I can copy/paste it into the query analyzer and get a valid and returned values that I expect.
I'd sure appreciate some help with this. Thank you!
Private Sub NewTest()
' Dimension Variables
'----------------------------------------------------------
Dim rsNewTest As ADODB.Recordset
Dim sqlNewTest As String
Dim Counter As Integer
' Set variables
'----------------------------------------------------------
Set rsNewTest = New ADODB.Recordset
sqlNewTest = "SELECT dbo_partmtl.partnum as [Job/Sub], dbo_partmtl.revisionnum as Rev, " & _
"dbo_part.partdescription as Description, dbo_partmtl.qtyper as [Qty Per] " & _
"FROM dbo_partmtl " & _
"LEFT JOIN dbo_part ON dbo_partmtl.partnum = dbo_part.partnum " & _
"WHERE dbo_partmtl.mtlpartnum=" & Chr(34) & "3C16470" & Chr(34)
' Open recordset
rsNewTest.Open sqlNewTest, CurrentProject.Connection, adOpenDynamic, adLockOptimistic
Do Until rsNewTest.EOF
For Counter = 0 To rsNewTest.Fields.Count - 1
MsgBox rsNewTest.Fields(Counter).Name
Next
MsgBox rsNewTest.Fields("Description")
rsNewTest.MoveNext
Loop
' close the recordset
rsNewTest.Close
Set rsNewTest = Nothing
End Sub
EDIT: Someone requested that I post the DEBUG.PRINT of the query. Here it is:
SELECT dbo_partmtl.partnum as [Job/Sub], dbo_partmtl.revisionnum as Rev, dbo_part.partdescription as [Description], dbo_partmtl.qtyper as [Qty Per] FROM dbo_partmtl LEFT JOIN dbo_part ON dbo_partmtl.partnum = dbo_part.partnum WHERE dbo_partmtl.mtlpartnum='3C16470'
I have tried double and single quotes using ASCII characters and implicitly.
For example:
"WHERE dbo_partmtl.mtlpartnum='3C16470'"
I even tried your suggestion with chr(39):
"WHERE dbo_partmtl.mtlpartnum=" & Chr(39) & "3C16470" & Chr(39)
Both return a null value for description. However, if I debug.print the query and paste it into the Access query analyzer, it displays just fine. Again (as a side note), if I do a LIKE statement in the WHERE clause, it will give me a completely empty recordset. Something is really wonky here.
Here is an interesting tidbit. The tables are linked to a SQL Server. If I copy the tables (data and structure) locally, the ADO code above worked flawlessly. If I use DAO it works fine. I've tried this code on Windows XP, Access 2003, and various versions of ADO (2.5, 2.6, 2.8). ADO will not work if the tables are linked.
There is some flaw in ADO that causes the issue.
Absolutely I do. Remember, the DEBUG.PRINT query you see runs perfectly in the query analyzer. It returns the following:
Job/Sub Rev Description Qty Per
36511C01 A MAIN ELECTRICAL ENCLOSURE 1
36515C0V A VISION SYSTEM 1
36529C01 A MAIN ELECTRICAL ENCLOSURE 1
However, the same query returns empty values for Description (everything else is the same) when run through the recordset (messagebox errors because of "Null" value).
I tried renaming the "description" field to "testdep", but it's still empty. The only way to make it display data is to remove the WHERE section of the query. I'm starting to believe this is a problem with ADO. Maybe I'll rewriting it with DAO and seeing what results i get.
EDIT: I also tried compacting and repairing a couple of times. No dice.
When using ADO LIKE searches must use % instead of *. I know * works in Access but for some stupid reason ADO won't work unless you use % instead.
I had the same problem and ran accoss this forum while trying to fix it. Replacing *'s with %'s worked for me.
Description is a reserved word - put some [] brackets around it in the SELECT statement
EDIT
Try naming the column something besides Description
Also are you sure you are using the same values in the where clause - because it is a left join so the Description field will be blank if there is no corresponding record in dbo_part
EDIT AGAIN
If you are getting funny results - try a Compact/Repair Database - It might be corrupted
Well, what I feared is the case. It works FINE with DAO but not ADO.
Here is the working code:
Private Sub AltTest()
' Dimension Variables
'----------------------------------------------------------
Dim rsNewTest As DAO.Recordset
Dim dbl As DAO.Database
Dim sqlNewTest As String
Dim Counter As Integer
' Set variables
'----------------------------------------------------------
sqlNewTest = "SELECT dbo_partmtl.partnum as [Job/Sub], dbo_partmtl.revisionnum as Rev, " & _
"dbo_part.partdescription as [TestDep], dbo_partmtl.qtyper as [Qty Per] " & _
"FROM dbo_partmtl " & _
"LEFT JOIN dbo_part ON dbo_partmtl.partnum = dbo_part.partnum " & _
"WHERE dbo_partmtl.mtlpartnum=" & Chr(39) & "3C16470" & Chr(39)
Debug.Print "sqlNewTest: " & sqlNewTest
Set dbl = CurrentDb()
Set rsNewTest = dbl.OpenRecordset(sqlNewTest, dbOpenDynaset)
' rsnewtest.OpenRecordset
Do Until rsNewTest.EOF
For Counter = 0 To rsNewTest.Fields.Count - 1
MsgBox rsNewTest.Fields(Counter).Name
Next
MsgBox rsNewTest.Fields("TestDep")
rsNewTest.MoveNext
Loop
' close the recordset
dbl.Close
Set rsNewTest = Nothing
End Sub
I don't use DAO anywhere in this database and would prefer not to start. Where do we go from here?
I know some time has passed since this thread started, but just in case you're wondering, I have found out some curious about Access 2003 and the bug may have carried over to 2007 (as I can see it has).
I've had a similar problem with a WHERE clause because I needed records from a date field that also contained time, so the entire field contents would look like #6/14/2011 11:50:25 AM# (#'s added for formatting purposes).
Same issue as above, query works fine with the "WHERE ((tblTransactions.TransactionDate) Like '" & QueryDate & "*');" in the query design view, but it won't work in the VBA code using ADO.
So I resorted to using "WHERE ((tblTransactions.TransactionDate) Like '" & QueryDate & " %%:%%:%% %M');" in the VBA code, with ADO and it works just fine. Displays the record I was looking for, the trick is not to use "*" in the Like clause; or at least that was the issue in my case.
I put brackets around the word "Description" in the SELECT statement, but it's behavior remains. It works fine as long as I don't put anything in the WHERE clause. I've found if I put anything in the where clause, the description is blank (despite showing up in the Query analyzer). If I use a LIKE statement in the WHERE clause, the entire recordset is empty but it still works properly in the Query Analyzer.
Ultimately I think it's a problem with running ADO 2.8 on Vista 64
Personally I have always used DAO in Access projects.