Insert Into SomeTable Exec StoredProcedure #Param1 = #param1, #Param2 = 'system' is not calling Stored Procedure - sql-server

I have a scenario where I need to run a stored procedure individually as well as I need to call from some other stored procedure.
Let me present the scenario: I have 3 stored procedures in sequential call from another one. Like 1st stored procedure is getting called from the application when some raw financial data is being imported; 2nd stored procedure is getting called from 1st stored procedure and in 2nd stored procedure, there is a While loop in which my 3rd stored procedure is getting called.
I am posting here 2nd and 3rd stored procedure code here:
2ND stored procedure code:
If #loopCount > 0
Begin
While(#i <= #loopCount)
Begin
Select #RecoString = '',
#CompanyId = 0,
#UserId = 0
Select #RecoString = MainRecord,
#CompanyId = CompanyId,
#UserId = UsersId
From #RecoData With (Nolock)
Where Id = #i
Order By Id
/* 3rd stored procedure is getting called - IF NO INSERT Statement */
----Exec USP_Temp #IsReco = 1,#ReconcileBy = 'system',#UserCompanyId = #UserCompanyId,#UserId = #UserId,#finalCollection = #RecoString
/* 3rd stored procedure is NOT getting called - IF INSERT Statement */
Insert Into dbo.ReconcileInsertUpdateLog(TransferDetailId,Msg,ReconcilationId,IsFutureTransferReconciled)
Exec dbo.USP_Temp #IsReco = 1, #ReconcileBy = 'system', #CompanyId = #CompanyId, #UserId = #UserId, #finalCollection = #RecoString, #isAutoReconcile = 0
Set #i = #i + 1
End
End
3RD stored procedure code:
ALTER PROCEDURE dbo.USP_Temp
#IsReco Bit
,#ReconcileBy Nvarchar(250)
,#UserCompanyId int
,#UserId int
,#finalCollection Nvarchar(Max) = ''
,#isAutoReconcile Bit = 0
AS
BEGIN
Set Nocount On;
Declare #TransName Varchar(100)
Select #TransName = 'USP_Temp'
Begin Try
Begin Transaction #TransName
Declare #Msg Nvarchar(Max) = ''
,#ParentReconcilationId Int = 0 -- 07.25.2019
,#IsFutureTransferReconciled Int = 0 -- 07.25.2019
------------------------------------------------------------
-- Return result
------------------------------------------------------------
Insert Into dbo.TempReco(Comments)
Select 'Reached to USP_Temp 1 step ahead of Return final Result'
Select 1 As TransferDetailId
,#Msg As Msg
,#ParentReconcilationId As ReconcilationId -- 07.25.2019
,#IsFutureTransferReconciled As IsFutureTransferReconciled -- 07.25.2019
Commit Transaction #TransName
GoTo EndLevel
End Try
Begin Catch
Set #Msg = Error_Message()
GoTo Error
End Catch
Error:
BEGIN
Insert Into dbo.TempReco(Comments) Select 'Reached to USP_Temp - Error Block'
Rollback Transaction #TransName
Select 0 As TransferDetailId
,#Msg As Msg
,0 As ReconcilationId -- 07.25.2019
,0 As IsFutureTransferReconciled -- 07.25.2019
END
EndLevel:
END
GO
Look at the 2nd stored procedure code, I have commented the code which is working if no insert into statement prior to Exec SPName and when calling stored procedure along with insert into SomeTable prior statement then stored procedure is not getting called. Does anyone have some idea on this?

Related

Cannot see expected PRINT or RAISERROR output when a later error is raised

I'm getting an error message in a stored procedure, saying that I can't insert a NULL value into a table, when I should be getting errors earlier in the code if the value is null.
Here's the relevant part of the stored procedure:
CREATE PROCEDURE [dbo].[udp_AddUpdateStaffVariable]
-- Add the parameters for the stored procedure here
#StaffID int=null,
#VariableTypeID int,
#VariableIntValue int=null,
#VariableVarcharValue varchar(max)=null,
#VariableDatetimeValue datetime=null,
#VariableDecimalValue decimal=null
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
BEGIN TRY
DECLARE #PrintOutput varchar(150)
SET #PrintOutput = '#StaffID = ' + CASE WHEN #StaffID = NULL THEN 'Null' ELSE CONVERT(varchar(20), #StaffID) END
RAISERROR (#PrintOutput, 10, 1) WITH NOWAIT
IF (#StaffID = NULL) -- If the staffid of the current user was not supplied, find it in the Staff table
BEGIN
DECLARE #CurrentUser nvarchar(255) = SUSER_SNAME();
SELECT #StaffID = [StaffID] FROM [dbo].[Staff] WHERE [UserName] = #CurrentUser;
SET #PrintOutput = '#StaffID = ' + CASE WHEN #StaffID = NULL THEN 'Null' ELSE CONVERT(varchar(20), #StaffID) END
RAISERROR (#PrintOutput, 10, 1) WITH NOWAIT
IF #StaffID = NULL -- raise error if staffid wasn't found
BEGIN
RAISERROR (50001 --error number
, 16 -- severity
, 1 --state
, #CurrentUser -- parameter
)
END
END
-- Get the variable data type (used to determine where the variable is stored)
DECLARE #VarDataTypeDesc varchar(20)
DECLARE #StaffVarID int
SELECT #VarDataTypeDesc = dt.[StaffVariableDataType]
FROM [list].[DataTypes] dt INNER JOIN [list].[StaffVariableTypes] svt ON dt.DataTypeID = svt.DataTypeID
WHERE svt.VariableTypeID = #VariableTypeID
-- update or add the staff variable
IF EXISTS (SELECT 1 FROM [dbo].[StaffVariables] WHERE StaffID = #StaffID AND [VariableTypeID] = #VariableTypeID) -- update
BEGIN
IF #VarDataTypeDesc = 'int'
BEGIN -- only update here - other data types are updated further down
UPDATE [dbo].[StaffVariables] SET VariableIntValue = #VariableIntValue WHERE StaffID = #StaffID AND VariableTypeID = #VariableTypeID
END
ELSE -- StaffVariableID is only needed if the variable type is not int
BEGIN
SELECT #StaffVarID = StaffVariableID FROM [dbo].[StaffVariables] WHERE StaffID = #StaffID AND [VariableTypeID] = #VariableTypeID
END
END
ELSE -- insert
BEGIN
IF #VarDataTypeDesc = 'int'
BEGIN
INSERT INTO [dbo].[StaffVariables] (StaffID, VariableTypeID, VariableIntValue)
VALUES (#StaffID, #VariableTypeID, #VariableIntValue)
END
ELSE -- StaffVariableID is only needed if the variable type is not int
BEGIN
DECLARE #StaffVarIDTbl table(ID int)
INSERT INTO [dbo].[StaffVariables] (StaffID, VariableTypeID, VariableIntValue)
OUTPUT INSERTED.[StaffVariableID] INTO #StaffVarIDTbl
VALUES (#StaffID, #VariableTypeID, #VariableIntValue)
SELECT #StaffVarID = ID FROM #StaffVarIDTbl
END
END
-- Cutting out the section where I deal with other variable types besides int here - not relevant to this problem
END TRY
BEGIN CATCH
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT
#ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (#ErrorMessage, -- Message text.
#ErrorSeverity, -- Severity.
#ErrorState -- State.
);
END CATCH;
END
Here's the test procedure run code:
DECLARE #return_value int
EXEC #return_value = [dbo].[udp_AddUpdateStaffVariable]
#VariableTypeID = 1,
#VariableIntValue = 10
SELECT 'Return Value' = #return_value
GO
...and here's the response:
Msg 50000, Level 16, State 2, Procedure dbo.udp_AddUpdateStaffVariable, Line 130 [Batch Start Line 2]
Cannot insert the value NULL into column 'StaffID', table 'SnippingDbName.dbo.StaffVariables'; column does not allow nulls. INSERT fails.
(1 row affected)
Completion time: 2020-06-01T21:17:08.2049072-05:00
So... here's the question. The error seems to indicate that it either never ran the whole, if #StaffID = NULL portion of the code, or it did, and didn't find the StaffID and set the #StaffID variable. But if that were the case, why can't I see the results of my earlier RAISERROR statements?
I initially tried PRINT and switched to RAISERROR when PRINT wasn't working.
SQL Server 2017 Developer Edition, SSMS 15.0.18183.0
It was a syntax error, that people commenting on the question figured out. IF (#StaffID = NULL) should have been, IF (#StaffID IS NULL) Fixing that in all places in the procedure fixed the problem, and altering my test Staff record so UserName doesn't match SUSER_SNAME() resulted in the expected error.

SQL Server - Changes not reflecting everytime until manually doing CHECKPOINT

I am having an issue in SQL Server procedure.
I have two new stored procedures, with the PROC_Main proc performing a bunch of inserts and updates before it calls the PROC_child to pull the updated records back out.
--Child PROC
CREATE PROCEDURE dbo.Proc_Child
#Id int
AS
BEGIN
SELECT * FROM dbo.Employee WHERE Id = #Id AND Status=1
END
--Parent Proc
CREATE PROCEDURE dbo.Proc_Main
#Id int ,#Status varchar(100),#Date datetime
AS
BEGIN
BEGIN TRY
BEGIN TRAN
IF NOT EXISTS (SELECT Id FROM dbo.Employee WHERE Id = #Id)
BEGIN
UPDATE dbo.Employee
SET Status = 3,
Date = getdate()
WHERE Status <> 3
AND Id = #Id
INSERT INTO dbo.Employee (ID,Status,Date)
VALUES (#ID,#Status,#Date)
END
COMMIT
--CHECKPOINT;
EXEC dbo.Proc_Child #Id = #Id
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN
DECLARE #Message VARCHAR(1000) = ERROR_MESSAGE()
DECLARE #Severity INT = ERROR_SEVERITY()
DECLARE #State INT = ERROR_STATE()
RAISERROR(#Message, #Severity, #State)
END CATCH
END
--Procedure call
EXEC Proc_Main #ID=1,#Status=1,#Date='2019-01-01'
I am facing the issue that Proc_Main is not returning the records from PROC_Child every time.
When I am manually doing checkpoint before Proc_Child is called then only it is returning records.
Nothing to do with checkpoint. Based on your code, if you call main proc with Status != 1, your child proc will not return it. Also, why are you doing update if you know that record does not exist? Finally, in the multi-threaded environment this may blow up, you need to lock the id when you checking for the existence.

Stored procedure returns wrong value in asp.net web api

I wrote some procedure code which is return value 1 when it runs successfully.
But it always returns -1(Failed value) when it goes well in ASP.NET Web API.
I tested in SSMS with this case.
USE [MY_DATABASE]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[API_TO_WEB_CREATE_RESOURCE]
#RES_Size = 3019,
#RES_ContentType = N'image/jpeg',
#RES_OriginalName = N'evolving_google_identity_share.jpg',
#RES_GUID = N'b98bd7ee-cb19-49c8-a8dc-3b92b3210b91',
#RES_Path = N'~/Content/resources\\b98bd7ee-cb19-49c8-a8dc-3b92b3210b91',
#RES_Upload_USR_Index = NULL
SELECT 'Return Value' = #return_value
GO
This returns 1
Same code in ASP.NET Web API.
int result = context.API_TO_WEB_CREATE_RESOURCE(
3019,
"image/jpeg",
"evolving_google_identity_share.jpg",
"b98bd7ee-cb19-49c8-a8dc-3b92b3210b91",
"~/Content/resources\\b98bd7ee-cb19-49c8-a8dc-3b92b3210b91",
null
);
This returns -1
And this is my procedure.
USE [MY_DATABASE]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
-- Create date:
-- Description:
-- =============================================
ALTER PROCEDURE [dbo].[API_TO_WEB_CREATE_RESOURCE]
-- Add the parameters for the stored procedure here
#RES_Size int = 0,
#RES_ContentType nvarchar(100) = NULL,
#RES_OriginalName nvarchar(300),
#RES_GUID nvarchar(50),
#RES_Path nvarchar(500),
#RES_Upload_USR_Index int = NULL
AS
BEGIN
DECLARE #RES_RegisteredDatetime datetime = GETDATE()
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRAN
INSERT INTO
dbo.NS_Resource (RES_Size, RES_ContentType, RES_OriginalName, RES_GUID, RES_Path, RES_Upload_USR_Index)
VALUES (#RES_Size, #RES_ContentType, #RES_OriginalName, #RES_GUID, #RES_Path, #RES_Upload_USR_Index);
PRINT '리소스 추가됨'
COMMIT TRAN
RETURN(1);
END TRY
BEGIN CATCH
ROLLBACK TRAN
DECLARE #ERROR_Msg nvarchar = error_message()
RAISERROR('리소스 추가 중 문제 발생됨 %s', 16, 1, #ERROR_Msg)
RETURN (-1)
END CATCH
END
Summary
Expected
Return value 1 and insert new value successfully.
Actual
In SSMS
Return Value 1 and insert new value successfully.
In ASP.NET Web API (This is the problem)
Return Value -1 and insert new value successfully.
It's never a good idea to have multiple return statements in a code module, and SQL is not an exception. Try to rewrite your procedure as follows and see if it will help:
ALTER PROCEDURE [dbo].[API_TO_WEB_CREATE_RESOURCE]
-- Add the parameters for the stored procedure here
#RES_Size int = 0,
#RES_ContentType nvarchar(100) = NULL,
#RES_OriginalName nvarchar(300),
#RES_GUID nvarchar(50),
#RES_Path nvarchar(500),
#RES_Upload_USR_Index int = NULL
AS
DECLARE #RES_RegisteredDatetime datetime = GETDATE();
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #Ret int = -1; -- Failure by default
BEGIN TRY
BEGIN TRAN
INSERT INTO
dbo.NS_Resource (RES_Size, RES_ContentType, RES_OriginalName, RES_GUID, RES_Path, RES_Upload_USR_Index)
VALUES (#RES_Size, #RES_ContentType, #RES_OriginalName, #RES_GUID, #RES_Path, #RES_Upload_USR_Index);
PRINT '리소스 추가됨';
COMMIT TRAN
set #Ret = 1; -- Success
END TRY
BEGIN CATCH
if ##trancount > 0
ROLLBACK TRAN;
DECLARE #ERROR_Msg nvarchar(2048) = error_message();
RAISERROR('리소스 추가 중 문제 발생됨 %s', 16, 1, #ERROR_Msg);
END CATCH;
return #Ret;
go
However, the whole thing looks a bit cumbersome to me. If you are throwing the error to the client from inside the catch block, this should be enough. It will translate into an SQLException in C#, so return value becomes rather irrelevant.
Personally, I don't use the return value; instead, I usually create 2 output parameters, int for the number and nvarchar(2048) for the error message, and assign their values in the catch block without re-throwing. When execution is completed I simply check the value of the #ErrorNumber output parameter, and if it's neither zero nor NULL, I process the error on the client side.

SQL Server stored procedure: wait for a delete's trigger to finish before continuing in the procedure

My stored procedure executes a delete statement that sets off a trigger that can't record who deleted the row, but records a blank for changed_by.
Then the stored procedure updates the changed_by with the username it was given.
Half the time, part 2 of the below stored procedure finds the results of the trigger, the other half of the time, it doesn't find the results of the trigger, so there is nothing to update.
How can I "yield" control and ensure the update's trigger finishes before continuing with the stored procedure?
(In comments you see some things I've tried so far that haven't worked)
DROP PROCEDURE IF EXISTS dbo.deleteAndUpdateChangedByInAuditTrail
GO
CREATE PROCEDURE dbo.deleteAndUpdateChangedByInAuditTrail
(#tableName VARCHAR(100),
#pkIDColName VARCHAR(100),
#pkIDValue NUMERIC,
#delUser VARCHAR(100) )
AS
BEGIN TRANSACTION;
-- PART 1: DO THE DELETE:
DECLARE #JUST_BEFORE_DELETION_TIMESTAMP AS DATETIME2;
SET #JUST_BEFORE_DELETION_TIMESTAMP = CONVERT(varchar, SYSDATETIME(), 121);
DECLARE #DELETION_TEMPLATE AS VARCHAR(MAX);
SET #DELETION_TEMPLATE = 'delete from {THE_TABLE_NAME} WHERE {PK_ID_COL_NAME} = {PK_ID_VALUE}';
SET #DELETION_TEMPLATE = REPLACE(#DELETION_TEMPLATE, '{THE_TABLE_NAME}', #tableName);
SET #DELETION_TEMPLATE = REPLACE(#DELETION_TEMPLATE, '{PK_ID_COL_NAME}', #pkIDColName);
SET #DELETION_TEMPLATE = REPLACE(#DELETION_TEMPLATE, '{PK_ID_VALUE}', #pkIDValue);
--PRINT #DELETION_TEMPLATE
EXEC (#DELETION_TEMPLATE);
COMMIT TRANSACTION;
BEGIN TRANSACTION;
-- PART 2: UPDATE THE AUDIT_TRAIL:
DECLARE #TOTAL_NUM_ROWS_UPDATED_WITH_USERNAME AS NUMERIC;
SET #TOTAL_NUM_ROWS_UPDATED_WITH_USERNAME = 0;
--DECLARE #TOTAL_TRIES_SO_FAR AS NUMERIC;
--SET #TOTAL_TRIES_SO_FAR = 0;
--WHILE #TOTAL_NUM_ROWS_UPDATED_WITH_USERNAME < 1 AND #TOTAL_TRIES_SO_FAR < 5
--BEGIN
--SET #TOTAL_TRIES_SO_FAR = #TOTAL_TRIES_SO_FAR + 1;
--WAITFOR DELAY '00:00:01.000' -- SEEN IT FAIL FOR 4 SECONDS :(
DECLARE #UPDATE_AUDIT_TRAIL_TEMPLATE AS VARCHAR(MAX);
SET #UPDATE_AUDIT_TRAIL_TEMPLATE = 'update AUDIT_TRAIL set changed_by = ''{CHANGED_BY}'' WHERE upper(table_name) = upper(''{THE_TABLE_NAME}'') and table_pk_value = {PK_ID_VALUE} and CONVERT(varchar, changed_at, 121) >= ''{CHANGED_AT}'' ';
SET #UPDATE_AUDIT_TRAIL_TEMPLATE = REPLACE(#UPDATE_AUDIT_TRAIL_TEMPLATE, '{CHANGED_BY}', #delUser);
SET #UPDATE_AUDIT_TRAIL_TEMPLATE = REPLACE(#UPDATE_AUDIT_TRAIL_TEMPLATE, '{THE_TABLE_NAME}', #tableName);
SET #UPDATE_AUDIT_TRAIL_TEMPLATE = REPLACE(#UPDATE_AUDIT_TRAIL_TEMPLATE, '{PK_ID_VALUE}', #pkIDValue);
SET #UPDATE_AUDIT_TRAIL_TEMPLATE = REPLACE(#UPDATE_AUDIT_TRAIL_TEMPLATE, '{CHANGED_AT}', #JUST_BEFORE_DELETION_TIMESTAMP);
--PRINT #UPDATE_AUDIT_TRAIL_TEMPLATE
EXEC (#UPDATE_AUDIT_TRAIL_TEMPLATE);
SELECT #TOTAL_NUM_ROWS_UPDATED_WITH_USERNAME = ##ROWCOUNT;
--END
COMMIT TRANSACTION;
RETURN #TOTAL_NUM_ROWS_UPDATED_WITH_USERNAME;
GO
Triggers don't get executed asynchronously. The next step after the DELETE will not happen until the trigger is finished.
If you are seeing something that makes you think otherwise, there is some other reason for it. It's not because the trigger "didn't finish".

SQL Server if statement does not execute as expected

I am trying to use the following stored procedure but there are some instances WHERE only the incremental happens AND the code does not run. What I need is that, when the program enters the IF statement, either it should run both the statements or None.
Stored procedure goes like this:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spflpunch]
AS
BEGIN
DECLARE #id NUMERIC(18,0)
DECLARE #studname NVARCHAR(50)
DECLARE #punchtime DATETIME
DECLARE #samedaycount NUMERIC(2)
SELECT #id = (MAX(lastid)) FROM [smartswype].[dbo].[read]
PRINT #id
SELECT #studname = studname
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE id =#id
PRINT #studname
SELECT #punchtime = punchtime
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE id = #id
PRINT #punchtime
--SELECT #punchvarchar = CONVERT(VARCHAR(10),#punchtime, 103) + ' ' + CONVERT(VARCHAR(5), #punchtime, 14)
IF #id = (SELECT MAX(id) FROM [SSWYPE_WEBDB].[dbo].[attdview])
BEGIN
SELECT #samedaycount = COUNT(*)
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE (studname = #studname
AND CONVERT(DATE, punchtime) = CONVERT(DATE, #punchtime)) -- If firstpunch = 1 then it is the first punch
PRINT #samedaycount
IF #samedaycount =1
BEGIN
INSERT INTO [smartswype].[dbo].[firstlastpunch] ([studname], [DATE], [punch1], [punch2])
VALUES(#studname, CONVERT(DATE, #punchtime), #punchtime, NULL);
UPDATE [smartswype].[dbo].[read]
SET lastid = #id + 1;
END
ELSE IF (#samedaycount > 1)
BEGIN
UPDATE [smartswype].[dbo].[firstlastpunch]
SET punch2 = #punchtime
WHERE (studname = #studname AND DATE = CONVERT(DATE, #punchtime));
UPDATE [smartswype].[dbo].[read]
SET lastid = #id + 1;
END
END
END
If you want to ensure that both or none of the statements run, you should wrap the contents of the if statement in a transaction.
By wrapping it in a transaction, you can ensure that if one statement fails, that the other statement will not run.
Here is a link to the docs on transactions in SQL Server
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/commit-transaction-transact-sql

Resources