I have a very easy Stored Procedure in SQL (this is my first one!) and I can run it after researching how to accomplish this. Essentially, it deletes all the current records in a table and appends a new set of records. (I have read that having two queries in the same Stored Procedure may cause the problem I am having.)
This works very well the first time I run it. I make a change to the open table to see if it works the second time. It does not. I can even close the database, reopen and rerun the code and it still doesn't give me what I expect.
What I have figured out is that if I try to open the "CurrentProc" query in the Access window, I get an error that says "Pass-through query with ReturnsRecords property set to True did not return any records." That's fine, because after I hit "OK", the code will work again and give me the expected return.
My question is what can I do with the code below so that I can make whatever change I want to in a table, but have it all reset whenever I call the function without having to open the CurrentProc query and getting the error message. (Yes, I have tried opening the query with OpenQuery, but that didn't work either.)
Please understand that, while I have been an Access developer for (yikes!) nearly 20 years, this is my first time trying to use SQL stored procedures. Running this same query in Access takes about 45 minutes. Using the Stored procedure, it literally takes seconds! I will be adapting this for use with much larger recordsets and rewriting some Access code as SQL stored procedures to leverage this power, so any ideas you can provide will be greatly appreciated.
Dim qdf As dao.QueryDef
Dim dbs As dao.Database
Dim rst As dao.Recordset
Dim sSQL As String
strConnect = "ODBC;DRIVER={SQL Server}" _
& ";SERVER=ourserver\equipment" _
& ";DATABASE=BDS"
Set dbs = CurrentDb
Set qdf = dbs.QueryDefs("CurrentProc")
qdf.Connect = strConnect
qdf.SQL = "exec AppendtoFRPbyModel1"
DoCmd.OpenTable "FRP by Model1"
Set rst = Nothing
Set qdf = Nothing
Set dbs = Nothing
Josetta
Here's what worked:
I changed ReturnsRecords to "no" and that didn't do anything, HOWEVER, when I added "DoCmd.OpenQuery "CurrentProc" I did not receive an error (as I did before when I tried to run it outside of code) and I did get the expected results every time. Thank you!!
Related
until few days ago everything was working fine and then I run into this problem.
I wrote some code for Access vba in Microsoft 365 that run SQL query on some local and connected tables.
One of this connected table has a field set as data type Number - Decimal. As I mention, few days ago this field start to return empty string. This are few steps I try to investigate the problem.
I made a local copy of the connected table to make sure the problem was not coming from outside. No difference
I create a simple query access - SELECT * FROM [NameTable] and all the data were there
I run the same query in vba and the field in question return an empty string
I run the access query within vba
Set qdfNew = dbs.QueryDefs("Pippo")
Set RS = qdfNew.OpenRecordset
If Not (RS.EOF And RS.BOF) Then
RS.MoveLast
RS.MoveFirst
For iCurRec = 0 To RS.RecordCount - 1
Debug.Print RS.Fields("HSL_QUANTITA").Value
RS.MoveNext
Next iCurRec
End If
RS.Close
It returns an empty string
5. I change the data type of the table into Number - Integer, Long, Single and Double and in all these cases the query in vba return correct value
6. I modify the code in this way
Set qdfNew = dbs.QueryDefs("Pippo")
Set RS = qdfNew.OpenRecordset
If Not (RS.EOF And RS.BOF) Then
RS.MoveLast
RS.MoveFirst
For iCurRec = 0 To RS.RecordCount - 1
Debug.Print TypeName(RS.Fields("HSL_QUANTITA").Value)
RS.MoveNext
Next iCurRec
End If
RS.Close
While changing the data type the code return in the immediate windows:
String -> Number-Decimal
Single -> Number-Single precision
Double -> Number-Double precision
Integer -> Number-Integer
Long -> Number-Long
It looks like since few days ago vba cannot convert the decimal to a String anymore
I do not own the connected table hence I cannot change the data type.
I try to report the problem to the the Office help desk but they cannot solve the problem since is vba related.
Any suggestion?
Thanks
You have been hit by a recent bug:
Access VBA/DAO code may crash or report incorrect data for Decimal columns
Notice the included link for a temporary work-around.
I'm hoping somebody could provide me with some fresh eyes on my vb script. The main purpose of this script is to execute a stored procedure using some parameters.
The error I get is
'Expected end of statement'
I haven't done much VB scripting but from what I have found so far - this error has been down to some kind of syntax issue. I've looked over this script for many hours and can't see anything obvious. I can only assume it's down to the declaration of adArray (which doesn't look right in my eyes but I haven't been able to find ANY examples of this being declared). This error has only been introduced when I started adding more parameters.
Code:
Const adVarChar = 200
Const adParamInput = 1
Const adArray = 0x2000
Dim cmd
Dim sp
Dim intCode
Dim addIn
Dim groupCode
Dim screens
Dim arrScreens
arrScreens=split(LF06,",")
Set cmd=CreateObject("ADODB.Command")
sp="vfile_dev.dbo.vfp_groupReorder"
Set intCode=CreateObject("ADODB.Parameter")
intCode.Direction=adParamInput
intCode.name="#p_intCode"
intCode.Size=100
intCode.Type=adVarChar
intCode.Value=LF03
Set addIn=CreateObject("ADODB.Parameter")
addIn.Direction=adParamInput
addIn.name="#p_addIn"
addIn.Size=100
addIn.Type=adVarChar
addIn.Value=LF04
Set groupCode=CreateObject("ADODB.Parameter")
groupCode.Direction=adParamInput
groupCode.name="#p_groupCode"
groupCode.Size=100
groupCode.Type=adVarChar
groupCode.Value=LF05
Set screens=CreateObject("ADODB.Parameter")
screens.Direction=adParamInput
screens.name="#p_screens"
screens.Size=100
screens.Type=adArray
screens.Value=arrScreens
With cmd
.ActiveCOnnection = "Provider='sqloledb';Data source='xxx';Integrated Security='SSPI';"
.CommandType = 4
.CommandText = sp
.Parameters.Append intCode
.Parameters.Append addIn
.Parameters.Append groupCode
.Parameters.Append screens
.Execute
End With
Set cmd = Nothing
Set sp = Nothing
Set intCode = Nothing
Set addIn = Nothing
Set groupCode = Nothing
Any help would be much appreciated. Thanks.
EDIT:
For those interested - my solution was to ditch adArray and pass my data through as a comma delimited varchar. I then handle this data in my stored procedure with a simple split function.
I'm fairly sure adArray although defined in the ADO constants is not supported by ADO and was added for future compatibility.
From MSDN - ADO API Reference - DataTypeEnum
A flag value, always combined with another data type constant, that indicates an array of the other data type. Does not apply to ADOX.
This definition suggests it should only be used with another ADO DataTypeEnum constant value to denote an Array of that Data Type.
Although there is some suggestion that ORing the value with another DataTypeEnum constant should work, I found this from the 12 years ago.
From the ADO public newsgroup (microsoft.public.ado)
Discussion: how to use AdArray data type with sql server 7 and stored procedures
Date: 2003-09-29 19:24:10 UTC
Hi David,
adArray is not supported in ADO and was created for future compatibility.
What do you need to achieve? Maybe we could help with another solution
--
Val Mazur
Microsoft MVP
Check Virus Alert, stay updated
http://www.microsoft.com/security/incident/blast.asp
Useful Links
How to use ADODB parameterized query with adArray data type in VBScript? - Suggestion that using adArray is possible.
Carl Prothman - Data Type Mapping - My go to resource for ADO data Type Mapping.
I'm facing timeout issues when performing multiple SELECTs after moving database to a different server, in a relic (VB6 application) I've been tasked to patch up. Things worked flawlessly in the old environemnt, the new one contains carbon copies of the old tables.
NOTE! The new database was built from scratch (that is, DBA ran many CREATE TABLE + INSERT scripts to create carbon copies of tables then fill them with the old data).
This is the error source:
// "conn" is being initialized outside the function
Public Function PerformOperation(ByRef conn as ADODB.Connection, query as string) as Boolean
Dim rs as ADODB.Recordset
//This below is the timeout source
rs.Open conn, query, adOpenStatic, adLockReadOnly
If Not (rs.EOF or rs.BOF) Then
rs.MoveFirst
//assign data to many variables
End If
ExitPoint:
If Not (rs Is Nothing) Then
If (rs.State = adStateOpen) Then rs.Close
Set rs = Nothing
End If
Exit Function
Error:
MsgBox "Blah blah"
Resume ExitPoint
Resume 0
End Function
Function is called like this
conn = New ADODB.Connection
conn.ConnectionString = "..."
conn.Open
For i = 1 To RowCount //reading data from a grid component (data is correct!)
//very long select here... kept short
query = "SELECT something FROM somewhere WHERE <manyFields> = <manyValues>"
If PerformOperation(conn, query) = True Then
//UPDATE another table based on the SELECT data
// NOTE: this occurs on a DIFFERENT, INDEPENDENT ADODB.Connection object
End If
Next i
The first time PerformOperation is called it goes through fine, second time through it times out no matter how long i set the CommandTimeout. It also works OK if the cycle "cycles" a single time.
Big problem here is, all I have to try things out is the production environment so I'll need to be extra careful. I also don't have a very deep DBA knowledge at hand... Just a very very old piece of software which will eventually be ported to .NET but needs to be dealt with in the meantime...
How can I check and/or fix this issue ? This has to work for any length of the For cycle
Many thanks for any suggestion (as always, if i missed any essential detail point it out and i'll provide it if i can).
EDIT #1
I've expanded the first and secondo code blocks to provide deeper details about what's going on. Comments changed in order to try and fix highlighting (single quotes mess up coloring).
EDIT #2
Enabling Multiple Active Result Sets (MARS) in the connection string didn't help either.
I'm a bit suprised that it has worked so well so far.
You have to close the recordset that you open, otherwise you will use up one database connection for each query you run. The database will reclaim the unused connections after a while, but if you use up too many connections too fast you will reach the limit for the number of connections per user, and the database will refuse any more connections.
The reason that it worked at all with the older database is probably because it created new connections as needed. This has been changed in later versions, and you would have to change the settings to allow the older, more resource wasteful behaviour. Changing that setting is however not a good solution to the problem.
Close the recordset and remove the reference when you don't need it any more. That will free up the connection so that you can use it for another query:
Public Function PerformOperation(ByRef conn as ADODB.Connection, query as string) as Boolean
Dim rs as ADODB.Recordset
'This below is the timeout source
rs.Open conn, query, adOpenStatic, adLockReadOnly
rs.Close()
Set rs = Nothing
' [cut]: PerformOperation returns true if SELECT returns something
End Function
Edit:
There are other open states than adStateOpen, you should probably check against the closed state instead:
If (rs.State <> adStateClosed) Then rs.Close
Issue was solved editing this line:
If PerformOperation(conn, query) = True Then
like this
If PerformOperation(connOther, query) = True Then
Basically, method call has been moved to its own connection, declared exactly like the other one. Now it works, though I don't really know why: this is the result of some wild editing in an attempt to patch things up.
I'm working on a legacy VB6 app here at work, and it has been a long time since I've looked at VB6 or ADO. One thing the app does is to executes SQL Tasks and then to output the success/failure into an XML file. If there is an error it inserts the text the task node.
What I have been asked to do is try and do the same with the other mundane messages that result from succesfully executed tasks, like (323 row(s) affected).
There is no command object being used, it's just an ADODB.Connection object. Here is the gist of the code:
Dim sqlStatement As String
Set sqlStatement = /* sql for task */
Dim sqlConn As ADODB.Connection
Set sqlConn = /* connection magic */
sqlConn.Execute sqlStatement, , adExecuteNoRecords
What is the best way for me to capture the non-error messages so I can output them? Or is it even possible?
The number of rows affected is returned through an optional second argument of the Connnection object's Execute method
Dim num As Long
sqlConn.Execute sqlStatement, num, adExecuteNoRecords
MsgBox num & " records were affected"
Besides having a generic error handler in your routines the ADO connection object has an Errors collection. After performing some action check the errors for a count > 0 and if it is you need to iterate the collection and log all the errors. There is a Clear method if you want to continue after logging.
After making a quick test project I found that declaring my variable using WithEvents VB adds the InfoMessage event. I ran a DBCC CHECKDB command and the InfoMessage event fired once. The pConnection variable had 284 errors in it with all the other messages.
note: the Connection.Errors collection is 0 based.
I think the rows affected is a function of the Query Analyzer/Enterprise manager, and not something returned through the API.
If I recall correctly, using classic ADO, we had to do a MoveLast then a MoveFirst to force all of the records to come over the wire, then do a count of the Recordset.
I also remember something about which cursor type being used affecting the count of records coming back.
Other than that, are you trying to grab the print statement... It seems like you are using no stored procedures, so beyond count, what are you expecting to get?
I'm trying to retrieve a varbinary output value from a query running on SQL Server 2005 into Classic ASP. The ASP execution just fails when it comes to part of code that is simply taking a varbinary output into a string. So I guess we gotta handle it some other way.
Actually, I'm trying to set (sp_setapprole) and unset (sp_unsetapprole) application roles for a database connection. First I'd set the approle, then I'd run my required queries and finally unset the approle. During unsetting is when I need the cookie (varbinary) value in my ASP code so that I can create a query like 'exec sp_unsetapprole #cookie'. Well at this stage, I don't have the cookie (varbinary) value.
The reason I'm doing this is I used to get 'sp_setapprole was not invoked correctly' error when trying to set app roles. I've disabled pooling by appending 'OLE DB Services = -2;Pooling=False' into my connection string.
I know pooling helps performance wise but here I'm facing big problems.
Please help me out to retrieve a varbinary value into an classic ASP file or suggest a way to set & unset app roles. Either way solutions are appreciated.
Thanks,
Nandagopal
Maybe you could try casting your VARBINARY datatype to IMAGE, which is old enough that it might be able to be used by "Classic" ASP. Just a thought. Could be wrong.
The easiest way is to store the varbinary value from sp_setapprole in an ADO recordset and keep that value around, not worrying about the actual type (you should be able to store the value in an array of bytes, though).
Then, when you need to place that varbinary value in your final sp_setapprole, you can simply use the recordset value. Do this by invoking sp_setapprole using a ADODB.Command object:
'--untested, syntax could be slightly off'
Set myCommand = Server.CreateObject("ADODB.Command")
With myCommand
.ActiveConnection = myConnection
.CommandType = adCmdStoredProc
.CommandText = "sp_unsetapprole"
.Parameters.Append _
.CreateParameter("#Cookie", adLongVarBinary, adParamInput, fileSize)
.Parameters(str_ParamName).Attributes = adFldLong
.Parameters(str_ParamName).AppendChunk myRecordset.Fields("Cookie").Value
.Execute
End With
Perhaps you can also get some insights from this Stackoverflow question.