DECLARE
#id nvarchar(MAX),
#Counter int,
#CheckCount int
DECLARE CC1 CURSOR READ_ONLY
FOR
SELECT Ename, Ecount
FROM TestDB.dbo.TestEmail
OPEN CC1
FETCH NEXT FROM CC1 INTO #id, #Counter
WHILE ##FETCH_STATUS = 0
BEGIN
Begin
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Bob',
#recipients = #id,
#body = 'The stored procedure finished successfully. #$%',
#subject = 'Automated Success Message' ;
update TestDB.dbo.TestEmail
set Ecount = Ecount + 1
where Ename = #id
print #id
END
Select
#CheckCount = Ecount
from TestDB.dbo.TestEmail
where Ename = #id
print #CheckCount
If #CheckCount > 3
Begin
exec msdb.dbo.sp_update_job #job_id = N'6a81d6b3-af2d-4a27-b688-b9c69098f840', #enabled = 0
return
PRINT 'Count reached 3+'
End
FETCH NEXT FROM CC1 INTO #id, #Counter
END
CLOSE CC1
DEALLOCATE CC1
I have a table TestEmail with two columns Ename, Ecount. By using this table, I am trying to send emails to users. If the Ecount is greater than 3, the scripts exits, and nothing happens.
One user will receive emails for three times only. But my functionality fails, can't figure out where I am going wrong. My script doesn't throw any error but doesn't work either.
Marc's edit worked for me. The time I wrote the question, I had no idea about TSQL programming.
Although, the code in my question is working fine, Here is a wonderful tutorial to send an email via SQl server.
Send email in SQL server
Related
I've created a query that pulls info and emails in the way that I need it to be presented to our clients. How can I turn this into a stored procedure fed by a query (query A)? I need it to run for each unique set of cmp_code and cmp_e_mail it returns. So for example if QueryA returns the following, I need the email query to run for each of them individually.
C0001 email1#asdf.com
C0002 email2#asdf.com
C0003 email3#asdf.com
QueryA:
SELECT DISTINCT
[cmp_code]
,[cmp_e_mail]
FROM Table1
Query to email:
DECLARE #email nvarchar(50)
DECLARE #cmp_code nvarchar (5)
DECLARE #profile nvarchar(50)
DECLARE #subject nvarchar(100)
DECLARE #querystr nvarchar (MAX)
set #email = QueryA.[cmp_e_mail]
set #cmp_code = QueryA.[cmp_code]
set #profile = 'Reports'
set #subject = 'Test'+#cmp_code
set #querystr = 'SELECT [Year],[Week],[DueDate]
FROM Table1
WHERE [cmp_code] = '''+#cmp_code+'''';
EXEC msdb.dbo.sp_send_dbmail
#profile_name = #profile,
#recipients = #email,
#subject = #subject,
#body = 'This message is to inform you that we have not received your financial report for the following weeks.
Please remit as soon as possible and pay by the due date listed.',
#query = #querystr
try create a stored procedure like this one below that loops through the table and then calls another stored procedure passing in the data , be sure to deallocate and close the cursor at the end
Declare #Code nvarchar(50)
Declare #EmailAddress nvarchar(Max)
Declare dbCurSP Cursor
For SELECT DISTINCT [cmp_code] FROM Table1
Open dbCurSP
Fetch Next From dbCurSP Into #Code
While ##fetch_status = 0
Begin
-- find email address
SELECT #EmailAddress= [cmp_e_mail] FROM Table1 where [cmp_code]=#Code
execute SP_SendEmail #EmailAddress, #Code
Fetch Next From dbCurSP Into #Code
End
Close dbCurSP
Deallocate dbCurSP
I have created a job alert for sending emails to user everyday. I have used Database mail and wrote a script to a send an email to users who falls in the particular category.
But I want to send this email to the users only for three days. Email should be sent to the all users for three days only.
Updated:
DECLARE #name VARCHAR(20),
#birthdate datetime,
#email NVARCHAR(50),
#id nvarchar(MAX)
DECLARE #body NVARCHAR(1000)
DECLARE CC1 CURSOR READ_ONLY
FOR
SELECT Name, Birthdate, Email
FROM TestDB.dbo.cust
OPEN CC1
FETCH NEXT FROM CC1 INTO
#name, #birthdate, #email
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #id= Ename FROM TestDB.dbo.TestEmail
IF #email = #id
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'vate',
#recipients = 'vegeta#gmail.com',
#body = 'The stored procedure finished successfully.',
#subject = 'Automated Success Message' ;
END
FETCH NEXT FROM CC1 INTO
#name, #birthdate, #email
END
CLOSE CC1
DEALLOCATE CC1
First of all when you create Job using Management Studio (Management Studio > SQL Server Agent > Jobs > New Job) you can create schedule on the Schedules tab.
When you have created Job using this wizard you can get SQL script to create this Job (with schedule) - Script button on the top of Wizard.
Here is a part of this script which create Schedule for a Job:
DECLARE #schedule_id int
EXEC msdb.dbo.sp_add_jobschedule #job_name=N'backup_job', #name=N'my_schedule',
#enabled=1,
#freq_type=8,
#freq_interval=7,
#freq_subday_type=1,
#freq_subday_interval=0,
#freq_relative_interval=0,
#freq_recurrence_factor=1,
#active_start_date=20140709,
#active_end_date=99991231,
#active_start_time=0,
#active_end_time=235959, #schedule_id = #schedule_id OUTPUT
select #schedule_id
GO
I want to create a procedure that will insert all my jobs to the DB.
(a. All my jobs have equal characteristics. b. SSDT doesn't support jobs code management)
Now, I thought to create a script to insert all of them and as a c# developer I thought I need to initialize a list with their names.
I discovered while googling that the way to do it is with an in memory table and the best I could come with is this.
declare #jobsNames table(Id int, JobName nvarchar(100))
insert into #jobsNames (Id,JobName)
select 1,'JobName1' union
select 2,'JobName2' union
......
BEGIN TRANSACTION
DECLARE JobsCursor CURSOR FOR SELECT JobName FROM #jobsNames
OPEN JobsCursor
FETCH NEXT FROM JobsCursor INTO #JobName
WHILE ##Fetch_status = 0
BEGIN
.. do stuff
FETCH NEXT FROM JobsCursor INTO #JobName
WHILE ##Fetch_status = 0
END
COMMIT TRANSACTION
Question -
Is this the shortest/recommended way?
(It seems a hellotof code for a foreach)
declare #jobNames table(Id int, JobName nvarchar(100))
insert #jobNames values
(1, 'JobName1'),
(2, 'JobName2'),
--
(10, 'JobName10')
while exists(select 1 from #jobNames)
begin
declare #id int, #name nvarchar(100)
select top 1 #id = Id, #name = JobName from #jobNames
delete from #jobNames where Id = #Id
-- Do stuff here
end
Personally I avoid Cursors like the plague. Please make sure that you HAVE to iterate instead of doing your work set based. They don't call it RBAR for nothing.
DECLARE #counter INT, #max INT
SELECT #counter = 1, #max = max(id)
FROM #jobsNames
WHILE #counter <= #max
BEGIN
SELECT #val1 = val1 ... FROM #jobNames where ID = #counter
-- .. do stuff
SET #counter = #counter + 1
END
I have a curious problem with an infinite loop in a TSQL cursor. The cursor loops infinitely when I do not add TOP 300 to the defining select statement of the cursor. The following is an example of the code: Any assistance to this issue is much appreciated.
DECLARE #Done BIT
SET #Done = 0
DECLARE cursOut CURSOR LOCAL FAST_FORWARD
FOR
SELECT
--TOP 300
FirstName FirstName
,LastName LastName
,MiddleName MiddleName
,Email Email
,Address1 Address1
,Address2 Address2
,City City
,[State] [State]
FROM StagedUsers
OPEN cursOut;
WHILE (#Done = 0)
BEGIN
--Fetch next row
FETCH NEXT
FROM cursOut
INTO ,#v_FirstName
,#v_LastName
,#v_MiddleName
,#v_Email
,#v_Address1
,#v_Address2
,#v_City
,#v_State
IF (##FETCH_STATUS <> 0)
BEGIN
SET #Done = 1
BREAK
END
--if #batch = 0
BEGIN TRANSACTION
--process statements
--updates or insert statements
--Commit transaction
COMMIT TRANSACTION
--End While
END
--CleanUp:
CLOSE cursOut
DEALLOCATE cursOut
Thanks,
Renegrin
First I think you do not need transaction here, I presume it is only one statement executed, so remove transaction from code.
Second do it without #done flag, it is confusing (it is probably not problem here).
DECLARE #v_FirstName VARCHAR(500),#v_LastName VARCHAR(500),#v_MiddleName VARCHAR(500),#v_Email VARCHAR(500),#v_Address1 VARCHAR(500),#v_Address2 VARCHAR(500),#v_City VARCHAR(500),#v_State VARCHAR(500)
DECLARE cursOut CURSOR FAST_FORWARD FOR
SELECT FirstName FirstName,LastName LastName,MiddleName MiddleName,Email Email,Address1 Address1,Address2 Address2,City City,[State] [State]
FROM StagedUsers
OPEN cursOut;
FETCH NEXT FROM cursOut INTO #v_FirstName,#v_LastName,#v_MiddleName,#v_Email,#v_Address1,#v_Address2,#v_City,#v_State
declare #i int = 1
WHILE ##FETCH_STATUS = 0
BEGIN
print cast(#i as varchar(10))
--> statement here
FETCH NEXT FROM cursOut INTO #v_FirstName,#v_LastName,#v_MiddleName,#v_Email,#v_Address1,#v_Address2,#v_City,#v_State
set #i = #i + 1
END
CLOSE cursOut
DEALLOCATE cursOut
Do you want to update current row where cursor point? If so, there is way to do it.
Is there any indexes on table? Can you post an update query?
I have a stored procedure build update query and store in temp table each time in loop.
Total query built UNKNOWN (2 to 4)
How can I put multi query in a transaction?
For example, temp table contains following rows in column EXPSQL (nvarchar)
id EXPSQL
1 Update tableA SET Name = 'Test' WHERE id=1
2 Update tableB SET Name = 'Test2' WHERE id=10
How can I begin a transaction for a loop to exec above query? or is there any other way?
while #id < total
begin
set #id = #id +1
select #SQL = EXPSQL FROM #TEMPTABLE WHERE id=#id
EXEC (#SQL)
end
Thanks
If you want to execute all as one:
begin transaction
while #id < total
begin
set #id = #id +1
select #SQL = EXPSQL FROM #TEMPTABLE WHERE id=#id
EXEC (#SQL)
-- if a error occurs go back to the original state
if(##error <> 0)
rollback transaction
end
commit transaction
If you want to execute each one individually:
while #id < total
begin
set #id = #id +1
select #SQL = EXPSQL FROM #TEMPTABLE WHERE id=#id
begin transaction
EXEC (#SQL)
-- if a error occurs go back to the original state
if(##error <> 0)
rollback transaction
else
commit transaction
end