Delete statement not working in Stored Procedure - sql-server

I am trying delete multiple records from store procedure SQL-Server 2012. I have select and then delete statement, apparently my delete statement is not been called
ALTER PROCEDURE [dbo].[DeleteFunctionsNavigation]
#FunctionName nvarchar(250),
#Function_identity INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT Navigation_Functions.Function_ID
FROM Navigation_Functions
WHERE Navigation_Functions.FunctionName = #FunctionName
SET #Function_identity=SCOPE_IDENTITY()
DELETE FROM Navigation_FunctionHierarchy
WHERE Navigation_FunctionHierarchy.Function_IDs = #Function_identity
RETURN
END

The usage of SCOPE_IDENTITY() is incorrect in this context. Try this
ALTER PROCEDURE [dbo].[DeleteFunctionsNavigation]
#FunctionName nvarchar(250),
#Function_identity INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #Function_identity = Navigation_Functions.Function_ID
FROM Navigation_Functions
WHERE Navigation_Functions.FunctionName = #FunctionName
DELETE FROM Navigation_FunctionHierarchy
WHERE Navigation_FunctionHierarchy.Function_IDs = #Function_identity
RETURN
END

Related

SQL server execute SP from sql table and update

The table below stores sql insert statements and I run those from a sp. I need to also add an insert to the last_run_dt column. I put the code together via existing stackoverflow questions. I need help implementing this in my code, any feedback will be helpful.
How can I update my code to update the last_run_dt column?
Table:
audit_sql_id audit_sql last_run_dt
1 select * from <<need to add last run_dt value>>
2 select * from <<need to add last run_dt value>>
Code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter proc [dbo].[sp_sqlAudit]
#packagename as varchar(255)
as
begin
set nocount on;
if #packagename='SQL_DM_AUDIT'
begin
declare #queries table (audit_sql_id int identity(1,1),sqlscript varchar(max))
declare #str_query varchar(max);
declare #startloop int
declare #endloop int
insert into #queries
select audit_sql
from dw.dbo.audit_sql with(nolock)
select #endloop = max(audit_sql_id), #startloop = min(audit_sql_id)
from #queries
while #startloop < = #endloop
begin
select #str_query = sqlscript
from #queries
where audit_sql_id = #startloop
exec (#str_query)
set #startloop = #startloop + 1
end
end
end
I would suggest a slight refactor something like the below. There's no need to bring the entire list of sql statements into TemDB, just iterate over it and get each statement in turn. I would also always add a #debug parameter to print the sql instead if executing.
create or alter procedure dbo.sqlAudit
#packagename as varchar(255)
as
set nocount on;
declare #str_query varchar(max), #Id int
declare #AuditID table (Id int)
if #packagename='SQL_DM_AUDIT'
begin
insert into #AuditID (Id) /* Get list of IDs */
select audit_sql_id
from dw.dbo.audit_sql
while exists(select * from #AuditID) /* Continue while there are IDs in the list */
begin
select top (1) #Id=Id from #AuditID /* Get an ID */
select #str_query=audit_sql /* Get the sql for the ID */
from dw.dbo.audit_sql
where audit_sql_id=#Id
delete from #AuditID where Id=#Id /* Remove this ID from the list */
begin try
exec (#str_query)
if ##Error=0
begin
update dw.dbo.audit_sql set last_run_dt=GetDate() /* Update date for ID if run successful */
where audit_sql_id=#Id
end
end try
begin catch
/*handle error*/
end catch
end
end
go

Insert trigger: set value from procedure ends with 3609 error

I have to check if a specific value of an insert is null. If it is null, I want to give it a value from a stored procedure. This procedure returns a number like a sequence, but because I have SQL Server 2008 I had to create it myself:
CREATE PROCEDURE dbo.Get_BAV_PERSONALARCHIV_SEQUENCE ( #value BIGINT OUTPUT)
AS
BEGIN TRANSACTION;
INSERT dbo.BAV_Personalarchiv_Sequence WITH (TABLOCKX) DEFAULT VALUES;
ROLLBACK TRANSACTION;
SELECT #value = SCOPE_IDENTITY();
GO
I want to use the created value in my Insert Trigger if 'SYSROWID' is null (if it is null, it should be the only record with it) :
ALTER TRIGGER [dbo].[NT_BAV_PERSONALARCHIV_MITARBEITER_INSERT]
ON [dbo].[NT_BAV_PERSONALARCHIV_MITARBEITER]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
If (SELECT SYSROWID FROM INSERTED) IS NULL
Begin
DECLARE #value BIGINT;
EXECUTE dbo.Get_BAV_PERSONALARCHIV_SEQUENCE #value OUTPUT;
Update dbo.NT_BAV_PERSONALARCHIV_MITARBEITER
SET SYSROWID = #value
where SYSROWID IS NULL
End
END
But sadly it returns with an 3609 error and rolls back the transaction.
Testing only the Execute and Update works without a problem:
DECLARE #value BIGINT;
EXECUTE dbo.Get_BAV_PERSONALARCHIV_SEQUENCE #value OUTPUT;
Update dbo.NT_BAV_PERSONALARCHIV_MITARBEITER
SET SYSROWID = #value
where SYSROWID IS NULL
What am I missing? Thank you for your help!
Ok, I found out that the rollback in the procedure causes the trigger to end with the error. My workaround is to delete the values of the "sequence"-table before I create a new value:
ALTER PROCEDURE dbo.Get_BAV_PERSONALARCHIV_SEQUENCE ( #value BIGINT OUTPUT)
AS
delete from dbo.BAV_Personalarchiv_Sequence
INSERT dbo.BAV_Personalarchiv_Sequence WITH (TABLOCKX) DEFAULT VALUES;
SELECT #value = SCOPE_IDENTITY();
GO

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".

Insert after event trigger in SQL Server

I need to create a trigger in SQL Server for filling a table if an event is done.
My code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[Tr_EsportaMancatiContatti]
ON [dbo].[Lav_CollaudiVodaf_StoricoMancatiContatti]
AFTER INSERT
AS
BEGIN
DECLARE #IDPRATStorico INT;
DECLARE #IDPRAT INT;
DECLARE #CodRichiestaCRM INT;
DECLARE #IDESITO INT;
DECLARE #Telefono VARCHAR;
DECLARE #DataOraContatto INT;
SET NOCOUNT ON;
SET #IDPRATStorico = (SELECT IDPRATStorico FROM inserted);
SET #IDPRAT = (SELECT IDPRAT FROM inserted);
SET #CodRichiestaCRM = (SELECT CodRichiestaCRM FROM inserted);
SET #IDESITO = (SELECT IDESITO FROM inserted);
SET #Telefono = (SELECT Telefono FROM inserted);
SET #DataOraContatto = (SELECT DataOraContatto FROM inserted);
IF #IDESITO = 18 AND count(#IDPRAT) < 3
BEGIN
INSERT Lav_CollaudiVodaf_StoricoMancatiContatti
SET IDPRATStorico=#IDPRATStorico
SET CodRichiestaCRM=#CodRichiestaCRM
SET IDESITO=#IDESITO
SET Telefono=Telefono
SET DataOraContatto=#DataOraContatto
WHERE IdPrat=#IDPRAT;
END
END;
It throws some error.
Target: I have a table filled with contacts, I need to insert these record into another table, if the IDESITO is 18 and the count in the new table is < 3.
Any suggestion is appreciated.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[Tr_EsportaMancatiContatti]
ON [dbo].[Lav_CollaudiVodaf_StoricoMancatiContatti]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO Lav_CollaudiVodaf_StoricoMancatiContatti(
IDPRATStorico,
CodRichiestaCRM,
IDESITO,
Telefono,
DataOraContatto
)
SELECT TOP 3
IDPRATStorico,
CodRichiestaCRM,
IDESITO,
Telefono,
DataOraContatto
FROM INSERTED
WHERE IDESITO = 18
END;
I am not sure what you are trying to achieve with count(#IDPRAT) < 3. I guess you might want only the top 3 rows

Prevent INSERT of NULL values for Stored Procedure

I'm working on a stored procedure that is supposed to update a table Order_TruckDelivery with info from another table Basket_TruckDelivery if the second table has any data. There are two columns in each of the tables: an int id and a datetime column called TruckDeliveryDate. If Basket_TruckDelivery has a date stored for the current basket id, then insert that date into the Order_TruckDelivery table.
Right now, the INSERT will execute regardless if there is anything in the Basket_TruckDelivery table, and this results in a NULL value for the TruckDelveryDate column in the Order_TruckDelivery column. I want to prevent this from happening but am not entirely sure how. Basically, I only want to perform and INSERT into the Order_TruckDelivery table IF the value of TruckDeliveryDate in Basket_TruckDelivery is NOT empty or null.
This is what I have so far...I have not done much work with stored procedures, so I am not sure what I've missed....
ALTER PROCEDURE [dbo].[SaveTruckIntoOrder]
#BasketID INT,
#OrderID INT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE
#TruckDeliveryDate DATETIME
IF(EXISTS(SELECT uidBasket FROM [Basket_TruckDelivery] WHERE [uidBasket] = #BasketID))
BEGIN
SELECT
#TruckDeliveryDate = [TruckDeliveryDate]
FROM
[Basket_TruckDelivery]
WHERE
[uidBasket] = #BasketID
END
BEGIN
INSERT INTO [Order_TruckDelivery] ([uidOrder], [TruckDeliveryDate])
VALUES (#OrderID, #TruckDeliveryDate)
END
END
ALTER PROCEDURE [dbo].[SaveTruckIntoOrder] #BasketID INT
,#OrderID INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #TruckDeliveryDate DATETIME
IF (
EXISTS (
SELECT uidBasket
FROM [Basket_TruckDelivery]
WHERE [uidBasket] = #BasketID
)
)
BEGIN
SELECT #TruckDeliveryDate = [TruckDeliveryDate]
FROM [Basket_TruckDelivery]
WHERE [uidBasket] = #BasketID
END
IF (
#TruckDeliveryDate IS NOT NULL
AND #TruckDeliveryDate != ''
)
BEGIN
INSERT INTO [Order_TruckDelivery] (
[uidOrder]
,[TruckDeliveryDate]
)
VALUES (
#OrderID
,#TruckDeliveryDate
)
END
END

Resources