VBA SQL Query Table Error - excel

I am trying to pull data from an ACD call data system, Nortel Contact Center 6.0 to be exact, and if you use that particular system what I am trying to capture is the daily call by call data. However when I use this code
(sCW is a common word string that equals eCallByCallStat and
sDate is
dDate = Format(Month(deffDate) & "/" & iStartDay & "/" & Year(deffDate), "mm/dd/yyyy")
sDate = Format(dDate, "yyyymmdd")
)
sSql = ""
sConn = "ODBC;DSN=Aus1S002;UID=somevaliduser;PWD=avalidpassword;SRVR=Thecorrectserver;DB=blue"
sSql = "SELECT " & sCW & sDate & ".Timestamp, "
sSql = sSql & sCW & sDate & ".CallEvent, "
sSql = sSql & sCW & sDate & ".CallEventName, "
sSql = sSql & sCW & sDate & ".CallID, "
sSql = sSql & sCW & sDate & ".TelsetLoginID, "
sSql = sSql & sCW & sDate & ".AssociatedData, "
sSql = sSql & sCW & sDate & ".Destination, "
sSql = sSql & sCW & sDate & ".EventData, "
sSql = sSql & sCW & sDate & ".Source, "
sSql = sSql & sCW & sDate & ".Time " & vbCrLf
sSql = sSql & "FROM blue.dbo.eCallByCallStat" & sDate & " " & sCW & sDate & vbCrLf
sSql = sSql & " ORDER BY " & sCW & sDate & ".Timestamp"
Set oQT = ActiveSheet.QueryTables.Add(Connection:=sConn, Destination:=Range("A1"), Sql:=sSql)
oQT.Refresh BackgroundQuery:=False
Do While oQT.Refreshing = True
Loop"
When I run this I get an odd error message at oQT.Refresh BackgroundQuery:=False
Oddly enough it worked for a month or so then just died
# loopo
I actually added the "" to the connection string and actually have the user name and password hard coded into the query with out quotes, I have since removed them for clarity in the posting
The error I recieve is
Run-time error '-2147417848(80010108)':
Method 'Refresh" of Object "_QueryTable' Failed
Thanks for your input Kevin. The Database is never in a state where no one is accessing it, it is a Call Handling system that is on 24 x 7 and always connected to is clients. At least that is my understanding. If I do this manually through Excel I never get an error, or have any issues only when I am doing this via a macro does it give me issues which lead me to think that it was my code causing the issue.
I am connecting to the database via ODBC as recommended by the manuafacturer, but I wonder if they ever envisioned this sort of thing.
I will see if I can leverage this into a .NET project and see if that helps.

Seems like an error with the query itself...
If you can step through your code and post the contents of sSql, it would probably help troubleshoot...
When you go through it, be sure quotes are getting escaped properly.

Looks like your connection string has double quotes in it.
This could potentially be due to some parsing by the website
you should probably set sConn using "double double" quotes, as in:
sConn = "ODBC;DSN=Aus1S002;UID=""somevaliduser"";PWD=""avalidpassword"";SRVR=""Thecorrectserver"";DB=blue"

What is the actual error message you're getting?
In the FROM clause, are you trying to SELECT from 2 different tables, with the same name in different namespaces? (In which case I think they should be separated by a comma rather than a space)
Or is there supposed to be another '.' instead of the space in the FROM clause? Or is it an alias?
Do you need to specify the table for every field? why not just do:
SELECT Timestamp, CallEvent, ... ,Time
FROM blue.dbo.eCallByCallStat" & sDate & " ORDER BY Timestamp

First off, if you're connecting to a non-generic database (SQL Server, Oracle, etc.), try using a database connection that's specific to it.
Secondly, since you said this error comes and goes, can you test whether it still happens when no one else is accessing the system? Perhaps it is an issue with certain rows being locked while your query is trying to read them...
Third, either switch to a different reporting method or find a different way to get the data. There are limits to this type of call within Excel. While, yes, it certainly does allow you to connect to databases and pull in data, you may find it falling short if you're working with large sets of data, complex queries, or finicky database connections.

I start by deleting the contents of sSQL with sSql=""
after that, because the query is run in a for loop I build the query in each of the next lines, each line builds on the previous line, I made it that way so it would be easier to edit and understand by the next guy.
After running through the sSQL looks like this
sSQL=SELECT eCallByCallStat20081001.Timestamp, eCallByCallStat20081001.CallEvent,
eCallByCallStat20081001.CallEventName, eCallByCallStat20081001.CallID,
eCallByCallStat20081001.TelsetLoginID, eCallByCallStat20081001.AssociatedData,
eCallByCallStat20081001.Destination, eCallByCallStat20081001.EventData,
eCallByCallStat20081001.Source, eCallByCallStat20081001.Time FROM
blue.dbo.eCallByCallStat20081001 eCallByCallStat20081001 ORDER BY
eCallByCallStat20081001.Timestamp

I was having this same issue when trying to refresh a Query.
For some reason that I don't know. When refering to a QueryTable object the refresh only works the first time you run the vba code. If you run it again the runtime error will prompt Run-time error '-2147217842(80040e4e): Method 'Refresh' of object '_QueryTable' failed occurs
This is an example of a Query refresh that fails.
Ws.ListObjects("TableName").QueryTable.Refresh BackgroundQuery:=False
Here is the solution found.
ThisWorkbook.Connections("ConnectionName").Refresh
If someone knows the reason why the refresh method of the QueryTable object fails. please let us know.

Related

The INSERT INTO statement contains an unknown field name

I'm using the following code to export information from an excel file to an access database. It worked fine last time I used it but ever since I started it up today I've been running into the following issue.
Public Sub Export_to_ACCDB()
Set cn = CreateObject("ADODB.Connection")
dbPath = Application.ActiveWorkbook.Path & "\Newdatabase.accdb"
dbWb = Application.ActiveWorkbook.FullName
dbWs = Application.Worksheets("DATABASE").Name
scn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath
dsh = "[" & Application.ActiveSheet.Name & "$]"
cn.Open scn
'ssql = "INSERT INTO Database ([Column1],[Column2],[Column3]) "
ssql = ssql & "SELECT * FROM [Excel 8.0;HDR=YES;DATABASE=" & dbWb & "]." & dsh
cn.Execute ssql '<<< The error occurs here
End Sub
I get the following error running this code:
Run-time error '-2147217900 (80040e14)':
The INSERT INTO statement contains the following unknown field name: 'F12'. Make sure you have typed the name correctly, and try the operation again.
I don't have a field name called 'F12' in either my excel file or my access database. I can't seem to figure out what's going on.
Column headers are written correctly.
Column headers do not contain spaces or other irregularities.
EDIT:
Seems like Excel thinks you got a 12th column (maybe by accidentally entering something). Mark column L and delete it #FunThomas
This seemed to be the problem. I had to delete all the columns after the last one which contained the correct fieldname. Now it's working again.

Setting an ODBC connection string in VBA

I have created a macro that sends a new CommandText to an ODBC Connection in my Excel spreadsheet and then refreshes the table of results associated with the query. This has been working fine, but I've noticed that each time I run the macro it overwrites the connection string with some default values that work on my machine but will not work on other users' machines because they do not have the saved connection file that I have. The more specific connection string that specifies a server address works when entered manually, but will get overwritten anytime the macro is run.
I figured I would just have the macro write the connection string at the same time it sends the new CommandText, but I'm running into errors.
My code is as follows:
Sub NewData()
Dim lStr As String
lStr = ""
lStr = lStr & " USE myDBname; "
lStr = lStr & " WITH X AS ("
lStr = lStr & " SELECT"
lStr = lStr & " column1, column2, column3, etc"
lStr = lStr & " FROM"
lStr = lStr & " etc. etc. etc."
With ActiveWorkbook.Connections("PayoffQuery").ODBCConnection
.CommandText = lStr
.Connection = "SERVER=myserveraddress;UID=SYSTEM;Trusted_Connection=Yes;APP=2007 Microsoft Office system;WSID=SYSTEM;DATABASE=myDBname;"
End With
End Sub
The .CommandText still updates just fine, but the .Connection throws runtime error 1004: Application-defined or object-defined error.
Any idea what I'm doing wrong here? TIA.
In your VBA code, add ODBC; to the beginning of your new connection string.
.Connection = "ODBC;SERVER=myserveraddress;UID=SYSTEM;Trusted_Connection=Yes;APP=2007 Microsoft Office system;WSID=SYSTEM;DATABASE=myDBname;"

Using VBA to connect Access to Excel, will not output any records from Access

I would like to connect to my Access tables using VBA. I want to be able to type in a purchase order number, and reference that value in a query to the Access table. I want to print the results of that query to my Excel worksheet. This is what I have so far.. any ideas?
Sub CommandButton1_Click()
Dim myValue As Variant
myValue = InputBox("Enter Purchase Order Number:")
Range("A1").Value = myValue
Call ADO_Conn(myValue)
End Sub
Sub ADO_Conn(myValue)
Dim conn As New Connection
Dim rstAnswer As New ADODB.Recordset
Dim connected As Boolean
Dim RootPath, DBPath As String
Dim tempString As String
connected = False
RootPath = "Z:\BSD Internship Program\FY14 Intern Files\John Jameson\Vouchers"
DBPath = RootPath & "Acquisition Support Datamart Build 9.11-03.accdb"
conn.Open "Provider=Microsoft.ACE.OLEDB.12.0; Data Source= Z:\BSD Internship Program\FY14 Intern Files\John Jameson\Vouchers\Acquisition Support Datamart 9.1103.accdb;"
connected = True
rstAnswer.Open "SELECT VW_PUB_PURCHASE_ORDER.PO_NO FROM VW_PUB_PURCHASE_ORDER " & _
"WHERE VW_PUB_PURCHASE_ORDER.PO_NO = ' " & myValue & " ';", conn, adOpenKeyset, adLockOptimistic
Do Until rstAnswer.EOF
tempString = CStr(rstAnswer!VW_PUB_PURCHASE_ORDER)
Application.ActiveWorkbook.Worksheets("Sheet1").Range("A5").Value = tempString
rstAnswer.MoveNext
Loop
rstAnswer.Close
conn.Close
connected = False
End Sub
A couple of things about your initial query:
rstAnswer.Open "SELECT VW_PUB_PURCHASE_ORDER.PO_NO FROM VW_PUB_PURCHASE_ORDER " & _
"WHERE VW_PUB_PURCHASE_ORDER.PO_NO = ' " & myValue & " ';", conn, adOpenKeyset, adLockOptimistic
You are searching only for PO_NO in this query, so that is the only value that will return. If you want more than just that data (as I assume you might), then you want this:
rstAnswer.Open "SELECT * FROM VW_PUB_PURCHASE_ORDER " & _
"WHERE VW_PUB_PURCHASE_ORDER.PO_NO = ' " & myValue & " ';", conn, adOpenKeyset, adLockOptimistic
... where the asterisk means "all".
In addition, this bit concerns me:
' " & myValue & " '
You are adding leading and trailing blanks to your search term. This may or may not be what you want, but I assume that you do not want this. You probably want:
'" & myValue & "'
And if your PO_NO is a numeric value, you need to omit the apostrophes:
" & myValue & "
Lastly, I don't think you want to loop at all. The SELECT query will return all the results without requiring you to iterate rows. Maybe you should try getting rid of your "do" loop and using this instead:
Worksheets("Sheet1").Range("A5").CopyFromRecordset rstAnswer
Your query values will then be dropped into a dynamic range starting at the designated sheet & cell.
I didn't test the code so I might not have caught everything, but those jumped out at me.
Hope that helps!
Nate

update and delete single access record set via excel vba

I have this tool where employee information needs to be updated. I call in the MDB data to excel in one sheet. Now I use vlookup to see what is there and change it if needed.
I have tried some tricks however some thing seems to be wrong.. please help.
Sub update()
Dim cn As Object
Dim rs As Object
Dim a As String
strFile = "D:\temp excel\EIM.mdb"
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile & ";"
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon
a = Sheet2.Range("D4")
strSQL = "SELECT * FROM EIM WHERE EIM.NBKID=" & a
rs.Open strSQL, cn
strSQL = "UPDATE EIM SET EIM.Person#=('" & Sheet2.Range("D5") & "')WHERE EIM.NBKID=('" & Sheet2.Range("D4")
cn.Execute strSQL
End Sub
In the above code the file EIM has a table called EIM with NBKID and Person# fields.
So sorry about not explaining the request clearly, I have this tool which allows people to update there information. I cannot use access to manipulate it as not all have access available and even it would be available I do not want to give them access to master database.
We have more than 500 employee's when ever some one moves out of one role to another or when someone leaves the organization. A manager has to request for hierarchy report which takes time to come.
Instead of going through that I want this tool to maintain record of all the employees, here nbkid is nothing but system id and person# is employee number or id.
I have a code to update the information however if someone needs to edit it due to some change to their role than I need another set of code.
By doing it in excel it is easy to manage - no additional training.
I have this button which should update the change made to the vaules updated in excel sheet. I dont want it to check if the record change, I just want it to use update.
When I run the above code I get error saying "No value given for one or more reqired parameters."
I agree as to the point of modifying the data in excel as opposed to directly in access however I just spotted that your SQL statement seems to be slightly wrong. Try changing
WHERE EIM.NBKID=('" & Sheet2.Range("D4")
to
WHERE EIM.NBKID=" & Sheet2.Range("D4")
Note the removal of the single quote mark as the original statement would have been seen as
WHERE EIM.NBKID=('123456
You are missing a space between the bracket and where:
strSQL = "UPDATE EIM SET EIM.Person#=('" & Sheet2.Range("D5") _
& "') WHERE EIM.NBKID=('" & Sheet2.Range("D4")
The single quotes are needed if NBKID is a text field:
WHERE EIM.NBKID=('" & Sheet2.Range("D4") & "'"
Or for a numeric field:
WHERE EIM.NBKID=(" & Sheet2.Range("D4")
I doubt that this is a date field, but if it was, it would take hash (#) delimiters.
Just as a point of efficiency, I am not sure why you actually opened the recordset at all. The cn.Execute line works very well by itself.
I would also write a function you could call and pass it parameters to, depending on what you are trying to do. If you passed in the ID, the strFileName and the strSQL, then you have an all-purpose function.
I have a prebaked SQL string somewhere on a key pair "SELECT * from tblFoo WHERE tblFoo.ixFoo = {key}". I then get the parameter and do a Replace on the strSQL to insert the key.
Sub Update(strFile as string, strKey As String, strPerson as string)
Dim cn As Object : Set cn = CreateObject("ADODB.Connection")
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile & ";"
cn.Open strCon
strSQL = "UPDATE EIM SET EIM.Person#="{person}" WHERE EIM.NBKID={key}"
strSQL = Replace(strSQL, {person}, strPerson, 1)
strSQL = Replace(strSQL, {key}, strKey, 1)
cn.Execute strSQL
End Sub
If speed of code greater than need for speed of execution (which is what I can gather here), then this approach alleviates all the quote/doublequote confusion
I would set aside a sheet in the book that had all the strSQL statements there, if you had a few. You could even pass this in and do the replace within Excel with its much faster native execution speed.
You now have a function you can pick up and reuse. If you are serious about using VBA, reuse heavily. It saves so much time. VBA jobs tend to place a high amount of pressure on time to produce.
I presume that you have removed error trapping to save us the hassle of reading it.

How can I best use VBA in Access or Excel to test an ODBC connection?

Given a pre-configured ODBC System DSN, I'd like to write a function that gracefully tests that connection using VBA.
Private Function TestConnection(ByVal dsnName As String) As Boolean
' What goes here?? '
End Function
Edit: To clarify, the System DSNs are pointing to external SQL Server 2005 databases, with Windows NT authentication.
One approach I've tried is to send some random query to the target database and catch the error. If the query works, return true. If there's an error then return false. This works just fine but it feels...kludgy. Is there a more elegant way, especially one that doesn't rely on On Error Goto ?
Note: It's a legacy Access 2000 database I'm working on, so any solution can't have any Access 2007 or 2003 dependencies. I'd like to make it generic to VBA, but if there's a simple way in Access that's fine too.
Much obliged for any advice.
Dim cnn As ADODB.Connection
Dim canConnect as Boolean
Set cnn = New ADODB.Connection
cnn.Open "DSN HERE"
If cnn.State = adStateOpen Then
canConnect = True
cnn.Close
End If
Msgbox canConnect
EDIT: DSN Format could be "DSN=MyDSN;UID=myuser;PWD=myPwd;"
Look this for connection strings
I'm too late to give you a useful answer to your question, but I came here because I wanted to see if StaCkOverflow has a better answer than the code I'm currently using to test ADODB connections.
...It turns out that the answer is 'No', so I'll post the code for reference: someone else will find it useful.
Coding notes: this isn't a generic answer: it's a method from a class encapsulating the ADODB.Connection object, and it assumes the existence of object 'm_objConnect'.
TestConnection: a VBA Class method for publishing debugging information for an ADODB.Connection object
This prints out the connection string, the current status, a list of ADODB errors (if any) and a full listing of the onnection's named properties.
Public Sub TestConnection()
On Error GoTo ErrTest
Dim i As Integer
If m_objConnect Is Nothing Then
Debug.Print "Object 'm_objConnect' not instantiated."
Else
Debug.Print m_objConnect.ConnectionString
Debug.Print "Connection state = " & ObjectStateString(m_objConnect.State)
Debug.Print
If m_objConnect.Errors.Count > 0 Then
Debug.Print "ADODB ERRORS (" & m_objConnect.Errors.Count & "):"
For i = 0 To m_objConnect.Errors.Count
With m_objConnect.Errors(i)
Debug.Print vbTab & i & ":" _
& vbTab & .Source & " Error " & .Number & ": " _
& vbTab & .Description & " " _
& vbTab & "(SQL state = " & .SqlState & ")"
End With
Next i
End If
Debug.Print
Debug.Print "CONNECTION PROPERTIES (" & m_objConnect.Properties.Count & "):"
For i = 0 To m_objConnect.Properties.Count - 1
Debug.Print vbTab & i & ":" _
& vbTab & m_objConnect.Properties(i).Name & " = " _
& vbTab & m_objConnect.Properties(i).Value
Next i
End If
ExitTest:
Exit Sub
ErrTest:
Debug.Print "Error " & Err.Number & " raised by " & Err.Source & ": " & Err.Description
Resume Next
End Sub
Private Function ObjectStateString(ObjectState As ADODB.ObjectStateEnum) As String
Select Case ObjectState
Case ADODB.ObjectStateEnum.adStateClosed
ObjectStateString = "Closed"
Case ADODB.ObjectStateEnum.adStateConnecting
ObjectStateString = "Connecting"
Case ADODB.ObjectStateEnum.adStateExecuting
ObjectStateString = "Executing"
Case ADODB.ObjectStateEnum.adStateFetching
ObjectStateString = "Fetching"
Case ADODB.ObjectStateEnum.adStateOpen
ObjectStateString = "Open"
Case Else
ObjectStateString = "State " & CLng(ObjectState) & ": unknown state number"
End Select
End Function
Share and enjoy: and watch out for line-breaks, helpfully inserted where they will break the code by your browser (or by StackOverflow's formatting functions).
There no magic function that will test this without actually connecting and trying an operation.
If you feel bad about the random query part - you can query the system tables
For Access
SELECT TOP 1 NAME FROM MSysObjects
For SQL Server
SELECT TOP 1 NAME FROM sysobjects
If you merely have to test that the database server is actually available, this can be done, despite what is being said here that it cannot.
In that case, you can attempt to open a TCP connection to the specific server and port.
The default instance of SQL Server, for example, listens on TCP port 1433. Attempting a simple TCP connection in VBA will tell you if it succeeds or not. Only if that is successful I would query using the ODBC connection.
This is a lot more graceful and efficient. It would remove any "gross" error from your ODBC test code. However, as I said, it is only applicable if you need to test for the mere existence/availability of the database server instance.

Resources