SQL Server 2008 R2 match counts - sql

I have a SQL query that checks when a stored procedure was last run, from that date it gathers all the units that were purchased between that date and today's date and compares it to another number. If they match it sends an email saying the two number match and executes the rest of the stored procedure. However, when it runs I constantly get 0 for the number of accounts, when it should be a value greater than 0 daily:Here is my code:
DECLARE #UnitsPurchased int
DECLARE #WelcomeLetterGenerated int
DECLARE #LastSuccesfulRunTime datetime
SET #LastSuccesfulRunTime = (select cast(run_datetime as DATE) from apsllc_v2.dbo.LastSuccesfulRunDate)
SET #UnitsPurchased = (SELECT COUNT(*) FROM rsbi.dbo.loans as l
where rsbi.dbo.fn_Convert_Paradata_Birth_Date(l.Unit_PURDATE) between #LastSuccesfulRunTime
AND getDate() and l.LN_CLASS in (58,59)) -- Shows the number of units that were purchased yesterday
SET #WelcomeLetterGenerated = ( SELECT COUNT(*) FROM apsllc_v2.dbo.ApsUpload ap where ap.FormNumber IN(1100,1150) ) -- Shows how many welcome letters were generated today
if #UnitsPurchased <> #WelcomeLetterGenerated
begin
EXEC msdb.dbo.sp_send_dbmail
#recipients = N''
, #body = ' '
, #subject = 'Welcome Letter Counts do not Match'
, #profile_name = 'Email_Profile_01'
return
end
ELSE if #UnitsPurchased = #WelcomeLetterGenerated --or if
begin
EXEC msdb.dbo.sp_send_dbmail
#recipients = N''
, #body = ' '
, #subject = 'Welcome Letter Counts Match'
, #profile_name = 'Email_Profile_01'
end

Related

After Trigger with JOIN Tables

TASK: Create an AFTER TRIGGER to accomplish a condition from a JOIN. The Trigger would be in table_1 when some record is created. Meanwhile, table_2 has a common column with some parameters that the condition needs to have.
Every time that the Result <> 1 AND Status <> 3 in table_2 and ALERT should be sent
-- QUERY WITH JOIN TABLE_1 ON TABLE_2
-- MOCK TABLE
-- Table_1 as A | Table_2 as B
A.LotCode | A.LineNumber | B.Result | B.Status
00000 | xxxx | 1 | 3
00001 | xxxx | 2 | 4
-- The LotCode 00001 should send it through email because satisfy the condition
CREATE TRIGGER FullfillOrderQCResult
ON Table_1
AFTER INSERT
AS
BEGIN
-----DECLARE VARIABLES-----
DECLARE #LOTNUMBER VARCHAR(50)
DECLARE #ACTIONPEFORMED VARCHAR(MAX)
DECLARE #ITEM INT
DECLARE #RESULT TINYINT
DECLARE #STATUS TINYINT
SELECT #LOTNUMBER = A.LotCode, #ITEM = A.LineNumber, #RESULT = B.Result, #STATUS = B.Status
FROM inserted AS A
JOIN Table_2 AS B
ON A.LotCode = B.DocumentID2
-----CONDITION WHEN I INSERT A VALUE-----
IF (#RESULT <> 1 AND #STATUS <> 3)
BEGIN
SET #ACTIONPEFORMED =
N'Hello, ' + '<br>' + '<br>'
+ N' The following LOT NUMBER: ' + #LOTNUMBER + ' has not been approved for this Item: '
EXEC MSDB.DBO.SP_SEND_DBMAIL
#PROFILE_NAME = 'SQLMail',
#RECIPIENTS = 'TEST#gmail.com',
#SUBJECT = 'LOT NON-Approved',
#BODY = #ACTIONPEFORMED,
#IMPORTANCE = 'HIGH',
#BODY_FORMAT = 'HTML'
END
ELSE
PRINT 'ALL GOOD MY FRIEND'
END
TESTING THE TRIGGER
--------INSERT VALUES------------------
INSERT INTO Table_1 (LotCode,LineNumber)
values ('00000','xxxx')
-----EXISTING VALUES-----
INSERT INTO Table_2 (CreationUser,DocumentID1,DocumentID2,DocumentID3,Result,Status)
values ('JL','00000','00000','00000',2,3)
The following shows you how to handle the fact that Inserted might have multiple rows. This is really not ideal behaviour for a trigger, because you have to process the results RBAR (row by agonising row), which is slow by itself, let alone the fact that you are sending an email.
CREATE TRIGGER FullfillOrderQCResult
ON Table_1
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
-----DECLARE VARIABLES-----
DECLARE #ACTIONPEFORMED varchar(max), #Id int;
SELECT A.LotCode, A.LineNumber, CONVERT(bit, 0) Done, IDENTITY(int) id -- Use your own id if you have one, just need to uniquely identify each row.
INTO #FullfillOrderQCResult_temp
FROM Inserted AS A
INNER JOIN Table_2 AS B ON A.LotCode = B.DocumentID2
WHERE B.Result <> 1 and B.[Status] <> 3;
WHILE EXISTS (SELECT 1 FROM #FullfillOrderQCResult_temp WHERE Done = 0) BEGIN
SELECT TOP 1 #Id = id, #ACTIONPEFORMED =
N'Hello, ' + '<br>' + '<br>'
+ N'The following LOT NUMBER: ' + LotCode + ' has not been approved for this Item: ' + LineNumber
FROM #FullfillOrderQCResult_temp
WHERE Done = 0;
EXEC MSDB.DBO.SP_SEND_DBMAIL
#PROFILE_NAME = 'SQLMail',
#RECIPIENTS = 'TEST#gmail.com',
#SUBJECT = 'LOT NON-Approved',
#BODY = #ACTIONPEFORMED,
#IMPORTANCE = 'HIGH',
#BODY_FORMAT = 'HTML';
UPDATE #FullfillOrderQCResult_temp SET Done = 1 WHERE id = #Id;
END;
END;
I don't know whether you would still want the concept of 'ALL GOOD MY FRIEND' because you could have none, some or all rows with issues. Anyway I assume print is only for debugging.
That said you would be much better off pushing an event into a queue and having a service process said event because triggers really should be as fast as possible. And adding an event to a queue could be handled in a set based manner e.g.
CREATE TRIGGER FullfillOrderQCResult
ON Table_1
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO MyEventQueue (A.LotCode, A.LineNumber) -- Any other information required to identify the records etc
SELECT A.LotCode, A.LineNumber
FROM Inserted AS A
INNER JOIN Table_2 AS B ON A.LotCode = B.DocumentID2
WHERE B.Result <> 1 and B.[Status] <> 3;
END;

Obtain a repeated data and send SQL mail

Good day I have a table called Ticket which has several tickets registered, each one has a status:
1 = Accepted,2 = Assigned,3 = At ​​attention,4 = Attended,5 = Agree.
I want to perform a stored procedure in which I only send mail to the tickets that are in state 4, that is, my ticket has status 4, it is activated exec sp_sendmail .
Then I will use it as a Job every 30 minutes, check to see if it is still in that state and if it is in state 4 it sends again mail, once it changes state 4 to 5 it will not send anything and it will be closed.
Something like this, that loops through the list of tickets and sends an email. Couple notes, though: first, if you try to send too many at once, your email provider may start dropping them, so maybe put in a {pre}WAITFOR DELAY '00:00:02'{pre} delay between messages. Also, instead of sending one email per ticket, you can look into the query options in sp_send_dbmail: you can email a single list of all currently-4 tickets. It just depends on your needs.
CREATE PROCEDURE dbo.SendTicketAttendedEmails
AS
BEGIN
DECLARE #MailList TABLE(TicketID INT, SendTo VARCHAR(255))
DECLARE #ThisTicketID INT
, #MailMessage NVARCHAR(2000)
, #MailSubject NVARCHAR(255)
, #SendTo VARCHAR(255)
INSERT INTO #MailList
([TicketID], [SendTo])
SELECT t.[ID], u.[UserEmail]
FROM dbo.YourTicketTable t
JOIN dbo.YourUserTable u
ON t.UserCreated = u.ID
WHERE [StatusID] = 4
WHILE EXISTS(SELECT 1 FROM #MailList)
BEGIN
SELECT TOP(1) #ThisTicketID = [TicketID]
, #MailSubject = 'Ticket ' + CAST([TicketID] AS VARCHAR(10)) + ' is in status 4.'
, #MailMessage = 'Please review, or whatever, ticket ' + CAST([TicketID] AS VARCHAR(10)) + '.'
, #SendTo = COALESCE([SendTo], 'yourEmailAddress#InCase.Missing')
FROM #MailList
ORDER BY [TicketID];
DECLARE #mailitem_id INT ;
EXEC [msdb].dbo.[sp_send_dbmail]
#profile_name = 'SomeDBMailProfileName' -- sysname
, #recipients = #SendTo -- varchar(max)
, #subject = #MailSubject -- nvarchar(255)
, #body = #MailMessage -- nvarchar(max)
, #mailitem_id = #mailitem_id OUTPUT -- int
, #from_address = 'you#you.com' -- varchar(max)
, #reply_to = 'you#you.com' -- varchar(max)
DELETE #MailList
WHERE [TicketID] = #ThisTicketID
END
END
Basically you will use something like this for your job.
exec sp_send_dbmail
#profile_name = 'your_mail_profile'
,#recipients = 'you#email.com'
,#subject = 'Attended'
,#query = 'select * from yourTable where [status] = 4'
--,#attach_query_result_as_file = 1
--,#query_attachment_filename = 'somefile.csv'
See other options in the docs... and adjust accordingly.

Validation if you're using the correct DB

Is there a way to have a validation script before continuing a script?
So
DECLARE #strServernameToClear as VarChar(100)
DECLARE #strCurrentServer as VarChar(100)
DECLARE #strDatabaseToClear as VarChar (100)
DECLARE #strDatabase as VarChar (100)
SET #strDatabase = (SELECT ##database) << THIS IS WHERE IM HAVING TROUBLE. How to indicate which database it is running against
IF #strCurrentServer <> #strServernameToClear
BEGIN
PRINT '*****************WARNING *****************'
PRINT 'WRONG DB NAME: This server is: ' + #strCurrentServer
PRINT 'If this is the correct server, set #strServernameToClear to ' + #strCurrentServer
RETURN
END
ELSE
EXECUTE ORDER 66
I think this'll work for you:
select #strDatabase = d.name
from sys.sysprocesses p
join sys.databases d on d.database_id = p.dbid
where p.spid = ##SPID

SQL Email based on query

I have set up SQL server to email and have successfully. I am trying to send an email with the following query:
select count(*) from report queue
I would like an email sent when count is > 10.
I have never done a SQL stored procedure before.
SELECT COUNT(*) AS ct
FROM report_queue
HAVING ct > 10
Can you try this?
select email from report queue group by email having count(*)>10
Another alternative;
IF ((SELECT COUNT(*) FROM [report queue]) > 10)
SELECT * FROM [report queue]
CREATE PROCEDURE [dbo].[email_report] (#recipients nvarchar(max), #subject nvarchar(max) = '', #body nvarchar(max) = '')
AS
BEGIN
IF (SELECT COUNT(*) FROM [report_queue]) > 10
EXEC [msdb].[dbo].[sp_send_dbmail]
#recipients = #recipients,
#subject = #subject,
#body = #body;
END
More details available here: sp_send_dbmail (Transact-SQL)

Select Values based on Range Automatically and Trigger Email

The table from which a data range is to be queried :
Id Variance
1 2
2 17
3 7
4 4
5 20
6 1
7 111
8 8
9 18
10 67
Another table that has
Freq StartRange EndRange
H 10 7
H 8 8
H 6 20
The data in the first table is loaded every 30mins through an SSIS package.
Now I want alert as in emails to be triggered when the data in the Variance column falls in the StartRange and EndRange.
CREATE PROCEDURE [dbo].[SP_Email] #Start varchar(50),#End varchar(50),#Date datetime
AS
BEGIN
DECLARE #xml NVARCHAR(MAX)
DECLARE #body NVARCHAR(MAX)
SET #xml = CAST(( SELECT [SlNo] AS 'td','',[date] AS 'td','',
[lag] AS 'td','', Percent AS 'td'
FROM TestTbl
WHERE(percent >= #Start AND percent < #End)
AND CAST(CONVERT(VARCHAR,curDate,106) AS DATETIME) = CAST(#Date AS DATETIME)
ORDER BY SlNo
FOR XML PATH('tr'), ELEMENTS ) AS NVARCHAR(MAX))
SET #body ='<html><body><H3>Report</H3>
<table border = 1>
<tr>
<th> SlNo </th> <th> date </th> <th> lag </th> <th> Percent </th></tr>'
SET #body = #body + #xml +'</table></body></html>'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Alert',
#body = #body,
#body_format ='HTML',
#recipients = 'abc#gmail.com'
#subject = 'Report';
END
Please suggest a process that will help me setup such in SQL Server 2005.
Thanks in Advance
This can be done via SQL Server Agent jobs:
EXEC dbo.sp_add_job
#job_name = N'Variance Check',
#notify_email_operator_name='you#your.domain',
#notify_level_email=2; -- Only notify you when YourStoredProceedure fails
GO
EXEC sp_add_jobstep
#job_name = N'Variance Check',
#step_name = N'Check the variance',
#subsystem = N'TSQL',
#command = N'EXEC YourStoredProceedure',
#retry_attempts = 1,
#retry_interval = 5 ;
GO
EXEC dbo.sp_add_schedule
#schedule_name = N'EveryThirtyMinutes',
#freq_type = 4, -- Daily
#freq_subday_type = 0x4, -- Minutes
#freq_subday_interval = 30,
#active_start_time = NULL; -- Start right away
USE msdb ;
GO
EXEC sp_attach_schedule
#job_name = N'Variance Check',
#schedule_name = N'EveryThirtyMinutes';
GO
EXEC dbo.sp_add_jobserver
#job_name = N'Variance Check';
GO
One way to approach this is through triggers. However, I don't recomment sending emails through triggers.
Instead, add a step to the process that loads the data in T1. After this step, call a stored procedure that finds the rows that meet the conditions and send the appropriate email.
It is rather hard to tell exactly what the conditions are, however. Your second table has three ranges. It is not clear which to apply to which row.