Karen Schaefer
asked on
Using Scope_Identity with an Update Query
found this At stackoverflow - How do I convert it to use an Update query instead of an Append query - Drawing a blank.
I need to update the following for the newly created RecordID. using the SCOPE_IDENTITY()"
ERROR MSG
Dim rs As ADODB.Recordset
Dim cn As Connection
Dim SQLStr As String
Dim serverName As String
Dim databaseName As String
serverName = "MSSQLServer"
databaseName = "QA"
cxnStr = "Driver={SQL Server};Server=" & serverName & ";Database=" & databaseName & ";"
SQLStr = "INSERT INTO DataSheet(databaseUserID, currentTimestamp)
VALUES (1, CURRENT_TIMESTAMP); SELECT SCOPE_IDENTITY()"
Set cn = New ADODB.Connection
cn.Open cxnStr
Set rs = New ADODB.Recordset
rs.Open SQLStr, cn, adOpenKeyset, adLockOptimistic
MsgBox (rs.Fields(0).Value)
I need to update the following for the newly created RecordID. using the SCOPE_IDENTITY()"
sCmd.CommandText = "[ISCenter_Monitor].[usp_log_ISCenter_Event]" & _
" @EventName='" & ReportName & "'," & _
" @ModuleName='" & MODNAME & "'," & _
" @ProcedureName='" & ProcName & "'"
Debug.Print sCmd.CommandText
Set sRC = sCmd.CreateParameter(MyValue, adInteger, adParamReturnValue)
' Set sRC = sCmd.CreateParameter("EventID", adInteger, adParamReturnValue)
sCmd.Parameters.Append sRC
sCmd.Execute
ERROR MSG
Nice SQL syntax tutorials here
http://www.w3schools.com/sql/sql_update.asp
Although for myself, I always do updates through VBA recordset code.
Much easier to test and debug without screwing up the data, but...
The syntax is
UPDATE table_name
SET column1=value1,column2=val ue2,...
WHERE some_column=some_value;
so
Update DataSheet
SET databaseUserID=Something,c urrentTime stamp=curr entTimesta mp,...
WHERE some_column=some_value;
I think, though that you are looking to do that on the SQL Server side
You are hoping to get SQL Server to use
SELECT SCOPE_IDENTITY()
and update some field with it.
9 for 10 that will involve writing a new sproc on the server -- because I don't think you'll get that to happen in a passthrough. You could write a passthrough to retrieve the result of the T-SQL 'SELECT SCOPE_IDENTITY()' and then use that value in another passthrough
"EXEC [ISCenter_Monitor].[usp_lo g_ISCenter _Event]" & "' " & ReportName & "'," & _
" '" & MODNAME & "'," & " " & ProcName & "'"
Although, where in there is that 'SELECT SCOPE_IDENTITY()' meant to go?
Remember, the syntax for Access to execute a passthrough is just
EXEC SomeSproc 'StringValue', IntegerValue,'DateValueAsL iteralStri ng'
http://www.w3schools.com/sql/sql_update.asp
Although for myself, I always do updates through VBA recordset code.
Much easier to test and debug without screwing up the data, but...
The syntax is
UPDATE table_name
SET column1=value1,column2=val
WHERE some_column=some_value;
so
Update DataSheet
SET databaseUserID=Something,c
WHERE some_column=some_value;
I think, though that you are looking to do that on the SQL Server side
You are hoping to get SQL Server to use
SELECT SCOPE_IDENTITY()
and update some field with it.
9 for 10 that will involve writing a new sproc on the server -- because I don't think you'll get that to happen in a passthrough. You could write a passthrough to retrieve the result of the T-SQL 'SELECT SCOPE_IDENTITY()' and then use that value in another passthrough
"EXEC [ISCenter_Monitor].[usp_lo
" '" & MODNAME & "'," & " " & ProcName & "'"
Although, where in there is that 'SELECT SCOPE_IDENTITY()' meant to go?
Remember, the syntax for Access to execute a passthrough is just
EXEC SomeSproc 'StringValue', IntegerValue,'DateValueAsL
Here's an actual intelligible bit on how to use Scope_Identity
http://technet.microsoft.com/en-us/library/ms190315.aspx
You'll DEFINITELY need to write a new sproc that itself executes [ISCenter_Monitor].[usp_lo g_ISCenter _Event] if you are going to use it!
http://technet.microsoft.com/en-us/library/ms190315.aspx
You'll DEFINITELY need to write a new sproc that itself executes [ISCenter_Monitor].[usp_lo
ASKER
Thanks for all the info.
To clarify, I want to use VBA to execute sprocs. here is my current SPROC - that does inlcude the @@IDENTITY value set. The first portion of my code that executes the first SProc successfully, however, When it reaches the 2nd exec statement it runs, but returns a null value in the SQL data.
I was ask to avoid using linked tables or dao.recordset types, hence my attempt to find the solution that will execute the SPROC, but I understand that when the Sproc is executed it creates the PK (EventID), it is this value I need in order to update the various fields with in the SQL table (ISCenter_EventLog) remaining fields like the ErrorMsg that occurred on the Access Side of the database.
'
I am looking for the best approach to create an Error log within SQL that is call via VBA that will capture any errors that may occur in the Access databae.
To clarify, I want to use VBA to execute sprocs. here is my current SPROC - that does inlcude the @@IDENTITY value set. The first portion of my code that executes the first SProc successfully, however, When it reaches the 2nd exec statement it runs, but returns a null value in the SQL data.
I was ask to avoid using linked tables or dao.recordset types, hence my attempt to find the solution that will execute the SPROC, but I understand that when the Sproc is executed it creates the PK (EventID), it is this value I need in order to update the various fields with in the SQL table (ISCenter_EventLog) remaining fields like the ErrorMsg that occurred on the Access Side of the database.
'
I am looking for the best approach to create an Error log within SQL that is call via VBA that will capture any errors that may occur in the Access databae.
USE [TRACI_ANALYTICS]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [ISCenter_Monitor].[usp_log_ISCenter_Event]
(
@EventID integer = NULL
, @EventName nvarchar(255) = NULL
, @ModuleName nvarchar(255) = NULL
, @ProcedureName nvarchar(255) = NULL
, @EventStep nvarchar(255) = NULL
, @EventStepParentID integer = NULL
, @AffectedRows integer = NULL
, @StepSucceeded bit = NULL
, @ErrorMessage nvarchar(512) = NULL
, @AdditionalInfo nvarchar(1024) = NULL
)
AS BEGIN
--========================================================================================
--
-- SCRIPT: usp_log_ISCenter_Event
--
-- --
-- DESCRIPTION: Logs an event to ISCenter_Monitor].[ISCenter_EventLog]
--
-- The following parameters are used only when an event entry is being created.
-- These parameters will be ignored when closing an event; no error will be raised.
-- (@EventID is NULL):
-- @EventName
-- @ModuleName
-- @ProcedureName
-- @EventStep
-- @EventStepParentID
--
-- CHANGE HISTORY
-- DATE BY ISSUE # DESCRIPTION
-- ------------ ------- --------------- -----------------------------------------------------------
-- 27-June-2013 49mwg Created sproc.
--
--========================================================================================
SET NOCOUNT ON
DECLARE @OpenEventID integer
DECLARE @EndDate datetime
DECLARE @RETVAL integer
BEGIN TRY
IF @EventID IS NULL
BEGIN
-- Creating a new event log entry
-- If @EventStepParentID is provided, verify that the ParentID exists.
IF @EventStepParentID IS NOT NULL
BEGIN
SELECT @OpenEventID = EventID
FROM [ISCenter_Monitor].[ISCenter_EventLog]
WHERE EventID = @EventStepParentID
IF @OpenEventID IS NULL
BEGIN
RAISERROR ( N'A parent event was specified (EventID = %d), but no matching EventID was found in the event table.'
, 11 -- severity
, 1 -- state
, @EventStepParentID
)
END
END
BEGIN
INSERT INTO [ISCenter_Monitor].[ISCenter_EventLog]
(EventName, EventStartDate, ModuleName, ProcedureName, EventStep, EventStepParentID)
SELECT @EventName
, GETDATE()
, @ModuleName
, @ProcedureName
, @EventStep
, @EventStepParentID
SET @RETVAL = @@IDENTITY
END
END
ELSE BEGIN
-- Closing an existing event log entry
-- Verify that the specified @EventID exists.
IF @StepSucceeded IS NULL
BEGIN
RAISERROR ( N'@StepSucceeded is NULL. You must specify SUCCEED (1) or FAIL (0).'
, 11 -- severity
, 1 -- state
, @EventID
)
END
SELECT @OpenEventID = EventID,
@EndDate = EventEndDate
FROM [ISCenter_Monitor].[ISCenter_EventLog]
WHERE EventID = @EventID
IF @OpenEventID IS NULL
BEGIN
RAISERROR ( N'The specified event (EventID = %d) was not found in the event table.'
, 11 -- severity
, 1 -- state
, @EventID
)
END
IF @EndDate IS NOT NULL
BEGIN
RAISERROR ( N'The specified event (EventID = %d) already has an end date specified. This event may not be updated.'
, 11 -- severity
, 1 -- state
, @EventID
)
END
UPDATE [ISCenter_Monitor].[ISCenter_EventLog]
SET EventEndDate = GETDATE()
, AffectedRows = @AffectedRows
, StepSucceeded = @StepSucceeded
, ErrorMessage = @ErrorMessage
, @AdditionalInfo = @AdditionalInfo
WHERE EventID = @EventID
END
END TRY
BEGIN CATCH
DECLARE @ErrorMsg NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT
@ErrorMsg = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
RAISERROR (@ErrorMsg, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
RETURN -1
END CATCH
RETURN @RETVAL
SET NOCOUNT OFF
END
I was ask to avoid using linked tables or dao.recordset typesSo you were asked to run a world record 100m time AFTER being amputated below both knees :(
It is what it is.
I don't see Select Scope_Identity() anywhere in your T-SQL that you posted
I think what you are going to need is to declare a variable to hold that Identity near the nose of your procedure.
DECLARE @OpenEventID integer
DECLARE @EndDate datetime
DECLARE @RETVAL integer
Declare @MyScopeIdentityValue Integer
--I assume your identities are auto-numbers!
And down below where you are doing the insert you'll need to fill it
BEGIN
INSERT INTO [ISCenter_Monitor].[ISCent
(EventName, EventStartDate, ModuleName, ProcedureName, EventStep, EventStepParentID)
SELECT @EventName
, GETDATE()
, @ModuleName
, @ProcedureName
, @EventStep
, @EventStepParentID
--SET @RETVAL = @@IDENTITY
--I think that's the problem
--Try
select @MyScopeIdentityValue = Scope_Identity()
END
And then when you are doing your update, use @MyScopeIdentityValue wherever you need it here.
UPDATE [ISCenter_Monitor].[ISCent
SET EventEndDate = GETDATE()
, AffectedRows = @AffectedRows
, StepSucceeded = @StepSucceeded
, ErrorMessage = @ErrorMessage
, @AdditionalInfo = @AdditionalInfo
WHERE EventID = @EventID
For Scope_Identity, the key is that you have to get it between the BEGIN and END where the record creation is happening
ASKER
ok how do I call this and use the value of the Scope_Identity() from within the VBA in Access, since I am trrying to capture the "error Msg" from Access?
K
K
On the Access side, create a pass-through query that returns records
In VBA you are then going to alter that pass-through's SQL, and then execute it
In DAO, it would be
Dim db As Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim strSQL as string
Set db = CurrentDb
Set qdf = db.QueryDefs("TheNameOfYou rPassThrou gh")
strSQL = "exec TheNameOfYourSproc parameter1, parameter2, Parameter3"
Set rs = qdf.OpenRecordset(dbOpenDy naset, dbSeeChanges)
You'd then use rs!WhateverField however you'd need to
ADO has different syntax, but the idea is the same.
The thing is -- you are passing everything in to a sproc, so why does anything need to come back to Access? Isn't the sproc going to do all this?
In VBA you are then going to alter that pass-through's SQL, and then execute it
In DAO, it would be
Dim db As Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim strSQL as string
Set db = CurrentDb
Set qdf = db.QueryDefs("TheNameOfYou
strSQL = "exec TheNameOfYourSproc parameter1, parameter2, Parameter3"
Set rs = qdf.OpenRecordset(dbOpenDy
You'd then use rs!WhateverField however you'd need to
ADO has different syntax, but the idea is the same.
The thing is -- you are passing everything in to a sproc, so why does anything need to come back to Access? Isn't the sproc going to do all this?
Ok, here's a little sproc I built to demo it
And here's a query on the T-SQL side that uses that sproc and returns values
And it nicely returns 1 row, with the Identity value and three inputs
And in VBA I have
And I get a nice messagebox with the autonumber created by the sproc
Alter PROCEDURE SpTestScopeIdentity
-- Add the parameters for the stored procedure here
@JobID int = 0,
@Path nvarchar(255) = '',
@FileName nvarchar(255) = ''
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare @MyScopeIdentityValue int
-- Insert statements for procedure here
Insert into tblPictures (JobID, Path, Filename)
select @JobID,@Path,@FileName
select @MyScopeIdentityValue = Scope_Identity()
END
select @MyScopeIdentityValue,@JobID,@Path,@FileName
GO
And here's a query on the T-SQL side that uses that sproc and returns values
USE [TI_Data]
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[SpTestScopeIdentity]
@JobID = 1,
@Path = 'w:\ti\',
@FileName = '1.jpg'
GO
And it nicely returns 1 row, with the Identity value and three inputs
And in VBA I have
Dim db As Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim strSQL As String
Set db = CurrentDb
Set qdf = db.QueryDefs("qrySpTestScopeIdentity")
strSQL = "exec SpTestScopeIdentity 1, 'w:\ti\', '1.jpg'"
Set rs = qdf.OpenRecordset(dbOpenDynaset, dbSeeChanges)
MsgBox rs.Fields(0)
And I get a nice messagebox with the autonumber created by the sproc
ASKER
I need to caputre any errors that happen in Access and store the error information in the Sql tables.
so if this can be done inn Sproc - great, the problem I have had in the past is that I can execute the first portion Insert query, however when I attempt to update the same record - it can't find the record or If I include the remaining fields in the original Insert Query - it returns "NULL" values for the Error Message, etc.
Please keep in mind that I am new to SPROC creation and SQL Server. I am more an Access Person.
Thanks,
K
so if this can be done inn Sproc - great, the problem I have had in the past is that I can execute the first portion Insert query, however when I attempt to update the same record - it can't find the record or If I include the remaining fields in the original Insert Query - it returns "NULL" values for the Error Message, etc.
Please keep in mind that I am new to SPROC creation and SQL Server. I am more an Access Person.
Thanks,
K
I definitely an Access dude -- but SQL server makes a great back-end
Here's ADO code to use my test sproc
Does strSQL make sense to you?
That's all you are doing -- passing in EXEC someparameter, anotherparameter, anotherparamter (with the correct SQL delimiters for strings, of course)
Now, my simple sproc just spit the Scope_Identity back -- but at this point it is easy enough to do other stuff with it -- either in the sproc, or back in Access
Here's ADO code to use my test sproc
Dim cn As ADODB.Connection
Dim strSQL As String
Set cn = CreateObject("ADODB.Connection")
cn.ConnectionString = "ODBC;Description=ReesRDP;DRIVER=SQL Server;SERVER=REESRDP\SQLEXPRESS05;UID=nickmeyer;Trusted_Connection=Yes;DATABASE=TI_Data"
strSQL = "exec SpTestScopeIdentity 1, 'w:\ti\', '1.jpg'"
cn.Open
Set rs = CreateObject("ADODB.Recordset")
rs.Open strSQL, cn
MsgBox rs.Fields(0)
cn.Close
Set rs = Nothing
Set cn = Nothing
Does strSQL make sense to you?
That's all you are doing -- passing in EXEC someparameter, anotherparameter, anotherparamter (with the correct SQL delimiters for strings, of course)
Now, my simple sproc just spit the Scope_Identity back -- but at this point it is easy enough to do other stuff with it -- either in the sproc, or back in Access
ASKER
Attempting to use the demo version - get the following errors:
Msg 208, Level 16, State 6, Procedure SpTestScopeIdentity, Line 28
Invalid object name 'SpTestScopeIdentity'.
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near '.'.
Msg 2812, Level 16, State 62, Line 2
Could not find stored procedure 'dbo.SpTestScopeIdentity'.
Msg 208, Level 16, State 6, Procedure SpTestScopeIdentity, Line 28
Invalid object name 'SpTestScopeIdentity'.
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near '.'.
Msg 2812, Level 16, State 62, Line 2
Could not find stored procedure 'dbo.SpTestScopeIdentity'.
Look carefully!
I posted it as an ALTER procedure...
Change that to a CREATE procedure
But--you will need to change the tables too
They come from my data!
I posted it as an ALTER procedure...
Change that to a CREATE procedure
But--you will need to change the tables too
They come from my data!
Now,
Here's that sproc altered to do an insert AND then an update
Funny thing was, I DEFINITELY don't like using UPDATE on production data. That's just asking for trouble. So I scripted tblPictures out to a query window and created tblPictures1 to test on.
Guess what? It is doing what you have problems with -- null or zero values being dropped in and not what was inserted or updated
Here's that sproc altered to do an insert AND then an update
Alter PROCEDURE SpTestScopeIdentity
-- Add the parameters for the stored procedure here
@JobID int = 0,
@Path nvarchar(255) = '',
@FileName nvarchar(255) = ''
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare @MyScopeIdentityValue int
-- Insert statements for procedure here
Insert into tblPictures (JobID, Path, Filename)
select @JobID,@Path,@FileName
select @MyScopeIdentityValue = Scope_Identity()
update tblPictures
set [Path] = 'w:\ti\bad\'
where PictureID = @MyScopeIdentityValue
END
select @MyScopeIdentityValue,@JobID,@Path,@FileName
GO
Funny thing was, I DEFINITELY don't like using UPDATE on production data. That's just asking for trouble. So I scripted tblPictures out to a query window and created tblPictures1 to test on.
Guess what? It is doing what you have problems with -- null or zero values being dropped in and not what was inserted or updated
And when I went to go play with it again, now it is inserting correctly and updating correctly.
Go figger!
Go figger!
So, now for nuts and bolts.
When and how is this all to fire?
What does Access know and can pass in via a passthrough when it fires?
Does firing it create data that only Access knows about, or can everything be done in T-SQL in one go with what Access passes in?
And why are we doing an insert and an update?
Are there multiple tables being worked with?
I think I've given you what you need to use Scope_Identity()
Now, what do we need to do to solve your operational problem?
When and how is this all to fire?
What does Access know and can pass in via a passthrough when it fires?
Does firing it create data that only Access knows about, or can everything be done in T-SQL in one go with what Access passes in?
And why are we doing an insert and an update?
Are there multiple tables being worked with?
I think I've given you what you need to use Scope_Identity()
Now, what do we need to do to solve your operational problem?
ASKER
found possible solution - its easier when you finally figure out what word to using when searching the www for information - in this case the word was "OUTPUT", not parameter.
Came accross this.
http://bytes.com/topic/access/answers/205120-get-stored-procedure-output-value-back-vba
after: cmd.Execute Options:=adExecuteNoRecord s
all you need is:
Dim X as long
x = cmd.Parameters("@OutPutVar ")
Note I have not tested it because I am waiting on my coworker to grant me permissions to change the SPROC.
I need to modify it to include the new variable = @outputVar
and
Set that variable to equal @OutPutVar or hard code an actual value for testing purposes.
Have you ever used this approach, Nick?
Thanks for all your great suggestions - I will let you know if this actually resolves the issue - along with the code changes.
K
Came accross this.
http://bytes.com/topic/access/answers/205120-get-stored-procedure-output-value-back-vba
after: cmd.Execute Options:=adExecuteNoRecord
all you need is:
Dim X as long
x = cmd.Parameters("@OutPutVar
Note I have not tested it because I am waiting on my coworker to grant me permissions to change the SPROC.
I need to modify it to include the new variable = @outputVar
and
Set that variable to equal @OutPutVar or hard code an actual value for testing purposes.
Have you ever used this approach, Nick?
Thanks for all your great suggestions - I will let you know if this actually resolves the issue - along with the code changes.
K
Generally, I operate in DAO. Wherever I can, I use VBA DAO recordsets to do my data heavy lifting -- because I never deal with more than a few records at a time, so any mythical performance hit over straight up SQL is miniscule -- and it is a heck of a lot easier to debug
with rs
.edit
!somefield = somevalue
.update
end with
because you can drop a breakpoint on the .update, and then run a mouse over each value in the code window to see what you are going to get.
A SQL update or insert command is not so nice to debug.
I have a whack of passthroughs that return actual recordsets to Access. Generally, the return_value isn't a lot of use to me -- I either got my recordset or I didn't -- and I am not executing sprocs that alter data where I would be looking for a codeback value to tell me about success or failure.
Here was where I hunted down how to get the ADO code right
http://social.msdn.microsoft.com/Forums/office/en-US/2c350f9d-68ea-4039-83b5-33b12bf66ca5/problem-executing-stored-procedure-from-vba-ado-connection
You'll see that early on they are working on a command approach -- which you've now seen can return a parameter back.
I prefer to get the whole recordset back to VBA -- because then I can walk through that to see what I've done. My final iteration of my test sproc is
When I execute it from the Access side, I get a recordset back of all my input parameters, and the resulting field entries. Very easy for me to see if I've got things right!
But returning back the output parameter and building the error-handling into the T-SQL is certainly a valid approach. I am an Access VBA DAO guy. My T-SQL gets used when Access can't handle things quickly. As long as Access is up for it, I code it there.
Trying to debug between multiple layers can be a bugger
KYSS -- Keep your SQL simple!
with rs
.edit
!somefield = somevalue
.update
end with
because you can drop a breakpoint on the .update, and then run a mouse over each value in the code window to see what you are going to get.
A SQL update or insert command is not so nice to debug.
I have a whack of passthroughs that return actual recordsets to Access. Generally, the return_value isn't a lot of use to me -- I either got my recordset or I didn't -- and I am not executing sprocs that alter data where I would be looking for a codeback value to tell me about success or failure.
Here was where I hunted down how to get the ADO code right
http://social.msdn.microsoft.com/Forums/office/en-US/2c350f9d-68ea-4039-83b5-33b12bf66ca5/problem-executing-stored-procedure-from-vba-ado-connection
You'll see that early on they are working on a command approach -- which you've now seen can return a parameter back.
I prefer to get the whole recordset back to VBA -- because then I can walk through that to see what I've done. My final iteration of my test sproc is
Alter PROCEDURE SpTestScopeIdentity
-- Add the parameters for the stored procedure here
@JobID int = 0,
@Path nvarchar(255) = '',
@FileName nvarchar(255) = ''
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare @MyScopeIdentityValue int
-- Insert statements for procedure here
Insert into tblPictures1 (JobID, Path, Filename)
select @JobID,@Path,@FileName
select @MyScopeIdentityValue = Scope_Identity()
update tblPictures1
set [Path] = 'w:\ti\bad\'
where PictureID = @MyScopeIdentityValue
END
select @MyScopeIdentityValue as II,@JobID as iJobID,@Path as iPath,@FileName as iFileName, PictureId,jobID,Path,filename from tblPictures1 where Pictureid= @MyScopeIdentityValue
GO
When I execute it from the Access side, I get a recordset back of all my input parameters, and the resulting field entries. Very easy for me to see if I've got things right!
But returning back the output parameter and building the error-handling into the T-SQL is certainly a valid approach. I am an Access VBA DAO guy. My T-SQL gets used when Access can't handle things quickly. As long as Access is up for it, I code it there.
Trying to debug between multiple layers can be a bugger
KYSS -- Keep your SQL simple!
When you do these kinds of things in DAO, it is pretty straightforward to pull back the identity value
This is a NotInList() event from a combo box. lngOwnerID is the identity value created and was straightforward to pull back to the sub -- although I don't make any use of it in the code I posted. In production, a form is opened, filtered to OwnerId= lngOwnerID
But someone doesn't really want you using what Access is really good at :(_
I have code that does a straight SQL insert -- but doesn't pull back the value for use, too
This code is ADO -- which is what you'd like -- and pulls back the new identity value
Because of how ADO works with cursors
http://www.w3schools.com/ado/prop_rs_cursortype.asp
There isn't any danger that the identity value you haul back will be someone else's
Modifying how you execute your insert, and doing it through VBA and ADO and not using as a sproc, you should be able to haul back the identity value to then do your update through ADO as well.
Private Sub ConsigneeID_NotInList(NewData As String, response As Integer)
Dim db As Database
Dim rs As Recordset
Dim lngOwnerID As Long
If vbYes = MsgBox("'" & StrConv(NewData, vbProperCase) & "' is not entered as a current Client." & vbCrLf & "Do you wish to add it?", vbQuestion + vbYesNo, " ") Then
Set db = CurrentDb
Set rs = db.OpenRecordset("SELECT * FROM [tblClients] WHERE 1=2;", dbOpenDynaset, dbSeeChanges)
With rs
.AddNew
![Client Name] = StrConv(NewData, vbProperCase)
.Update
.Bookmark = .LastModified
lngOwnerID = ![Client ID]
End With
rs.Close
db.Close
Set rs = Nothing
Set db = Nothing
response = acDataErrAdded
Else
response = acDataErrContinue
End If
End Sub
This is a NotInList() event from a combo box. lngOwnerID is the identity value created and was straightforward to pull back to the sub -- although I don't make any use of it in the code I posted. In production, a form is opened, filtered to OwnerId= lngOwnerID
But someone doesn't really want you using what Access is really good at :(_
I have code that does a straight SQL insert -- but doesn't pull back the value for use, too
Set db = CurrentDb
strSQL = "INSERT INTO [tblInsLocations] ([LocationName],[HSTProvince]) VALUES('" & StrConv(NewData, vbProperCase) & "', " & response & ");"
db.Execute strSQL
This code is ADO -- which is what you'd like -- and pulls back the new identity value
Dim rs As ADODB.Recordset
Dim cn As ADODB.Connection
Dim strSQL As String
Dim x As Integer
Dim PicID As Long
Set cn = CreateObject("ADODB.Connection")
cn.ConnectionString = "ODBC;Description=ReesRDP;DRIVER=SQL Server;SERVER=REESRDP\SQLEXPRESS05;UID=nickmeyer;Trusted_Connection=Yes;DATABASE=TI_Data"
'strSQL = "exec SpTestScopeIdentity 1, 'w:\ti\', '1.jpg'"
'not a sproc but a straight table manipulation
strSQL = "select * from tblPictures1"
cn.Open
Set rs = CreateObject("ADODB.Recordset")
rs.Open strSQL, cn, adOpenKeyset, adLockOptimistic
With rs
.AddNew
!JobID = 1
!Path = "w:\ti\"
!Filename = "14.jpg"
.Update
.MoveLast
PicID = !PictureID
End With
cn.Close
Set rs = Nothing
Set cn = Nothing
MsgBox PicID
Because of how ADO works with cursors
http://www.w3schools.com/ado/prop_rs_cursortype.asp
There isn't any danger that the identity value you haul back will be someone else's
Modifying how you execute your insert, and doing it through VBA and ADO and not using as a sproc, you should be able to haul back the identity value to then do your update through ADO as well.
in this case the word was "OUTPUT", not parameter.
Actually, as your Stored Procedure is written here http:#a39453161 there is no need to make any changes whatsoever. You are already returning a special type of output parameter, it is called a RETURN parameter. All you have to do is check for the "RETURN" parameter when the call is complete. If you are not sure, post your MS Access code as is and I can suggest changes.
The OUTPUT parameter is useful when you want to return a scalar data type that is not an integer or when you cannot use the RETURN parameter.
The only minor quibble I have with your Stored Procedure is with your use of @@IDENTITY, I would use SCOPE_IDENTITY() instead. The reason for this, is that if that table has a TRIGGER on it and if that TRIGGER inserts into another table with an identity column, then the @@IDENTITY value would contain the identity value from that other table. Clearly not what you want, but as you can tell the risk involves a lot of Ifs that I should not think is your case. Moral of the story: Get in the habit of always using SCOPE_IDENTITY() instead of @@IDENTITY (unless you are still using SQL Server 7).
Actually, as your Stored Procedure is written here http:#a39453161 there is no need to make any changes whatsoever. You are already returning a special type of output parameter, it is called a RETURN parameter. All you have to do is check for the "RETURN" parameter when the call is complete. If you are not sure, post your MS Access code as is and I can suggest changes.
The OUTPUT parameter is useful when you want to return a scalar data type that is not an integer or when you cannot use the RETURN parameter.
The only minor quibble I have with your Stored Procedure is with your use of @@IDENTITY, I would use SCOPE_IDENTITY() instead. The reason for this, is that if that table has a TRIGGER on it and if that TRIGGER inserts into another table with an identity column, then the @@IDENTITY value would contain the identity value from that other table. Clearly not what you want, but as you can tell the risk involves a lot of Ifs that I should not think is your case. Moral of the story: Get in the habit of always using SCOPE_IDENTITY() instead of @@IDENTITY (unless you are still using SQL Server 7).
ASKER
Ok, Here is my latest attempt:
The problem is the update of data for the existing newly created ID still will not update the necessary fields - Unable to Update the NULL values. Note I am able to get the REturn Value (EventID) for the second portion of the code
I am able to debug the code and there are actual values, however, these values do not update the Null values in the Sql Table.
thanks,
K
The problem is the update of data for the existing newly created ID still will not update the necessary fields - Unable to Update the NULL values. Note I am able to get the REturn Value (EventID) for the second portion of the code
I am able to debug the code and there are actual values, however, these values do not update the Null values in the Sql Table.
thanks,
K
Function ParamSPT(ReportName As String, MODNAME As String, RecCt As Long, ProcName As String, _
sErr As String, nResults As Boolean)
Dim conn As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim parm As ADODB.Parameter
Dim EventID As Long
Dim X As Integer
Const sproc As String = "ISCenter_Monitor.usp_log_ISCenter_Event"
Const connstr = _
"Driver={SQL Server};Server=AQL02;database=TRACI_ANALYTICS;UID=;PWD="
On Error GoTo ParamSPT_Error
conn.ConnectionString = connstr
conn.Open
With cmd
.ActiveConnection = conn
.CommandType = adCmdStoredProc
.CommandText = sproc
.Parameters("@EventName").value = ReportName
.Parameters("@ModuleName").value = MODNAME
.Parameters("@ProcedureName").value = ProcName
End With
cmd.Execute
EventID = cmd.Parameters("@RETURN_VALUE").value
X = EventID
With cmd
.Parameters("@Eventid").value = X
.Parameters("@ErrorMessage").value = sErr
.Parameters("@AffectedRows").value = RecCt
.Parameters("@StepSucceeded").value = nResults
End With
conn.Close
On Error GoTo 0
Exit Function
ParamSPT_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure ParamSPT of Module basErrorEventLog"
End Function
USE [TRACI_ANALYTICS]
GO
/****** Object: StoredProcedure [ISCenter_Monitor].[usp_log_ISCenter_Event] Script Date: 09/04/2013 13:37:42 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [ISCenter_Monitor].[usp_log_ISCenter_Event]
(
@EventID integer = NULL
, @EventName nvarchar(255) = NULL
, @ModuleName nvarchar(255) = NULL
, @ProcedureName nvarchar(255) = NULL
, @EventStep nvarchar(255) = NULL
, @EventStepParentID integer = NULL
, @AffectedRows integer = NULL
, @StepSucceeded bit = NULL
, @ErrorMessage nvarchar(512) = NULL
, @AdditionalInfo nvarchar(1024) = NULL
)
AS BEGIN
--========================================================================================
--
-- SCRIPT: usp_log_ISCenter_Event
--
-- AUTHOR: Mark Gendron (49mwg)
--
-- DESCRIPTION: Logs an event to ISCenter_Monitor].[ISCenter_EventLog]
--
-- The following parameters are used only when an event entry is being created.
-- These parameters will be ignored when closing an event; no error will be raised.
-- (@EventID is NULL):
-- @EventName
-- @ModuleName
-- @ProcedureName
-- @EventStep
-- @EventStepParentID
--
-- CHANGE HISTORY
-- DATE BY ISSUE # DESCRIPTION
-- ------------ ------- --------------- -----------------------------------------------------------
-- 27-June-2013 49mwg Created sproc.
--
--========================================================================================
SET NOCOUNT ON
DECLARE @OpenEventID integer
DECLARE @EndDate datetime
DECLARE @RETVAL integer
BEGIN TRY
SET @RETVAL = 0
IF @EventID IS NULL
BEGIN
-- Creating a new event log entry
-- If @EventStepParentID is provided, verify that the ParentID exists.
IF @EventStepParentID IS NOT NULL
BEGIN
SELECT @OpenEventID = EventID
FROM [ISCenter_Monitor].[ISCenter_EventLog]
WHERE EventID = @EventStepParentID
IF @OpenEventID IS NULL
BEGIN
RAISERROR ( N'A parent event was specified (EventID = %d), but no matching EventID was found in the event table.'
, 11 -- severity
, 1 -- state
, @EventStepParentID
)
END
END
BEGIN
INSERT INTO [ISCenter_Monitor].[ISCenter_EventLog]
(EventName, EventStartDate, ModuleName, ProcedureName, EventStep, EventStepParentID)
SELECT @EventName
, GETDATE()
, @ModuleName
, @ProcedureName
, @EventStep
, @EventStepParentID
SET @RETVAL = SCOPE_IDENTITY()
END
END
ELSE BEGIN
-- Closing an existing event log entry
-- Verify that the specified @EventID exists.
IF @StepSucceeded IS NULL
BEGIN
RAISERROR ( N'@StepSucceeded is NULL. You must specify SUCCEED (1) or FAIL (0).'
, 11 -- severity
, 1 -- state
, @EventID
)
END
SELECT @OpenEventID = EventID,
@EndDate = EventEndDate
FROM [ISCenter_Monitor].[ISCenter_EventLog]
WHERE EventID = @EventID
IF @OpenEventID IS NULL
BEGIN
RAISERROR ( N'The specified event (EventID = %d) was not found in the event table.'
, 11 -- severity
, 1 -- state
, @EventID
)
END
IF @EndDate IS NOT NULL
BEGIN
RAISERROR ( N'The specified event (EventID = %d) already has an end date specified. This event may not be updated.'
, 11 -- severity
, 1 -- state
, @EventID
)
END
UPDATE [ISCenter_Monitor].[ISCenter_EventLog]
SET EventEndDate = GETDATE()
, AffectedRows = @AffectedRows
, StepSucceeded = @StepSucceeded
, ErrorMessage = @ErrorMessage
, @AdditionalInfo = @AdditionalInfo
WHERE EventID = @EventID
END
END TRY
BEGIN CATCH
DECLARE @ErrorMsg NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT
@ErrorMsg = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
RAISERROR (@ErrorMsg, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
RETURN -1
END CATCH
RETURN @RETVAL
SET NOCOUNT OFF
END
GO
As you recall, I had problems with my test table not accepting any values.
And then, POOF!, the problem went away.
I'd look at the table that isn't taking the updates
Can you hand-edit the table in SSMS?
Can you (for testing) create a linked table and hand-edit it in Access?
Can you run an Update query against that linked test table in Access?
You may have a timestamp issue!
Does your table have a timestamp column?
Does it need one?
You do have a primary key, right?
Look over the table (not) taking the updates -- and see if it will take ANY updates first!
And then, POOF!, the problem went away.
I'd look at the table that isn't taking the updates
Can you hand-edit the table in SSMS?
Can you (for testing) create a linked table and hand-edit it in Access?
Can you run an Update query against that linked test table in Access?
You may have a timestamp issue!
Does your table have a timestamp column?
Does it need one?
You do have a primary key, right?
Look over the table (not) taking the updates -- and see if it will take ANY updates first!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Here is my solution - so far. Got it from help from a co-worker. Thanks for all your time and effort - your input was invaluable.
Thanks,
Karen
Thanks,
Karen
Option Compare Database
Option Explicit
Public Const SPROC As String = "ISCenter_Monitor.usp_log_ISCenter_Event"
Public Const ConnStr = _
"Driver={SQL Server};Server=AQL02;database=TRACI_ANALYTICS;UID=;PWD="
Public Sub ErrorLogger()
Dim EventID As Long
Dim RowsAffected As Long
Dim ErrorMessage As String
Dim AdditionalInfo As String
Dim StepSucceeded As Integer
On Error GoTo PROC_ERROR
RowsAffected = 999
ErrorMessage = "Test Error Message #003"
AdditionalInfo = "Testing from MS Access VBA/ADODB"
StepSucceeded = 1
EventID = OpenErrorLogger()
If EventID <> 0 Then UpdateErrorLog EventID, RowsAffected, _
ErrorMessage, AdditionalInfo, StepSucceeded
MsgBox "EventID was " + CStr(EventID)
GoTo PROC_EXIT
PROC_ERROR:
MsgBox Err.Description
Resume PROC_EXIT
PROC_EXIT:
End Sub
Public Function OpenErrorLogger() As Long
On Error GoTo PROC_ERROR
Dim conn As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim EventID As Long
EventID = 0
conn.ConnectionString = ConnStr
conn.Open
With cmd
.ActiveConnection = conn
.CommandType = adCmdStoredProc
.CommandText = SPROC
.NamedParameters = True
.Parameters("@EventName").Value = "Test Event"
.Parameters("@ModuleName").Value = "Test Module"
.Parameters("@ProcedureName").Value = "Test Procedure"
End With
cmd.Execute
EventID = cmd.Parameters("@RETURN_VALUE").Value
GoTo PROC_EXIT
PROC_ERROR:
MsgBox Err.Description
Resume PROC_EXIT
PROC_EXIT:
On Error Resume Next
conn.Close
OpenErrorLogger = EventID
End Function
Public Sub UpdateErrorLog(EventID As Long, RowsAffected As Long, ErrMsg _
As String, AdditionalInfo As String, StepSucceeded As Integer)
On Error GoTo PROC_ERROR
Dim conn As New ADODB.Connection
Dim cmd As New ADODB.Command
conn.ConnectionString = ConnStr
conn.Open
With cmd
.ActiveConnection = conn
.CommandType = adCmdStoredProc
.CommandText = SPROC
.NamedParameters = True
.Parameters("@EventID").Value = EventID
.Parameters("@ErrorMessage").Value = ErrMsg
.Parameters("@StepSucceeded").Value = StepSucceeded
.Parameters("@AffectedRows").Value = RowsAffected
.Parameters("@AdditionalInfo").Value = AdditionalInfo
End With
cmd.Execute
GoTo PROC_EXIT
PROC_ERROR:
MsgBox Err.Description
Resume PROC_EXIT
PROC_EXIT:
On Error Resume Next
conn.Close
End Sub
:)
Glad to be of service
Nick67
Glad to be of service
Nick67
has the look of T-SQL to it.
Are you playing mix-and-match?
Are you looking to create a pass-through query to execute a sproc on the SQL Server side?
Or are you looking to create a VBA/ADO procedure to execute on the MS Access side?
It has to be one or the other.
If it is a passthrough, you are missing EXEC for sure. If it is not a pass-through, all those @ will be a problem.