我想建立一个后端系统,允许我每晚运行每个报告,然后查询执行日志,看看是否有任何失败。我知道你可以为这些报告建立订阅并定义参数等,但有没有一种方法可以在不建立每个订阅的情况下使用TSQL从ReportServer数据库执行每个报告?
我知道您的总体目标是实现自动化,而不必为每个报告编写订阅。你说你想在T-SQL中实现它,但这是满足你的总体目标所必需的吗?
如果可以接受,例如.Net,那么可以使用System.Data.SqlClient.SqlConnection和相关类来查询报表服务器目录并获取所有报表的列表。
然后,您可以使用System.Net.WebClient或类似工具尝试下载报告的pdf。从那里,您可以读取执行日志,也可以捕获.Net代码中的错误。
编辑
好吧,既然你接受了答案,而且你似乎可以走这条路,我要说的是,如果你不熟悉.net,这对你来说可能是一条很长的路。这里有一些东西可以让你开始。
下面是一个使用.Net的c#函数,它将查询报表目录。如果safeIntermediate设置为true,它将只捕获可以立即运行的报告,因为在中没有参数或默认值包含这些参数。
IEnumerable<string> GetReportPaths(
string conStr,
bool safeImmediate // as in, you can exexute the report right away without paramters
) {
using (var con = new SqlConnection(conStr))
using (var cmd = new SqlCommand()) {
cmd.Connection = con;
cmd.CommandText = @"select path from catalog where type=2";
con.Open();
if (safeImmediate)
cmd.CommandText = @"
select path
from catalog
cross apply (select
params = convert(xml, Parameter).value('count(Parameters/Parameter)', 'int'),
defaults = convert(xml, Parameter).value('count(Parameters/Parameter/DefaultValues/Value)', 'int')
) counts
where type = 2
and params = defaults
and path not like '%subreport%' -- this is not standard. Just works for my conventions
";
using (var rdr = cmd.ExecuteReader())
while (rdr.Read())
yield return rdr["path"].ToString();
}
}
下一个功能将下载一个报告,并给出正确的路径:
byte[] DownloadReport (
WebClient wc,
string coreUrl,
string fullReportPath,
string parameters = "" // you won't use this but may come in handy for other uses
) {
var pathToViewer = "ReportServer/Pages/ReportViewer.aspx"; // for typical ssrs installs
var renderOptions = "&rs:Format=pdf&rs:Command=Render"; // return as pdf
var url = $@"{coreUrl}/{pathToViewer}?{fullReportPath}{parameters}{renderOptions}";
url = Uri.EscapeUriString(url); // url's don't like certain characters, fix it
return wc.DownloadData(url);
}
这利用上面的函数来找到成功的和不成功的:
var sqlCon = "Server=yourReportServer; Database=ReportServer; Integrated Security=yes"; // or whatever
var ssrsSite = "http://www.yourSite.org";
using (var wc = new WebClient()) {
wc.UseDefaultCredentials = true; // or whatever
int loops = 3; // get rid of this when you're ready for prime-time
foreach(var path in GetReportPaths(sqlCon, true)) {
try {
DownloadReport(wc, ssrsSite, path);
Debug.WriteLine($"Success with: {path}");
}
catch(Exception ex) { // you might want to get more specific
Debug.WriteLine($"Failed with: {path}");
}
if (loops-- == 0)
break;
}
}
需要学习的东西很多,但也可能非常有益。祝你好运