简体   繁体   English

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

[英]Send CLR stored procedure results in email

I need to send the results of a CLR stored procedure (I am not able to alter the sproc / clr assembly) as HTML with email. 我需要使用电子邮件通过HTML将CLR存储过程的结果(我无法更改sproc / clr程序集)发送为HTML。 Is there a posibility to capture and format the resultset of the sproc (to email it) without using temp tables or other kind of persisting? 是否有可能在不使用临时表或其他持久化的情况下捕获并格式化sproc的结果集(以电子邮件发送)?

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

Try this out, hopefully it should get what you need. 试试看,希望它能满足您的需求。

I use Ola Hallengren's SQL Server Maintenance Solution for my database backups and index optimisation here at work. 我在这里使用Ola Hallengren的SQL Server维护解决方案进行数据库备份和索引优化。 I wrote a couple different stored procedures to produce emails every night when the jobs finish so I can see at a glance how long each DB backup took, how many indexes and statistics were rebuilt and on which tables, etc. 我写了几个不同的存储过程,每晚在工作结束时产生电子邮件,因此我一眼就能看到每个数据库备份花费了多长时间,重建了多少索引和统计信息以及在哪些表上进行了构建,等等。

The stored procedure I wrote for the indexes and statistics is below. 我为索引和统计信息编写的存储过程如下。

You'll have to modify it to suit your own needs and source data, but as a template to send HTML email, it should work for anything. 您必须对其进行修改以适合您自己的需求和源数据,但是作为发送HTML电子邮件的模板,它应该适用于任何情况。

As you've got a CLR stored procedure though, you'll have to create a temp table with the same schema as the SP returns, then do an INSERT EXEC otherwise you won't be able to use my code. 但是,由于有了CLR存储过程,因此必须创建一个具有与SP返回相同模式的临时表,然后执行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, '&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

If you have any questions about this, don't hesitate to ask! 如果您对此有任何疑问,请随时提出!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM