Sending email using sp_send_dbmail() does not work sometimes - sql-server

I am sending notification email using SQL Server but sometimes emails aren't sent to users.
Here is my SQL table that I store emails which it will be sent to users
CREATE TABLE [dbo].[EmailNotification](
[Id] [INT] IDENTITY(1,1) NOT NULL,
[EmailAdress] [NVARCHAR](50) NULL,
[EmailBody] [NVARCHAR](500) NULL,
[EmailSubject] [NVARCHAR](250) NULL,
[Attachment] [NVARCHAR](500) NULL,
[EmailSent] [BIT] NULL CONSTRAINT [DF_EmailNotification_EmailSent] DEFAULT
((0)),
[EmailCreateDate] [DATETIME] NULL CONSTRAINT
[DF_EmailNotification_EmailCreateDate] DEFAULT (GETDATE()),
[EmailSentDate] [DATETIME] NULL,
CONSTRAINT [PK_EmailNotification] PRIMARY KEY CLUSTERED
([Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
And I have created a job which executes this procedure every 1 minute
CREATE PROCEDURE [dbo].[spSendEmail]
AS
BEGIN
BEGIN TRAN
DECLARE #id BIGINT
DECLARE #max_id BIGINT
DECLARE #query NVARCHAR(1000)
DECLARE #EmailBody NVARCHAR(1000)
DECLARE #EmailAdress NVARCHAR(500)
DECLARE #EmailSubject NVARCHAR(500)
DECLARE #attachments NVARCHAR(1000)
if exists (SELECT * FROM dbo.EmailNotification where EmailSent=0)
begin
SELECT #id=MIN(id) FROM dbo.EmailNotification where EmailSent=0
SELECT #EmailAdress=EmailAdress,#EmailBody=EmailBody,#EmailSubject=EmailSubject,#attachments=Attachment
FROM EmailNotification WHERE id = #id
exec [msdb].[dbo].[sp_send_dbmail] #profile_name='Notification',
#recipients=#EmailAdress,
#blind_copy_recipients='example.email.com',
#subject=#EmailSubject,
#body=#EmailBody,
#file_attachments=#attachments
end
IF(##ERROR>0)
BEGIN
ROLLBACK
END
ELSE
BEGIN
UPDATE EmailNotification set EmailSent=1, EmailSentDate=getdate() WHERE Id=#id
COMMIT
END

What do you mean : spSendEmail is not triggering sp_send_dbmail? sp_send_dbmail is triggered but doesn't do anything....?
Please get the return code of sp_send_dbmail :
0 => OK
<> 0 => Error occured
DECLARE #result int;
DECLARE #ErrorNb int;
EXECUTE #result = exec [msdb].[dbo].[sp_send_dbmail] #profile_name='EDMS email notification',
#recipients=#EmailAdress,
#blind_copy_recipients='example.email.com',
#subject=#EmailSubject,
#body=#EmailBody,
#file_attachments=#attachments
SET #ErrorNb = ##ERROR
IF #result <> 0
BEGIN
-- Something goes wrong
SELECT #result,#ErrorNb
END
You can also use TRY :
BEGIN TRY
EXECUTE exec [msdb].[dbo].[sp_send_dbmail] #profile_name='EDMS email notification',
#recipients=#EmailAdress,
#blind_copy_recipients='example.email.com',
#subject=#EmailSubject,
#body=#EmailBody,
#file_attachments=#attachments
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE();
END CATCH

Related

SQL Server : create table using variables

When trying to execute the following, I get the errors
Msg 102, Level 15, State 1, Line 9
Incorrect syntax near 'GO'.
Msg 102, Level 15, State 1, Line 11
Incorrect syntax near 'GO'.
Msg 102, Level 15, State 1, Line 13
Incorrect syntax near 'GO'.
Can someone tell me where I am going wrong? I don't understand how the syntax is wrong
DECLARE #table nvarchar(100);
DECLARE #sql nvarchar(max);
SET #table = 'FooTable';
SET #sql = N'CREATE TABLE [dbo].[' + #table + '](
[id] [int] IDENTITY(1,1) NOT NULL,
[AddedBy] [int] NOT NULL,
[AddedDate] [datetime2](7) NOT NULL,
CONSTRAINT [PK_' + #table + '] PRIMARY KEY CLUSTERED
( [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[' + #table + '] ADD CONSTRAINT [DF_' + #table + '_AddedBy] DEFAULT ((-1)) FOR [AddedBy]
GO
ALTER TABLE [dbo].[' + #table + '] ADD CONSTRAINT [DF_' + #table + '_AddedDate] DEFAULT (getutcdate()) FOR [AddedDate]
GO';
exec (#sql)
Thanks for your assistance.
SQL server is not happy about sending batches in a dynamic context using exec(). So forget about GO. Just slice up your query where GO should be and exec() slices one by one:
DECLARE #table nvarchar(100);
DECLARE #sql nvarchar(max);
SET #table = 'FooTable';
SET #sql = N'CREATE TABLE [dbo].[' + #table + '](
[id] [int] IDENTITY(1,1) NOT NULL,
[AddedBy] [int] NOT NULL,
[AddedDate] [datetime2](7) NOT NULL,
CONSTRAINT [PK_' + #table + '] PRIMARY KEY CLUSTERED
( [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]'
exec (#sql)
SET #sql = 'ALTER TABLE [dbo].[' + #table + '] ADD CONSTRAINT [DF_' + #table + '_AddedBy] DEFAULT ((-1)) FOR [AddedBy]'
exec (#sql)
SET #sql = 'ALTER TABLE [dbo].[' + #table + '] ADD CONSTRAINT [DF_' + #table + '_AddedDate] DEFAULT (getutcdate()) FOR [AddedDate]'
exec (#sql)
The syntax would be fine if you executed the code inside the management tool which understands the GO command as a batch separator (just like the isql and osql tools). When you execute the code using exec() the GO command is not understood, which is why you get the error.
The solution is to either remove the GO statements (or replace them with ; which ends a statement), and it will execute fine, or inline the constraints and skip the alter table statements altogether (which looks cleaner in my opinion):
SET #sql =
N'CREATE TABLE [dbo].[' + #table + '](
[id] int IDENTITY(1,1) NOT NULL,
[AddedBy] int NOT NULL CONSTRAINT [DF_' + #table + '_AddedBy] DEFAULT ((-1)),
[AddedDate] datetime2(7) NOT NULL CONSTRAINT [DF_' + #table + '_AddedDate] DEFAULT (getutcdate()) ,
CONSTRAINT [PK_' + #table + '] PRIMARY KEY CLUSTERED ( [id] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON
) ON [PRIMARY]
) ON [PRIMARY]
';
Also, there is really no need to use quoted identifiers with the types (or even the column names), so you might as well remove the brackets [].

TSQL sp_executesql

I have a simple table:
CREATE TABLE [dbo].[test]
(
[eins] [varchar](50) NOT NULL,
[zwei] [varchar](50) NULL,
CONSTRAINT [PK_test]
PRIMARY KEY CLUSTERED ([eins] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
with two columns eins und zwei, both varchar(50)
with the values
insert into test(eins, zwei) values(1,2)
1 and 2 in the corresponding columns.
The query
select eins from test
gives the correct result of 1
the following code also gives the correct result of 1 in the results window:
declare
#in varchar(50),
#sql nvarchar(500)
set #in = 'eins'
set #sql = 'select ' + #in + ' from test'
Exec(#sql)
However, it doesn't make use of an output parameter and I need the result for further processing.
So, I try:
exec sp_executesql N' Select #1 from test where zwei = #2',N'#1 nvarchar(100),#2 nvarchar(100)',#1=N'eins',#2=N'2'
with an expected result of 1. However: the result is eins, i.e., the column name, not the value.
How can I query for something like Select #Variable from #Variable2 where #variabel3 = #Variable4?
The table and columns can be non-variable, if need be, what's primarily important is, the Select #Variable. I need this value for further processing.
Try something like this
DECLARE #result int
exec sp_executesql
N'Select #1=eins from test where zwei = #2',
N'#1 nvarchar(100) OUTPUT,#2 nvarchar(100)',
#1=#result OUTPUT,#2=N'2'
SELECT #result
What that does is say that the #1 is an OUTPUT variable inside the EXECed query string. Then it binds #result to the #1, so you can retrieve it. I've never found OUTPUT parameters very intuitive to use.
The Code from DWright in the last post has the correct result, but the main problem isn't solved.
I dont know the name of the column while writing the code. The following code seems to be correct:
Declare #result int
Declare #sql nvarchar(500)
Declare #columnname nvarchar(50)
set #columnname = 'eins'
set #sql= N'Select #1= ' + #columnname +' from test1 where zwei = #2'
exec sp_executesql
#sql,
N'#1 nvarchar(100) OUTPUT,#2 nvarchar(100)',
#1=#result OUTPUT,#2=N'2'
SELECT #result
And the result is the expectet 1
Thank you for helping

Quoted_Identifier SQL Server - Off - Unsure How

We've been having an issue every few months where all of a sudden a job or procedure will start failing due to a quoted_Identifier issue. The quoted identifier in the proc or even table will change from 1 to 0 and we don't see any recent modified date on that record. We aren't sure how this is happening and because it's so sporadic, I can't reproduce it or trace it easily. Any ideas as to why this is occurring or what I can do to find out. I've done a lot of research without luck so far.
Thanks
You could create a DDL trigger activated by CREATE/ALTER PROCEDURE events. Inside this trigger you could use EVENTDATE function to get information about SQL statements execute including ANSI_NULLS and QUOTED_IDENTIFIER settings.
For example, you could use ddlDatabaseTriggerLog ddl trigger from Adventure Works OLTP database that insert into [dbo].[DatabaseLog] all ddl changes from current database.
DDL Trigger:
CREATE TRIGGER [ddlDatabaseTriggerLog] ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS AS
BEGIN
SET NOCOUNT ON;
SET ANSI_WARNINGS ON;
DECLARE #data XML;
DECLARE #schema sysname;
DECLARE #object sysname;
DECLARE #eventType sysname;
SET #data = EVENTDATA();
SET #eventType = #data.value('(/EVENT_INSTANCE/EventType)[1]', 'sysname');
SET #schema = #data.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname');
SET #object = #data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname')
IF #object IS NOT NULL
PRINT ' ' + #eventType + ' - ' + #schema + '.' + #object;
ELSE
PRINT ' ' + #eventType + ' - ' + #schema;
IF #eventType IS NULL
PRINT CONVERT(nvarchar(max), #data);
INSERT [dbo].[DatabaseLog]
(
[PostTime],
[DatabaseUser],
[Event],
[Schema],
[Object],
[TSQL],
[XmlEvent]
)
VALUES
(
GETDATE(),
CONVERT(sysname, CURRENT_USER),
#eventType,
CONVERT(sysname, #schema),
CONVERT(sysname, #object),
#data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(max)'),
#data
);
END;
GO
[dbo].[DatabaseLog]
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[DatabaseLog](
[DatabaseLogID] [int] IDENTITY(1,1) NOT NULL,
[PostTime] [datetime] NOT NULL,
[DatabaseUser] [sysname] NOT NULL,
[Event] [sysname] NOT NULL,
[Schema] [sysname] NULL,
[Object] [sysname] NULL,
[TSQL] [nvarchar](max) NOT NULL,
[XmlEvent] [xml] NOT NULL,
CONSTRAINT [PK_DatabaseLog_DatabaseLogID] PRIMARY KEY NONCLUSTERED
(
[DatabaseLogID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
Who/when changed dbo.uspGetEmployeeManagers procedure ?
SELECT *
FROM [dbo].[DatabaseLog] x
WHERE x.[Event] IN ('CREATE_PROCEDURE', 'ALTER_PROCEDURE')
AND x.[Schema] = 'dbo'
AND x.[Object] = 'uspGetEmployeeManagers'
XmlEvent column content:
<EVENT_INSTANCE>
<EventType>CREATE_PROCEDURE</EventType>
...
<TSQLCommand>
<SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE" />
<CommandText>
CREATE PROCEDURE [dbo].[uspGetEmployeeManagers]
#BusinessEntityID [int]
AS
...
Those scripts are helpful and I'll use them in the future. I figured out what the issue is. A stored procedure had quoted_identifier set to 0 and it had been that way for at least a year. However, someone created a filtered index on a table that the stored procedure was using. They didn't realize that the filtered index required quoted_identifier to be set to 1.

Get last inserted value and if statement mssql

I have this database setup: http://sqlfiddle.com/#!6/3076a/4
EDIT:
CREATE TABLE [dbo].[Sensor1](
[SensorTime] [datetime] NOT NULL,
[SensorValue] [float] NOT NULL,
PRIMARY KEY CLUSTERED
(
[SensorTime] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO dbo.Sensor1(SensorTime, SensorValue) VALUES ('2014-03-17 11:10:34.343', 10);
INSERT INTO dbo.Sensor1(SensorTime, SensorValue) VALUES ('2014-03-17 11:20:34.343', 20);
INSERT INTO dbo.Sensor1(SensorTime, SensorValue) VALUES ('2014-03-17 11:30:34.343', 30);
CREATE PROCEDURE [dbo].[SelectLatestByDate]
#name nvarchar(128),
#date datetime
AS
DECLARE #sql NVARCHAR(MAX)
SET #sql = N'
SELECT TOP 1 * FROM '+ QUOTENAME(#name) +' WHERE SensorTime <= #date ORDER BY SensorTime DESC
'
EXEC sp_executesql #sql, N'#date datetime', #date = #date
RETURN
Now, whenever a new value will be inserted, I want to make a check to see if it's not equal to the last value. If it's the same, it should not insert the value. Right now I have this stored procedure to do this, but it's slow and I'm wondering if there is a faster way...
CREATE PROCEDURE [dbo].[PutData]
#name nvarchar(128),
#date datetime,
#value float
AS
DECLARE #Table TABLE
(
SensorTime datetime,
SensorValue float
)
INSERT INTO #Table
EXEC dbo.SelectLatestByDate #name, #date
DECLARE #lastValue float
SELECT #lastValue = [#Table].[SensorValue] FROM #Table
IF (#lastValue != #value)
BEGIN
DECLARE #sql NVARCHAR(MAX)
SET #sql = N'
INSERT INTO ' + QUOTENAME(#name) + ' (SensorTime, SensorValue) VALUES (#date, #value)
'
EXEC sp_executesql #sql, N'#date datetime, #value float', #date = #date, #value = #value
END
RETURN 0
The tablename should be variable, that's the reason I made a stored procedure for it
I guess you can use NOT EXIST condition with your INSERT statement to test for the existence of rows.
IF NOT EXISTS ( [subquery] ) INSERT INTO ... VALUES(...)
The document of NOT EXIST is here :
http://technet.microsoft.com/en-us/library/ms188336.aspx
To specify the row which has the the maximum SensorTime, you can use MAX( ) function like below:
MAX(SensorTime) = SensorTime
This means the maxmum value is equal to the value of this row.
The document of MAX( ) function is here:
http://technet.microsoft.com/en-us/library/ms187751.aspx
So, Your code could go something like this:
IF NOT EXISTS (
SELECT * FROM Sensor1 WHERE SensorTime <= #date
AND SensorTime = MAX(SensorTime) AND SensorValue = #value
)
INSERT INTO Sensor1 (SensorTime, SensorValue) VALUES (#date, #value)
Hope this helps.

incorrect syntax near begin expecting EXTERNAL

I create a store procedure . In which first i check a table if the table is in my DB then i drop it and create new table, Second i create a store procedure there within the SP where i am inserting value in the table . My problem is that when i add store procedure part in the store procedure i am getting error incorrect syntax near begin expecting EXTERNAL . Below is my store procedure can you please help me where i am doing wrong .
ALTER PROCEDURE myProcedure
AS
BEGIN
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ATSROUTES]') AND type in (N'U'))
DROP TABLE [dbo].[ATSROUTES]
CREATE TABLE [ATSROUTES](
[zip] [varchar](255) NULL,
[route] [varchar](255) NULL,
[drivernum] [varchar](255) NULL,
[altserviceid] [varchar](255) NULL,
[localorldrvnum] [varchar](255) NULL,
[pickupzone] [varchar](255) NULL,
[distcenter] [varchar](255) NULL,
[altdispid] [varchar](255) NULL,
[id] [int] NULL);
BULK INSERT ATSROUTES FROM 'C:\Routes\my1.csv' WITH (FIELDTERMINATOR = ',', ROWTERMINATOR = '\n')
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[updateroute_sp]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].updateroute_sp
CREATE procedure updateroute_sp
AS
BEGIN
DECLARE #route varchar(255)
DECLARE #zip varchar(255)
DECLARE #routeid varchar(255)
DECLARE #distcenter varchar(255)
DECLARE #altdispid varchar(255)
DECLARE #ERR_NOTFOUND varchar(2000)
DECLARE db_Cursor CURSOR FOR SELECT zip, [route] from ATSROUTES
OPEN db_Cursor
FETCH NEXT FROM db_Cursor INTO #zip,#route
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#route is not null and #route <> '')
BEGIN
IF NOT EXISTS (SELECT * FROM routenames WHERE routename = #ROUTE)
BEGIN
EXEC GETNEWRECID2 'ROUTENAMES','ROUTEID','ROUTENAMES',#ROUTEID
insert into routenames (routeid,routename) values (#routeid,#ROUTE);
END
END
FETCH NEXT FROM db_Cursor INTO #zip,#route
END
CLOSE db_Cursor
DEALLOCATE db_Cursor
END
EXEC updateroute_sp
DROP PROCEDURE updateroute_sp
UPDATE ATSROUTES set id = (select routeid from routenames where routename = [route]);
UPDATE ATSROUTES set drivernum =LTRIM(RTRIM(drivernum));
END
Thanks .
The keyword 'AS' is present two times before the end of the batch marked by 'GO' or ';'.
Encapsulate the creation of the SP in a string (dynamic SQL), then call the execution of that string with EXEC(#SQL) if you want to create an SP withing another SP.

Resources