The idea is to create an ‘empty’ standard subscription in SSRS and then, using a stored procedure, manipulate the parameters and run the report.
First create a dummy subscription that isn’t scheduled to run:
Once the subscription is saved, you need to get the SubscriptionID from the report server. Use the following code:
SELET
c.Name AS
ReportName,
rs.ScheduleID
FROM ReportServer.dbo.[Catalog] c
INNER JOIN ReportServer.dbo.Subscriptions s ON c.ItemID = s.Report_OID
INNER JOIN
ReportServer.dbo.ReportSchedule
rs ON c.ItemID = rs.ReportID
AND rs.SubscriptionID = s.SubscriptionID
Where
c.Name = 'Subscription Name'
You’ll need the SubscriptionID when calling the report.
Next create the following stored procedure that will be
called to run the report(s):
(I found this SP on the internet, but can’t remember where so
can’t credit where it’s due), either way it has a couple of changes and I hope
it helps out other people)
USE [ReportServer]
GO
/****** Object:
StoredProcedure [dbo].[data_driven_subscription] Script Date: 04/11/2012 16:38:33 ******/
SET ANSI_NULLS
ON
GO
SET QUOTED_IDENTIFIER
ON
GO
ALTER procedure
[dbo].[data_driven_subscription_1_Param]
( @scheduleID uniqueidentifier,
@TO varchar (2000) = ' ',
@CC varchar (2000) = ' ',
@BCC varchar (2000) = ' ',
@ReplyTO varchar (2000) =
' ',
@BODY varchar (8000) = ' ',
@param1 varchar (256) = ' '
)
as
DECLARE
@ptrval binary(16),
@PARAMptrval binary(16),
@TOpos int,
@CCpos int,
@BCCpos int,
@RTpos int,
@BODYpos int,
@PARAM1Pos int,
@length int,
@subscriptionID uniqueidentifier
-- set the subscription ID
SELECT @subscriptionID = SubscriptionID
FROM ReportSchedule WHERE ScheduleID = @scheduleID
-- set the text point for this records Email info
SELECT @ptrval = TEXTPTR(ExtensionSettings)
FROM Subscriptions WHERE SubscriptionID = @subscriptionID
-- set the text point for this records Parameter info
SELECT @PARAMptrval = TEXTPTR(Parameters)
FROM Subscriptions WHERE SubscriptionID = @subscriptionID
-- set the start position for the TO Address
SELECT @TOpos = patindex('%|EmailTO|%', ExtensionSettings) - 1
FROM Subscriptions WHERE SubscriptionID = @subscriptionID
IF isnull(@TOpos, '') <> '' and @TOpos > 0 and len(@To) > 0
-- change the TO address
UPDATETEXT Subscriptions.ExtensionSettings
@ptrval
@TOpos
4
@To
-- set the start position for the CC Address
SELECT @CCpos = patindex('%|CarbonCopy|%', ExtensionSettings) - 1
FROM Subscriptions WHERE SubscriptionID = @subscriptionID
IF isnull(@CCpos, '') <> '' and @CCpos > 0 and len(@CC) > 0
-- change the TO address
UPDATETEXT Subscriptions.ExtensionSettings
@ptrval
@CCpos
4
@CC
-- set the start position for the BCC Address
SELECT @BCCpos = patindex('%|BlindCopy|%', ExtensionSettings) - 1
FROM Subscriptions WHERE SubscriptionID = @subscriptionID
IF isnull(@BCCpos, '') <> '' and @BCCpos > 0 and len(@BCC) > 0
-- change the TO address
UPDATETEXT Subscriptions.ExtensionSettings
@ptrval
@BCCpos
4
@BCC
-- set the start position for the REPLY TO Address
SELECT @RTpos = patindex('%|ReplyTo|%', ExtensionSettings) - 1
FROM Subscriptions WHERE SubscriptionID = @subscriptionID
IF isnull(@RTpos, '') <> '' and @RTpos > 0 and len(@ReplyTO) > 0
-- change the REPLY TO address
UPDATETEXT Subscriptions.ExtensionSettings
@ptrval
@RTpos
4
@ReplyTO
-- set
the start position for the BODY Text
SELECT
@BODYpos = patindex('%|Comment|%', ExtensionSettings) - 1
FROM
Subscriptions WHERE SubscriptionID = @subscriptionID
IF
isnull(@BODYpos, '') <> '' and @BODYpos > 0 and len(@BODY) > 0
-- change the REPLY TO address
UPDATETEXT Subscriptions.ExtensionSettings
@ptrval
@BODYpos
4
@BODY
-- set
the start position for the Parameter 1
SELECT
@PARAM1Pos = patindex('%|Parameter1|%', Parameters) - 1
FROM
Subscriptions WHERE SubscriptionID = @subscriptionID
IF
isnull(@PARAM1Pos, '') <> '' and @PARAM1Pos > 0 and len(@parameter1) > 0
-- change the Parameter 1 value
UPDATETEXT Subscriptions.Parameters
@PARAMptrval
@PARAM1Pos
4
@parameter1
-- run the job
exec msdb..sp_start_job @job_name =
@scheduleID
-- this give
the report server time to execute the job.
-- there is
probably a better way to do this, so let me know if you know it ...
WAITFOR DELAY '00:00:10'
-- now change
everything back so you can run this again
-- set
the start position for the TO Address
SELECT
@TOpos = patindex('%' + @TO + '%', ExtensionSettings) - 1
FROM
Subscriptions WHERE SubscriptionID = @subscriptionID
SELECT
@length = len(@TO)
IF
@length > 0
--
replace the addresses with the original |TO|
UPDATETEXT
Subscriptions.ExtensionSettings
@ptrval
@TOpos
@length
'|EmailTO|'
-- set
the start position for the TO Address
SELECT
@CCpos = patindex('%' + @CC + '%', ExtensionSettings) - 1
FROM
Subscriptions WHERE SubscriptionID = @subscriptionID
SELECT
@length = len(@CC)
IF
@length > 0
--
replace the addresses with the original |CC|
UPDATETEXT
Subscriptions.ExtensionSettings
@ptrval
@CCpos
@length
'|CarbonCopy|'
-- set
the start position for the TO Address
SELECT
@BCCpos = patindex('%' + @BCC + '%', ExtensionSettings) - 1
FROM
Subscriptions WHERE SubscriptionID = @subscriptionID
SELECT
@length = len(@BCC)
IF
@length > 0
--
replace the addresses with the original |BC|
UPDATETEXT
Subscriptions.ExtensionSettings
@ptrval
@BCCpos
@length
'|BlindCopy|'
-- set
the start position for the REPLY TO Address
SELECT
@RTpos = patindex('%' + @ReplyTO + '%', ExtensionSettings) - 1
FROM
Subscriptions WHERE SubscriptionID = @subscriptionID
SELECT
@length = len(@ReplyTO)
IF
@length > 0
--
replace the addresses with the original |RT|
UPDATETEXT
Subscriptions.ExtensionSettings
@ptrval
@RTpos
@length
'|ReplyTo|'
-- set
the start position for the BODY Text
SELECT
@BODYpos = patindex('%' + @BODY + '%', ExtensionSettings) - 1
FROM
Subscriptions WHERE SubscriptionID = @subscriptionID
SELECT
@length = len(@BODY)
IF
@length > 0
--
replace the addresses with the original |BD|
UPDATETEXT
Subscriptions.ExtensionSettings
@ptrval
@BODYpos
@length
'|Comment|'
-- set
the start position for the Parameter
SELECT
@PARAM1Pos = patindex('%' + @parameter1 + '%', Parameters) - 1
FROM
Subscriptions WHERE SubscriptionID = @subscriptionID
SELECT
@length = len(@param1)
IF
@length > 0
--
replace the addresses with the original |P1|
UPDATETEXT
Subscriptions.Parameters
@PARAMptrval
@PARAM1Pos
@length
'|Parameter1|'
You’ll notice the name of the SP ends with ‘1_Param’. To add more use the following code in the
relevant part of the SP:
-- set the start position for the Parameter 2
SELECT
@PARAM2Pos = patindex('%|Parameter2|%', Parameters) - 1FROM Subscriptions WHERE SubscriptionID = @subscriptionID
IF isnull(@PARAM2Pos, '') <> '' and @PARAM2Pos > 0 and len(@parameter2) > 0
-- change the Parameter 1 value
UPDATETEXT Subscriptions.Parameters
@PARAMptrval
@PARAM2Pos
4
@parameter2
SELECT @length = len(@param2)
IF @length > 0
-- replace the addresses with the original |P2|
UPDATETEXT Subscriptions.Parameters
@PARAMptrval
@PARAM1Pos
@length
'|Parameter2|'
It would be prudent to create a few versions of this SP with
carrying numbers of parameters to meet all your needs.
The next SP is the one that runs and controls your new
data-driven subscription capabilities.declare @ReportParameter varchar(50)
declare @email_address varchar(255)
declare cur_cursor cursor for (select report_parameter,email_address
from
server.[database].[dbo].[tablewith
data])
open cur_cursorFetch Next from cur_cursor into @ReportParameter, @email_address
While @@fetch_status = 0
begin
exec data_driven_subscription_1_Param
@scheduleID = 'FE98A2D4-4430-4D5C-806C-717470CB1332',
@TO = @email_address,
@CC = '',
@BCC = 'AdministrativeEmail@CompanyName.com',
@ReplyTO = 'RelevantTeam@YourCompany.com',
@BODY = 'Hello testing 123',
@param1 = @ReportParameter
Fetch Next from cur_cursor into @ReportParameter, @email_address
end
close cur_cursor
deallocate cur_cursor
This cursor uses a table directly, but you can create any
complicated query you wish to determinethe parameters and emails, just as you
would with a normal data-driven subscription.
Notice the @scheduleID – this is the scheduleID you
collected after you saved the standard report subscription.The above code can either be turned into an SP, or placed directly into a SQL Agent Job.
Once you have an Agent job to run this procedure you can schedule it when and as required.
Any questions please don’t hesitate to contact me.
What I have been looking for well done
ReplyDeleteHi Geoff
ReplyDeleteThis version of the process is the closest to actually working that I've found! I managed to process half of my emails before getting a sharepoint osws timer related fault. The routine has failed to run ever since. Have you come across any similar problems?
Hi Squeaks. I'm not familiar with the Sharepoint aspect of your problem. Perhaps there is a timeout on the report or in Sharepoint that you need to extend. Does the report take a while to process, or does it run pretty smoothly?
DeleteCheck your SQL queries to look for anything that takes more than 60 seconds might be a good starting point.
Sorry I can't be more help - but we don't use Sharepoint.
Geoff
Also - try re-starting SSRS service on the server.
DeleteThis comment has been removed by the author.
ReplyDeleteI was wondering how the SP could pick up on multi-value parameters...
ReplyDeleteGeoff, I'm debugging this SP, but it looks like it had never been run correctly. For example, this code will never run correctly as it tailored to use 4 character |TO| instead of 9 character |EmailTo|...
ReplyDelete-- set the start position for the TO Address
SELECT @TOpos = patindex('%|EmailTO|%', ExtensionSettings) - 1
FROM Subscriptions WHERE SubscriptionID = @subscriptionID
IF isnull(@TOpos, '') <> '' and @TOpos > 0 and len(@To) > 0
-- change the TO address
UPDATETEXT Subscriptions.ExtensionSettings
@ptrval
@TOpos
4
@To
Hi Julia, Although it has been a couple of years since I used this code, I did so quite successfully.
ReplyDeleteI no longer have access to that server (different company), but you could just change the "|EmailTo|" to "|To|". I may have done this originally, but i can't remember.
Sometimes I have to edit before posting here for various reasons, so it could be that I changed that bit.
Thanks
Anyone get this to work? I'm getting The following setting is not valid: "Hello testing subscription 123" after I amended the character lengths i.e. Changed |EmailTo| from 4 to 9
Deletehttps://youtu.be/Ag0SJQQ7HrU
DeleteHi,
DeleteTry shortening 'Hello testing subscription 123' to 'testing' for now. It's unrelated to |Email| variable
Cool! Thanks :)
ReplyDeleteDo you have anything that will split a pdf report in different files based on parameters?
ReplyDeleteWould need more context to answer that....
DeleteYes, SQL-RD has a feature that does that. Check out christiansteven.com
ReplyDeleteHi Geoff,
ReplyDeleteI have this working, only issue is I have an intermittent fault, where it seems to send the correct amount of emails but it seems to miss some out but duplicates some by the same amount, i.e. send 3 of the same out but miss 2. Could increasing the wait delay time stop this issue? Any ideas? Thanks Charlie
Not encountered that one. First thing would be the delay I agree. try being on the safe side and doubling or tripling it to 20-30 seconds so you can rule it out completely.
DeleteLet me know how you get on.
Hi, I am having the exact same issue as the Anonymous post. Did increasing the wait time delay resolve the issue for you.
DeleteThis worked awesome - for anyone out there who needs some tips, you definitely have to change either the character length of the place holder strings to 4 (ie replace |ReplyTo| with |To|) or you need to replace the number of characters its searching for
ReplyDeletealso if you leave a line untouched, ie leaving |CarbonCopy| as is, it'll fail because that isn't a legit email format
thanks!!
Job '8ABB5F48-7D6C-4D44-9126-123456896C' started successfully.
ReplyDeleteMsg 7135, Level 16, State 2, Procedure data_driven_subscription_1_Param_Test, Line 73
Deletion length 8 is not in the range of available text, ntext, or image data.
The statement has been terminated.
How I can resolve this
I am also having the same error.
DeleteCan anyone please help?
This comment has been removed by the author.
DeleteI know this is old, but still wanted to share.
ReplyDeleteThis could be due to the parameters data type in the stored procedure/query not being the same as the parameter in your report. I had the same issue, but modified the data type of the query's data type to match the parameter in the rdl file and it ended up working out fine.
I did something similar. My problem is the user updating the Extension & Parameter settings and then calling sp_start_job.
ReplyDeleteUPDATE ReportServer.dbo.Subscriptions
SET Parameters =
(SELECT 'print_customer_nameTruejob_cut_sheet_id'
+ (SELECT CONVERT(NVARCHAR(6), @job_cut_sheet_id) )
+ '')
, ExtensionSettings =
(SELECT 'TOcwire@company.comIncludeReportTrueRenderFormatPDFSubject'
+ (SELECT @SubjectBody)
+ 'Comment'
+ (SELECT @SubjectBody)
+'IncludeLinkFalsePriorityNORMAL')
WHERE ReportServer.dbo.Subscriptions.SubscriptionId = '45559D89-A0D3-456D-A0DD-6E6072FF34AB'
DECLARE @ScheduleId as NVARCHAR(50)
SET @ScheduleId = 'CB8EAD1A-044A-4D8D-B667-7326ECE2275B'
EXEC msdb.dbo.sp_start_job @ScheduleId