I have an MS Access application that contains all tables linked to SQL Server, so in MS Access VBA code or query I work with those tables very simple, I access them via name, like [Customers].
Also I have a stored procedure in SQL Server called sp_CopyData which I need to call from my VBA code. How can I do that without creating new connection to SQL Server (I already have it somewhere!? because I have access to tables)?
Or it's impossible? Appreciate any help. Thanks!
The right answer found out, it should be like:
Dim qdef As DAO.QueryDef
Set qdef = CurrentDb.CreateQueryDef("")
qdef.Connect = CurrentDb.TableDefs("[ANY LINKED TABLE TO MS SQL SERVER]").Connect
qdef.SQL = "EXEC sp_CopyData"
qdef.ReturnsRecords = False ''avoid 3065 error
qdef.Execute
Create a pass-through query, and you can then use this through the WHOLE application anytime you need to execute some T-SQL.
The code this becomes:
With CurrentDb.QueryDefs("qPass")
.SQL = "exec sp_copydata"
.ReturnsRecords = False ''avoid 3065 error
.Execute
End With
The code in MS Access works for me:
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
cmd.ActiveConnection = "Provider=SQLOLEDB.1;Persist Security Info=False;Initial Catalog=[DB];Data Source=[PC];Integrated Security=SSPI;"
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "sp_CopyData"
cmd.Parameters.Append cmd.CreateParameter("#param", adVarChar, adParamInput, 255, param)
cmd.Execute
Try:
CurrentProject.Connection.Execute "EXEC sp_CopyData"
References: http://msdn.microsoft.com/en-us/library/office/ff821478(v=office.14).aspx
Related
I am trying to build a database for IT device inventory. It uses an MS Access Office 365 front-end with a SQL 2017 backend.
In the database, we don't want to delete records, simply archive them to another table. To do this, I created a stored procedure in SSMS and verified that it does the job properly.
I want VBA to call this stored procedure. For this procedure, I need to pass it identifying information. In VBA, I am trying to assign the server name value from a form to a variable that I can pass into a call of the stored procedure. I found examples using the EXEC command but Access tells me I must use the Procedure clause.
Private Sub Command148_Click()
Dim SrvNameVar As String
Dim strSQL As String
Dim strParm As String
SrvNameVar = Me.SrvName
strParm = "PARAMETERS [Server Name] As CHAR;"
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Set dbs = CurrentDb
strSQL = strParm & "PROCEDURE dbo.sp_ArchiveServer [Server Name];"
Set qdf = dbs.CreateQueryDef("SrvArchive", strSQL)
dbs.Execute ("SrvArchive")
End Sub
The stored procedure that functions properly in SSMS:
CREATE PROCEDURE sp_ArchiveServer #Server nvarchar(30) AS
BEGIN TRANSACTION;
INSERT INTO FSC.dbo.Archive_Servers ([SrvID],[SID],[SrvName],[Make],
[Model],[SN],[SrvIP],[RemoteMgmt],[OSID],[IsDP],[IsIEMRelay],
[IsGUP],[DatePurch],[WarrantyExp],[RAIDConfig],[PrintSrv],
[ConnectedToUPS],[VirtHost],[VirtMachine])
SELECT FSC.dbo.Servers.*
FROM FSC.dbo.Servers
WHERE FSC.dbo.Servers.SrvName = #Server;
DELETE FROM FSC.dbo.Servers
WHERE FSC.dbo.Servers.SrvName = #Server;
COMMIT;
Currently, you are conflating MS Access SQL dialect with SQL Server dialect. Only MS Access SQL queries supports PARAMETERS. However, you are attempting to run an SQL Server query, specifically to execute a stored procedure.
MS Access does allow pass-through queries to backend databases so you can adjust your QueryDef (defaults to Access backend) to connect to MSSQL database and then run EXEC command. All pass-through queries should conform to SQL dialect of backend.
Private Sub Command148_Click()
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Dim SrvNameVar, strSQL As String
SrvNameVar = Me.SrvName
strSQL = "EXEC dbo.sp_ArchiveServer #Server='" & SrvNameVar &"'"
Set dbs = CurrentDb
Set qdf = dbs.CreateQueryDef("SrvArchive")
' ASSIGN ODBC DSN CONNECTION
qdf.Connect = "ODBC; DATABASE=database; UID=user; PWD=password; DSN=datasourcename;"
qdf.SQL = strSQL
qdf.Execute
End Sub
To effectively use parameterization, consider a different API, namely ADO (extendable to any backend database) instead of DAO (more tailored for Access databases).
Private Sub Command148_Click()
' SET REFERENCE TO Microsoft ActiveX Data Object #.# Library
Dim conn As ADODB.Connection, cmd As ADODB.Command
Dim SrvNameVar As String
SrvNameVar = Me.SrvName
' OPEN DRIVER OR DSN CONNECTION
Set conn = New ADODB.Connection
conn.Open "DRIVER={SQL Server};server=servername;database=databasename;UID=username;PWD=password;"
' conn.Open "DSN=datasourcename"
' OPEN AND DEFINE COMMAND OBJECT
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandText = "sp_ArchiveServer"
.CommandType = adCmdStoredProc
' BIND PARAMETERS BY POSITION AND NOT NAME
.Parameters.Append .CreateParameter("param1", adVarchar, adParamInput, 255, SrvNameVar)
.Execute
End With
conn.close()
Set cmd = Nothing: Set conn = Nothing
End Sub
Create a pass-though query in the Access designer.
You can type in that command in the query (sql view). So, you have a pass-though query,and it will look like this:
EXEC dbo.sp_ArchiveServer #Server='test'
Save the above query. (make sure it is pass through query).
Ok, now your VBA code will look like this:
With CurrentDb.QueryDefs("qryPass")
.SQL = "EXEC dbo.sp_ArchiveServer #Server='" & Me.SrvName & "'"
.ReturnsRecords = False
.Execute
End With
Thank you everyone for your help! With all of the info that you provided, it is now working. To do it, I followed Albert's example creating the Pass Through query first and then appended his code with the information from Parfait and ErikA regarding the connection string. I then added a simple MsgBox command and a Close Form command to make it a little more "pretty". Here is the final code that worked:
Private Sub Command148_Click()
With CurrentDb.QueryDefs("SrvQryPass")
.Connect = "ODBC;DSN=ODBC_17;Description=FSC;Trusted_Connection=Yes;APP=Microsoft Office;DATABASE=FSC;Network=DBMSSOCN;"
.SQL = "EXEC dbo.sp_ArchiveServer #Server='" & Me.SrvName & "'"
.ReturnsRecords = False
.Execute
End With
MsgBox "Archived!"
DoCmd.Close
End Sub
I have an Access DB that has a bunch of linked tables from a SQL Server database. The Access DB calls a stored procedure on the SQL Server database that updates data on a form.
Dim sql As String
Dim cnn As ADODB.Connection
Set cnn = New ADODB.Connection
cnn.ConnectionString = "DSN=Records"
cnn.CommandTimeout = 90
cnn.Open
sql = "exec myStoredProcedure #param1=" & Me.txtParam1Field & ", #param2=" & Me.txtParam2Field
cnn.Execute sql
Set cnn = Nothing
frmMyForm.Requery
When I run this it either times out, if the CommandTimeout value isn't long enough, or it executes, but doesn't actually execute myStoredProcedure for some reason. If I take the string sql and past it into Sql Server Manager, myStoredProcedure executes in less than a second and everything works great.
I've tried debugging over this code in Access, but I'm not getting any useful results when I step over cnn.Execute sql.
Depending on the values of txtParam1Field and txtParam2Field you probably want to enclose the values with single quote like so:
sql = "exec myStoredProcedure #param1='" & Me.txtParam1Field & "', #param2='" & Me.txtParam2Field & "'"
If we take your original code and assume that txtParam1Field is equal to 1 and txtParam2Field is equal to John then your generated sql will not execute because it will look like this:
exec myStoredProcedure #param1=1, #param2=John
Your best bet is to output the value of "sql" variable in debug window and run that exact statement in sql query manager. That will tell you exactly where the problem is if it's malformed SQL.
You could try setting the Prepared property to false on the command object. This causes a recompile of the procedure before execution, but could result in a better plan depending on the parameters that are sent.
Dim sql As String
Dim cnn As ADODB.Connection
Dim Cmd As ADODB.Command
Set cnn = New ADODB.Connection
cnn.ConnectionString = "DSN=Records"
cnn.CommandTimeout = 90
cnn.Open
sql = "exec myStoredProcedure #param1=" & Me.txtParam1Field & ", #param2=" & Me.txtParam2Field
Set Cmd = New ADODB.Command
Set Cmd.ActiveConnection = cnn
Cmd.CommandType = adCmdText
Cmd.CommandText = sql
Cmd.Prepared = False
Cmd.CommandTimeout = 300
Cmd.Execute
I have a Proc for creating and updating a table in SQL Sever. The result table is linked to the MS ACCESS FE. It was before created by Macro involving queries in MS Access. How could I call or execute the Proc from MS Access FE.
I tried this code but it doesn't result in anything.
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
cmd.ActiveConnection = "Provider=SQLNCLI11.1;Security=SSPI;Initial Catalog=MYDB;Server=MyServer;Integrated Security=SSPI;"
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "UPDATE_DATA"
cmd.Execute
I'm new to VBA Coding. Any help or leads will be greatly appreciated.
In your code, you haven't opened a connection to the database. Open a connection first like in the below code:
Private Const gcConn As String = "Provider=SQLNCLI11.1;Security=SSPI;Initial Catalog=MYDB;Server=MyServer;Integrated Security=SSPI;"
Sub UpdateProc()
Dim oDB As ADODB.Connection
Dim oCM As ADODB.Command
Set oDB = New ADODB.Connection
oDB.Open gcConn
Set oCM = New ADODB.Command
With oCM
.ActiveConnection = oDB
.CommandType = adCmdStoredProc
.CommandText = "UPDATE_DATA"
.Execute
End With
oDB.Close
Set oDB = Nothing
End Sub
Simply save your command as a pass-though query. Thus your query is:
UPDATE_DATA
Then this one line of code will run that query
CurrentDb.QueryDefs("MyPass").Execute
I try call this stored procedure in SQL Server that inserts data.
I have this:
CREATE PROCEDURE [dbo].[AddUser]
#user_id bigint,
#user_name varchar(20)
AS
BEGIN
INSERT INTO [users] ([id], [name])
VALUES (#user_id, #user_name)
END
and I have this ASP code:
<%
Const adCmdStoredProc = 4
Const adBigInt = 20
Const adParamInput = 1
Const adVarChar = 200
Set conn = Server.CreateObject("ADODB.Connection")
connectionstring = "Provider=SQLOLEDB.1;Password=***********;Persist Security Info=True;User ID=sa;Initial Catalog=Test;Data Source=AREAWEB2-PC"
conn.Open connectionstring
Set cmd = Server.CreateObject("ADODB.Command")
Set cmd.ActiveConnection = conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "{call AddUser (?,?)}"
frm_id = 1
frm_name = "Carlos"
Set prmUserId = cmd.CreateParameter("#user_id", adBigInt, adParamInput, 0, frm_id)
Set prmUserName = cmd.CreateParameter("#user_name", adVarChar, adParamInput, 20, frm_name)
Cmd.Parameters.Append prmUserId
Cmd.Parameters.Append prmUserName
Set rs = cmd.Execute
%>
But I get this error message:
Microsoft OLE DB Provider for SQL Server error '80040e10'
What is wrong ?
If you Google the error code 80040e10 it becomes apparent quickly that the issue is one of the following to do with your parameter definitions;
From Why do I get 80040E10 errors?
Microsoft OLE DB Provider for SQL Server error '80040e10'
Procedure '' expects parameter '', which was not supplied.
Your issue is likely due to passing a 0 size in your #user_id parameter, as all parameters have to pass a maximum size either using .CreateParameter() or before appending a parameter to the collection using .Size property.
Update:
As the OP has pointed out the issue is actually due to the wrong CommandType property value being set.
Thought it would be worth expanding the answer to explain why. The reason is the CommandType in the OP's example is set to adCmdStoredProc but the .CommandText property is not set to a Stored Procedure name, the easiest way to correct this (instead of removing the .CommandType) is to change the .CommandText as follows;
cmd.CommandText = "AddUser"
The other option is to change the .CommandType to adCmdText which will accept the format {call AddUser (?,?)}.
cmd.CommandType = adCmdText
Internally ADO uses adCmdText for the adCmdStoredProc CommandTypeEnum as the .CommmandText will get changed to the format {call AddUser (?,?)}, the difference is you cannot use this form yourself unless you specify .CommandType = adCmdText. There is no additional benefits to using either one, but in my opinion adCmdStoredProc just simplifies the calls and hides the nuts and bolts from you.
The code fails because I have these incorrect:
cmd.CommandType = adCmdStoredProc
Removing it, works.
I have an Excel 2007 file in which I do a lot of dataprocessing (merely reporting) using remote connections to a SQL Server db. When a report has been processed I would like to update a specific field of a table that resides on the same SQL Server db. Something like:
UPDATE [MetricsCollection].[dbo].[tblBatchFeeder]
SET datReportProcessed = CURRENT_TIMESTAMP
WHERE intID = 48
What's the simplest way to approach this?
Kind regards,
Paul.
It would probably be best to have a procedure on the server.
Dim cn As New ADODB.Connection
Dim cmd As New ADODB.Command
cn.Open ServerConnect ''http://connectionstrings.com
cmd.ActiveConnection = cn
cmd.CommandText = "UpdateMetrics" ''stored procedure
cmd.CommandType = adCmdStoredProc
cmd.Parameters("#intID").Value = 48 ''Parameter
cmd.Execute recs