I've got a trigger on a table. It's a very simple trigger, set to after insert, send me an e-mail. Since I've put that trigger on, I've been sent e-mails by the system every 5 or 6 minutes or so. There is just one problem.
Whenever I receive an e-mail, the table is EMPTY
Here is my trigger
USE [didaprod]
GO
/****** Object: Trigger [dbo].[Caseplayer_CaseId_Restore_insert_mail] Script Date: 09-08-2016 11:59:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE trigger [dbo].[Caseplayer_CaseId_Restore_insert_mail] on [dbo].[Caseplayer_CaseId_Restore]
AFTER INSERT
as
SET NOCOUNT ON
declare #tekst nvarchar(500);
set #tekst = 'caseid sat til null på caseplayer! Tjek Caseplayer_CaseId_Restore tabel!' + convert(varchar,getdate(),105);
EXEC msdb.dbo.sp_send_dbmail #profile_name = 'Mail',
#recipients = 'kk#byggeevaluering.dk',
#subject = 'CASEID SAT TIL NULL!!!',
#body = #tekst
SET NOCOUNT OFF
GO
I've tried to manually insert a row, or a couple of rows in the table, just to check, and yes, the trigger fires as well, when there is a proper insert. But I cannot explain why I keep receiving the e-mails!. As for the table itself, it's got nothing fancy.
USE [didaprod]
GO
/****** Object: Table [dbo].[Caseplayer_CaseId_Restore] Script Date: 09-08-2016 12:04:46 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Caseplayer_CaseId_Restore](
[Id] [int] NOT NULL,
[CaseId] [int] NOT NULL,
[TimeOfChange] [datetime] NOT NULL
) ON [PRIMARY]
GO
I've disabled the trigger now, and confirmed that the e-mails have stopped. But this seems like an almost magic problem for me, and I would love to get an answer.
Suppose I do
delete from [Caseplayer_CaseId_Restore]
And just leave the table alone.
I'll still get e-mails from the system, telling me to check the table. When I then perform a
select * from [Caseplayer_CaseId_Restore]
The table is empty
SQL Server triggers fire once per statement rather than once per row. That's why it's important to write triggers that use inserted appropriately, to deal with the fact that it may contain 1, many, or zero rows.
I suspect that it's the latter case here. (I.e. a regularly executed INSERT statement that is in fact inserting zero rows)
So, you might want something like:
CREATE trigger [dbo].[Caseplayer_CaseId_Restore_insert_mail]
on [dbo].[Caseplayer_CaseId_Restore]
AFTER INSERT
as
SET NOCOUNT ON
IF EXISTS(select * from inserted)
BEGIN
declare #tekst nvarchar(500);
set #tekst = 'caseid sat til null på caseplayer! Tjek Caseplayer_CaseId_Restore tabel!' + convert(varchar,getdate(),105);
EXEC msdb.dbo.sp_send_dbmail #profile_name = 'Mail',
#recipients = 'kk#byggeevaluering.dk',
#subject = 'CASEID SAT TIL NULL!!!',
#body = #tekst
END
Related
I am adding the date to a column in SQL when the 'workstatus' is 'completed', but my problem is, when I open and save the same job again in the software, it runs the trigger and changes the date again to a new value which I don't want.
I want the trigger to run only if the 'workstatus' value is something else than 'completed'.
GO
/****** Object: Trigger [dbo].[TRJCD_JOBREQUEST] Script Date: 06/25/2021 15:49:04 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[TRJCD_JOBREQUEST] ON [dbo].[TBL_JOBREQUEST]
AFTER UPDATE,INSERT
AS
if (Update (workstatus))
begin
DECLARE #Jobcompletiondate datetime
DECLARE #workstatus VARCHAR(15)
DECLARE #jobid int
select #workstatus = workstatus from inserted
select #jobid = jobid from inserted
select #Jobcompletiondate = GETDATE()
begin
if #workstatus='Completed'
update TBL_JOBREQUEST set JobCompDate=#Jobcompletiondate where jobid = #jobid
end
end
The following is how you should construct your trigger.
There is no need to assign any values to variables, triggers fire once per batch and always operate on the set of updated rows.
If you update a status to Completed you need to check it's not currently Completed, also if you want to retain the first JobCompDate even if the status is amended afterwards simply use a case expression to only update the column where it's currently NULL.
create or alter trigger [dbo].[TRJCD_JOBREQUEST] on [dbo].[TBL_JOBREQUEST]
after update,insert
as
if ##RowCount=0 return
set nocount on
if Update (workstatus)
begin
update t set
t.JobCompDate=case when t.JobCompDate is null then GetDate() else t.JobCompDate end
from inserted i join TBL_JOBREQUEST t on t.jobid=i.jobid
where i.workstatus='Completed'
and not exists (
select * from deleted d
where d.jobid=i.jobid and d.workstatus=i.workstatus
)
end
Please note that I do not have your data set, so I'm unable to test the trigger, however, based on what you provided in your question, I believe this is the answer you are seeking:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[TRJCD_JOBREQUEST] ON [dbo].[TBL_JOBREQUEST]
AFTER UPDATE,INSERT
AS
if (Update (workstatus))
begin
DECLARE #Jobcompletiondate datetime
DECLARE #currentworkstatus VARCHAR(15)
DECLARE #oldworkstatus VARCHAR(15)
DECLARE #jobid int
select #oldworkstatus = workstatus from deleted
select #currentworkstatus = workstatus from inserted
select #jobid = jobid from inserted
select #Jobcompletiondate = GETDATE()
begin
if #currentworkstatus='Completed' and #oldworkstatus <> 'Completed'
update TBL_JOBREQUEST set JobCompDate=#Jobcompletiondate where jobid = #jobid
end
end
You needed to check if the deleted workstatus does not equal Completed and only then should the trigger fire.
I am working with a Old tool and the database that was connected to this tool in long gone. I am new at this and need some help understanding this. I need help with writing the code i tried and error-ed out every time.
public void UpdateUser(string NewUser, string OldUser)
{
using (SqlConnection con = HSDatabaseConnection())
{
using (SqlCommand cmd = new SqlCommand("UpdateNames", con))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("#LogonName", System.Data.SqlDbType.VarChar).Value = NewUser;
cmd.Parameters.Add("#OldLogonName", System.Data.SqlDbType.VarChar).Value = OldUser;
cmd.ExecuteNonQuery();
}
con.Close();
}
}
I have 4 tables the only thing each table has in common is the column name "AN". I need to update "AN" if a agent changes there name legally
so far I have come up with this procedure
USE [HSDB]
GO
/****** Object: StoredProcedure [dbo].[UpdateNames] Script Date: 9/16/2016 12:32:33 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[UpdateNames]
--Add the parameters for the stored procedure here
#AN varchar(MAX)
AS
BEGIN
--SET NOCOUNT ON added to prevent extra result sets from
--interfering with SELECT statements.
SET NOCOUNT ON;
--Insert statements for procedure here
UPDATE Att
SET AN = #AN
WHERE (AN = #AN)
UPDATE MS
SET AN = #AN
WHERE (AN = #AN)
UPDATE Lost
SET AN = #AN
WHERE (AN = #AN)
UPDATE WeeklyCharges
SET AN = #AN
WHERE (AN = #AN)
END
Can some one please tell me what i am doing wrong. Thank you
Issue 1:
your c# code is passing 2 paramaters #LogonName and #OldLogonName but your stored procedure is only accepting 1 parameter #AN. So that should error out.
Issue 2:
all of your update statements are setting AN = to itself because you are saying when AN = #AN then set AN = #AN....
Without having more detail about the error and your data structures, which you should include in the future, it is a little difficult to say. However, you probably could do something like this in SQL-Server 2012 +:
USE [HSDB]
GO
/****** Object: StoredProcedure [dbo].[UpdateNames] Script Date: 9/16/2016 12:32:33 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[UpdateNames]
--Add the parameters for the stored procedure here
#LogonName varchar(100)
,#OldLogonName varchar(100)
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
IF NOT EXISTS (SELECT * FROM LogOnOrUserTable WHERE LogonName = #OldLogonName)
BEGIN
;THROW 51000, 'Old Logon Name Does Not Exists', 1
END
BEGIN TRANSACTION
UPDATE Att
SET AN = #LogonName
WHERE (AN = #OldLogonName)
UPDATE MS
SET AN = #LogonName
WHERE (AN = #OldLogonName)
UPDATE Lost
SET AN = #LogonName
WHERE (AN = #OldLogonName)
UPDATE WeeklyCharges
SET AN = #LogonName
WHERE (AN = #OldLogonName)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0 ROLLBACK TRANSACTION
;THROW
END CATCH
END
What it does:
first tests to see if the old user name exists and if it doesn't throws an error.
then updates all of the tables where AN = old logon name and sets it to the new logon name
if any one of those fails it rolls back the transaction and throws an error so that you don't have a change half made
I've created an automated email that tells my customers when they've ordered a part that's on back order. It uses one SQL view and 2 stored procedures as listd below. My issue is that when I execute it, the first backorder sends an email with the title 'sql server message' and has no sql results in it. All subsequent backorders run properly with the correct subject and data in the body. Is there something I've done wrong in my sp's?
This sp runs first, and builds a list of our customers that have Backordered parts.
USE [001]
GO
/****** Object: StoredProcedure [mfg].[sp_BackorderEmailListing] Script Date: 6/29/2015 4:09:31 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Nicholas Dininno>
-- Create date: <6/15/15>
-- Description: <Runs through a distinct list of Franchisees that have
-- orders on backorder, and passes their info to [mfg].[sp_SendBackorderEmail]>
-- =============================================
ALTER PROCEDURE [mfg].[sp_BackorderEmailListing]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #cmp_code nvarchar(50)
Declare #email nvarchar(Max)
Declare cur_BackOrdSP Cursor
For SELECT DISTINCT [Franchise ID] FROM [001].[mfg].[Backorder_Report]
Open cur_BackOrdSP
Fetch Next From cur_BackOrdSP
While ##FETCH_STATUS = 0
Begin
--find email address
SELECT #email = [cmp_e_mail] FROM [001].[mfg].[Backorder_Report] where [Franchise ID]=#cmp_code
execute [mfg].[sp_SendBackorderEmail] #cmp_code, #email
Fetch Next From cur_BackOrdSP Into #cmp_code
END
Close cur_BackOrdSP
Deallocate cur_BackOrdSP
END
The next part is where the email is built.
USE [001]
GO
/****** Object: StoredProcedure [mfg].[sp_SendBackorderEmail] Script Date: 6/29/2015 4:12:51 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Nick Dininno
-- Create date: 6/25/2015
-- Description: Sends email to Franchisees with backordered parts
-- =============================================
ALTER PROCEDURE [mfg].[sp_SendBackorderEmail]
-- Add the parameters for the stored procedure here
(#cmp_code nvarchar(5), #email nvarchar(50))
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 #profile nvarchar(50)
DECLARE #subject nvarchar(100)
DECLARE #querystr nvarchar (MAX)
set #profile = 'Reports'
set #subject = 'Backorder Report for ' + #cmp_code
set #querystr = 'SET NOCOUNT ON
SELECT [Order #],[Order Date],[Item #],[Description]
FROM [001].[mfg].[Backorder_Report]
WHERE [Franchise ID] = '''+#cmp_code+'''';
EXEC msdb.dbo.sp_send_dbmail
#profile_name = #profile,
#recipients = 'me#company.com',
#subject = #subject,
#body = 'Note: This is an automatic e-mail message generated by the Parts Department.
Our records indicate that you ordered the parts shown below. Unfortunately these parts are currently on backorder. They will be shipped to you as soon as they become available. In the meantime, if you have any questions or concerns regarding this order please contact the Parts Department via email parts#lawndoctor.com or call 732-308-2300 x4.
Thank you!
Parts Department
parts#company.com
',
#query = #querystr
END
The recipient me#company.com will be replaced once i'm sure it works with the #email parameter
My issue here was a syntax issue. In the first procedure I didn't pass the Franchise ID into #cmp_code.
Fetch Next From cur_BackOrdSP
Should have been
Fetch Next From cur_BackOrdSP into #cmp_code
I have created a service broker that stores id's in the queue table. But the problem is when i want to get the id back in the stored procedure it's now formatted as xml. Because the service broker message is XML.
How can i just get the last Id each time because the trigger is fired after an update of a row.
Below my code =>
/****** Object: Trigger [dba].[TriggerCall] Script Date: 6/16/2015 2:55:57 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dba].[TriggerCall] ON [dba].[CallID] FOR UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #MessageBody XML
DECLARE #ID varchar(50)
-- Insert statements for trigger here
--get relevant information from inserted/deleted and convert to xml message
SET #MessageBody = (SELECT Id FROM inserted
FOR XML AUTO)
If (#MessageBody IS NOT NULL)
BEGIN
DECLARE #Handle UNIQUEIDENTIFIER;
BEGIN DIALOG CONVERSATION #Handle
FROM SERVICE [TestServiceInitiator]
TO SERVICE 'TestServiceTarget'
ON CONTRACT [TestContract]
WITH ENCRYPTION = OFF;
SEND ON CONVERSATION #Handle
MESSAGE TYPE [TestMessage](#MessageBody);
END
END
/****** Object: StoredProcedure [dbo].[usp_GetCall] Script Date: 6/16/2015 2:44:27 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_GetCall]
AS
BEGIN
DECLARE #message_type varchar(100)
DECLARE #dialog uniqueidentifier, #message_body XML;
Declare #Object as Int;
Declare #URL as varchar(255)
Declare #ResponseText as Varchar(8000);
Declare #ID as Varchar(38);
WHILE (1 = 1)
BEGIN -- Receive the next available message from the queue
WAITFOR (
RECEIVE TOP(1) #message_type = message_type_name,
#message_body = CAST(message_body AS XML),
#dialog = conversation_handle
FROM dbo.TestQueue ), TIMEOUT 500 if (##ROWCOUNT = 0 OR #message_body IS NULL)
BEGIN
BREAK
END
ELSE
BEGIN
INSERT INTO [dbo].[testtabel]
([id]
,[callid],
[test])
VALUES
('111', '111', #message_body)
END
END CONVERSATION #dialog
END
END
If I understand your question correctly, you're just looking to rehydrate the ID into an int. If that's the case, the following should do:
use tempdb;
create table inserted (id int);
insert into inserted values (1);
declare #message_body xml;
set #message_body= (select * from inserted for xml auto);
select #message_body.value('(/inserted/#id)[1]', 'int');
The magic is the last line (the rest was just setup for me to test).
I'll take this opportunity to clear up a misconception that you seem to have, though. Triggers in SQL server aren't fired per row, but per batch. So, if you run an update against your table and it updates 50 rows, the trigger gets fired once and the inserted (and deleted) table will have 50 rows in it. Just something to take into account.
I am creating first time stored procedure but I don't know why this showing error. I also have many other post but didn't understand if someone can tell what I am doing wrong here.
Stored procedure:
SET ANSI_NULLS ON
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[DeleteOrganization]
#ORG_ID bigint
AS
BEGIN
SET NOCOUNT ON;
delete from Organizations where ORG_ID=#ORGID
delete from Institutes where INS_FK_ORGID=#ORGID
delete from Branches where BRN_ID=#ORGID
END
The variable is declared as #ORG_ID bigint with an underscore but you refer to it without the underscore: #ORGID. Pick one and use it consistently.
This should work:
ALTER PROCEDURE [dbo].[DeleteOrganization]
#ORGID bigint
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM Organizations WHERE ORG_ID = #ORGID
DELETE FROM Institutes WHERE INS_FK_ORGID = #ORGID
DELETE FROM Branches WHERE BRN_ID = #ORGID
END