通过电子邮件发送CLR存储过程结果

时间:2015-04-17 13:50:20

标签: sql-server html-email clrstoredprocedure

我需要将CLR存储过程的结果(我无法改变sproc / clr程序集)作为带有电子邮件的HTML发送。是否有可能捕获和格式化sproc的结果集(通过电子邮件发送)而不使用临时表或其他类型的持久性?

2 个答案:

答案 0 :(得分:2)

  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]'  

试试这个,希望它能得到你需要的东西。

答案 1 :(得分:2)

我在这里使用Ola Hallengren's SQL Server Maintenance Solution进行数据库备份和索引优化。我写了几个不同的存储过程,每天晚上当作业结束时生成电子邮件,这样我就可以一眼看出每个数据库备份花了多长时间,重建了多少索引和统计数据以及哪些表等等。

我为索引和统计编写的存储过程如下。

您必须修改它以满足您自己的需求和源数据,但作为发送HTML电子邮件的模板,它应该适用于任何事情。

虽然你有一个CLR存储过程,但你必须创建一个与SP返回相同模式的临时表,然后执行INSERT EXEC,否则你将无法使用我的代码。 / p>

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, '&lt;', '<'), '&gt;', '>')
                    + 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

如果您对此有任何疑问,请随时提出!