在电子邮件中发送 CLR 存储过程结果
Send CLR stored procedure results in email
我需要将 CLR 存储过程的结果(我无法更改 sproc/clr 程序集)作为 HTML 通过电子邮件发送。是否可以在不使用临时表或其他类型的持久化的情况下捕获和格式化存储过程的结果集(通过电子邮件发送)?
USE msdb
EXEC sp_send_dbmail
@profile_name = 'MailProfile1', --you will need to create this profile in the Database Mail under Management
@recipients = 'test@email.com',
@subject = 'CLR Sproc Resultset',
@body = 'Resultset is attached.',
@execute_query_database = '[DatabaseName]',
@query = 'exec [DatabaseName].[SchemaName].[CLRProcName]'
试试这个,希望它能满足您的需要。
我在工作中使用 Ola Hallengren's SQL Server Maintenance Solution 进行数据库备份和索引优化。我写了几个不同的存储过程来在每晚作业完成时生成电子邮件,这样我就可以一目了然地看到每个数据库备份花费了多长时间,重建了多少索引和统计信息以及 tables,等等
下面是我为索引和统计写的存储过程。
您必须修改它以满足您自己的需要和源数据,但作为发送 HTML 电子邮件的模板,它应该适用于任何东西。
虽然你有一个 CLR 存储过程,但你必须创建一个与 SP returns 具有相同架构的临时 table,然后执行 INSERT EXEC 否则你会赢不能使用我的代码。
CREATE PROCEDURE dbo.spCommandLogIndexRebuildTimePerDatabase
@Operator sysname
AS
BEGIN
SET NOCOUNT ON;
/* Debug Block
DECLARE @Operator sysname = 'Your Operator Name';
--*/;
DECLARE @MaxID int
, @xml nvarchar(MAX)
, @body nvarchar(MAX)
, @subj nvarchar(255) = N'Index Optimise Results: ' + CAST(CAST(SYSDATETIME() AS date) AS nvarchar) + N' (' + @@SERVERNAME + N')'
, @span_start nchar(31) = N'<span style="font-weight:bold">'
, @span_end nchar(7) = N'</span>'
, @email varchar(255);
-- drop temp table
BEGIN
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
DROP TABLE #Temp;
END
-- create temp table
BEGIN
CREATE TABLE #Temp
(
ID int NOT NULL IDENTITY PRIMARY KEY
, [Database] sysname
, [Indexes] int
, [Statistics] int
, [TotalDuration] decimal(19, 3)
, [Time] time
);
END;
-- fill temp table
BEGIN
-- get the starting ID of the latest group of backups
WITH CTEBaseData
AS
(
SELECT l.ID
, l.CommandType
, l.DatabaseName
, l.StartTime
, l.EndTime
, DATEDIFF(MILLISECOND, l.StartTime, l.EndTime) AS DurationMS
, ROW_NUMBER() OVER (ORDER BY l.StartTime) AS RowNum
FROM dbo.CommandLog l
WHERE l.CommandType IN (N'ALTER_INDEX', N'UPDATE_STATISTICS')
)
SELECT @MaxID = MAX(a.ID)
FROM CTEBaseData a
LEFT JOIN CTEBaseData b
ON a.RowNum = b.RowNum + 1
WHERE DATEDIFF(SECOND, ISNULL(b.EndTime, '2013-01-01'), a.StartTime) > 3600;
-- fill the temp table
WITH CTEObjectTimes
AS
(
SELECT l.DatabaseName AS [Database]
, CASE l.CommandType WHEN N'ALTER_INDEX' THEN 1 ELSE 0 END AS [Indexes]
, CASE l.CommandType WHEN N'UPDATE_STATISTICS' THEN 1 ELSE 0 END AS [Statistics]
, DATEDIFF(MILLISECOND, l.StartTime, l.EndTime) AS [Milliseconds]
FROM dbo.CommandLog l
WHERE l.CommandType IN (N'ALTER_INDEX', N'UPDATE_STATISTICS')
AND l.ID >= @MaxID
)
, CTEIndividualTotals
AS
(
SELECT c.[Database]
, SUM(c.[Indexes]) AS [Indexes]
, SUM(c.[Statistics]) AS [Statistics]
, SUM(c.[Milliseconds]) AS [Milliseconds]
FROM CTEObjectTimes c
GROUP BY c.[Database]
)
, CTEResult
AS
(
SELECT c.[Database]
, c.[Indexes]
, c.[Statistics]
, c.[Milliseconds]
, 0 AS SortOrder
FROM CTEIndividualTotals c
UNION ALL
SELECT N'Total'
, SUM(c.[Indexes])
, SUM(c.[Statistics])
, SUM(c.Milliseconds)
, 1
FROM CTEIndividualTotals c
)
INSERT #Temp
(
[Database]
, [Indexes]
, [Statistics]
, [TotalDuration]
, [Time]
)
SELECT c.[Database]
, c.[Indexes]
, c.[Statistics]
, CONVERT(decimal(19, 3), c.[Milliseconds] / 1000.00)
, CONVERT(time, DATEADD(MILLISECOND, c.[Milliseconds], 0))
FROM CTEResult c
ORDER BY [SortOrder]
, [Database];
END;
-- convert temp table to html table
SELECT @xml = CONVERT
(
nvarchar(MAX)
, (
SELECT CASE t.[Database] WHEN N'Total' THEN @span_start + t.[Database] + @span_end ELSE t.[Database] END AS [td]
, N''
, N'right' AS [td/@align]
, CASE t.[Database] WHEN N'Total' THEN @span_start + CONVERT(nvarchar(10), t.[Indexes]) + @span_end ELSE CONVERT(nvarchar(10), t.[Indexes]) END AS [td]
, N''
, N'right' AS [td/@align]
, CASE t.[Database] WHEN N'Total' THEN @span_start + CONVERT(nvarchar(10), t.[Statistics]) + @span_end ELSE CONVERT(nvarchar(10), t.[Statistics]) END AS [td]
, N''
, N'right' AS [td/@align]
, CASE t.[Database] WHEN N'Total' THEN @span_start ELSE '' END
+ LEFT(CONVERT(nvarchar(50), t.[Time]), 2) + N'h ' + SUBSTRING(CONVERT(nvarchar(50), t.[Time]), 4, 2) + N'm ' + SUBSTRING(CONVERT(nvarchar(50), t.[Time]), 7, 6) + N's'
+ CASE t.[Database] WHEN N'Total' THEN @span_end ELSE '' END AS [td]
FROM #Temp t
FOR XML PATH('tr')
, ELEMENTS
)
);
-- combine the table rows from above into a complete html document
SELECT @body = N'<html><body><H3>Index Optimise Results for '
+ @@SERVERNAME
+ N' on '
+ CONVERT(nvarchar(10), SYSDATETIME(), 120)
+ N'</H3><table border = 1><tr><th> Database </th><th> Indexes </th><th> Statistics </th><th> Total Time </th></tr>'
+ REPLACE(REPLACE(@xml, '<', '<'), '>', '>')
+ N'</table></body></html>';
-- get the email address of the operator
SELECT @email = o.email_address
FROM msdb.dbo.sysoperators o
WHERE o.name = @Operator;
-- just in case the operator is non-existent
SELECT @email = ISNULL(@email, 'your.fallback.email.account@your.domain.com');
/* Debug Block
SELECT *
FROM #Temp;
SELECT @Body AS Body
, @email AS Email;
--*/;
-- send the email
EXEC msdb.dbo.sp_send_dbmail
@profile_name = N'Database Mail Account'
, @recipients = @email
, @subject = @subj
, @body = @body
, @body_format = 'HTML';
END;
GO
如果您对此有任何疑问,请随时提问!
我需要将 CLR 存储过程的结果(我无法更改 sproc/clr 程序集)作为 HTML 通过电子邮件发送。是否可以在不使用临时表或其他类型的持久化的情况下捕获和格式化存储过程的结果集(通过电子邮件发送)?
USE msdb
EXEC sp_send_dbmail
@profile_name = 'MailProfile1', --you will need to create this profile in the Database Mail under Management
@recipients = 'test@email.com',
@subject = 'CLR Sproc Resultset',
@body = 'Resultset is attached.',
@execute_query_database = '[DatabaseName]',
@query = 'exec [DatabaseName].[SchemaName].[CLRProcName]'
试试这个,希望它能满足您的需要。
我在工作中使用 Ola Hallengren's SQL Server Maintenance Solution 进行数据库备份和索引优化。我写了几个不同的存储过程来在每晚作业完成时生成电子邮件,这样我就可以一目了然地看到每个数据库备份花费了多长时间,重建了多少索引和统计信息以及 tables,等等
下面是我为索引和统计写的存储过程。
您必须修改它以满足您自己的需要和源数据,但作为发送 HTML 电子邮件的模板,它应该适用于任何东西。
虽然你有一个 CLR 存储过程,但你必须创建一个与 SP returns 具有相同架构的临时 table,然后执行 INSERT EXEC 否则你会赢不能使用我的代码。
CREATE PROCEDURE dbo.spCommandLogIndexRebuildTimePerDatabase
@Operator sysname
AS
BEGIN
SET NOCOUNT ON;
/* Debug Block
DECLARE @Operator sysname = 'Your Operator Name';
--*/;
DECLARE @MaxID int
, @xml nvarchar(MAX)
, @body nvarchar(MAX)
, @subj nvarchar(255) = N'Index Optimise Results: ' + CAST(CAST(SYSDATETIME() AS date) AS nvarchar) + N' (' + @@SERVERNAME + N')'
, @span_start nchar(31) = N'<span style="font-weight:bold">'
, @span_end nchar(7) = N'</span>'
, @email varchar(255);
-- drop temp table
BEGIN
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
DROP TABLE #Temp;
END
-- create temp table
BEGIN
CREATE TABLE #Temp
(
ID int NOT NULL IDENTITY PRIMARY KEY
, [Database] sysname
, [Indexes] int
, [Statistics] int
, [TotalDuration] decimal(19, 3)
, [Time] time
);
END;
-- fill temp table
BEGIN
-- get the starting ID of the latest group of backups
WITH CTEBaseData
AS
(
SELECT l.ID
, l.CommandType
, l.DatabaseName
, l.StartTime
, l.EndTime
, DATEDIFF(MILLISECOND, l.StartTime, l.EndTime) AS DurationMS
, ROW_NUMBER() OVER (ORDER BY l.StartTime) AS RowNum
FROM dbo.CommandLog l
WHERE l.CommandType IN (N'ALTER_INDEX', N'UPDATE_STATISTICS')
)
SELECT @MaxID = MAX(a.ID)
FROM CTEBaseData a
LEFT JOIN CTEBaseData b
ON a.RowNum = b.RowNum + 1
WHERE DATEDIFF(SECOND, ISNULL(b.EndTime, '2013-01-01'), a.StartTime) > 3600;
-- fill the temp table
WITH CTEObjectTimes
AS
(
SELECT l.DatabaseName AS [Database]
, CASE l.CommandType WHEN N'ALTER_INDEX' THEN 1 ELSE 0 END AS [Indexes]
, CASE l.CommandType WHEN N'UPDATE_STATISTICS' THEN 1 ELSE 0 END AS [Statistics]
, DATEDIFF(MILLISECOND, l.StartTime, l.EndTime) AS [Milliseconds]
FROM dbo.CommandLog l
WHERE l.CommandType IN (N'ALTER_INDEX', N'UPDATE_STATISTICS')
AND l.ID >= @MaxID
)
, CTEIndividualTotals
AS
(
SELECT c.[Database]
, SUM(c.[Indexes]) AS [Indexes]
, SUM(c.[Statistics]) AS [Statistics]
, SUM(c.[Milliseconds]) AS [Milliseconds]
FROM CTEObjectTimes c
GROUP BY c.[Database]
)
, CTEResult
AS
(
SELECT c.[Database]
, c.[Indexes]
, c.[Statistics]
, c.[Milliseconds]
, 0 AS SortOrder
FROM CTEIndividualTotals c
UNION ALL
SELECT N'Total'
, SUM(c.[Indexes])
, SUM(c.[Statistics])
, SUM(c.Milliseconds)
, 1
FROM CTEIndividualTotals c
)
INSERT #Temp
(
[Database]
, [Indexes]
, [Statistics]
, [TotalDuration]
, [Time]
)
SELECT c.[Database]
, c.[Indexes]
, c.[Statistics]
, CONVERT(decimal(19, 3), c.[Milliseconds] / 1000.00)
, CONVERT(time, DATEADD(MILLISECOND, c.[Milliseconds], 0))
FROM CTEResult c
ORDER BY [SortOrder]
, [Database];
END;
-- convert temp table to html table
SELECT @xml = CONVERT
(
nvarchar(MAX)
, (
SELECT CASE t.[Database] WHEN N'Total' THEN @span_start + t.[Database] + @span_end ELSE t.[Database] END AS [td]
, N''
, N'right' AS [td/@align]
, CASE t.[Database] WHEN N'Total' THEN @span_start + CONVERT(nvarchar(10), t.[Indexes]) + @span_end ELSE CONVERT(nvarchar(10), t.[Indexes]) END AS [td]
, N''
, N'right' AS [td/@align]
, CASE t.[Database] WHEN N'Total' THEN @span_start + CONVERT(nvarchar(10), t.[Statistics]) + @span_end ELSE CONVERT(nvarchar(10), t.[Statistics]) END AS [td]
, N''
, N'right' AS [td/@align]
, CASE t.[Database] WHEN N'Total' THEN @span_start ELSE '' END
+ LEFT(CONVERT(nvarchar(50), t.[Time]), 2) + N'h ' + SUBSTRING(CONVERT(nvarchar(50), t.[Time]), 4, 2) + N'm ' + SUBSTRING(CONVERT(nvarchar(50), t.[Time]), 7, 6) + N's'
+ CASE t.[Database] WHEN N'Total' THEN @span_end ELSE '' END AS [td]
FROM #Temp t
FOR XML PATH('tr')
, ELEMENTS
)
);
-- combine the table rows from above into a complete html document
SELECT @body = N'<html><body><H3>Index Optimise Results for '
+ @@SERVERNAME
+ N' on '
+ CONVERT(nvarchar(10), SYSDATETIME(), 120)
+ N'</H3><table border = 1><tr><th> Database </th><th> Indexes </th><th> Statistics </th><th> Total Time </th></tr>'
+ REPLACE(REPLACE(@xml, '<', '<'), '>', '>')
+ N'</table></body></html>';
-- get the email address of the operator
SELECT @email = o.email_address
FROM msdb.dbo.sysoperators o
WHERE o.name = @Operator;
-- just in case the operator is non-existent
SELECT @email = ISNULL(@email, 'your.fallback.email.account@your.domain.com');
/* Debug Block
SELECT *
FROM #Temp;
SELECT @Body AS Body
, @email AS Email;
--*/;
-- send the email
EXEC msdb.dbo.sp_send_dbmail
@profile_name = N'Database Mail Account'
, @recipients = @email
, @subject = @subj
, @body = @body
, @body_format = 'HTML';
END;
GO
如果您对此有任何疑问,请随时提问!