복붙노트

[SQL] 이메일에 대한 HTML 테이블에 SQL 쿼리 결과 테이블로 변환

SQL

이메일에 대한 HTML 테이블에 SQL 쿼리 결과 테이블로 변환

나는 결과 테이블을 반환하는 SQL 쿼리를 실행하고 있습니다. 나는 dbo.sp_send_dbMail를 사용하여 이메일에 표를 보내려고합니다.

HTML 테이블에 테이블을 설정하는 SQL 내에서 간단한 방법이 있나요? 현재, 나는 수동으로 구성 COALESCE을 사용하고 난 emailBody로 사용하는 VARCHAR로 결과를 가져온 거에요.

이 작업을 수행하는 더 좋은 방법이 있나요?

해결법

  1. ==============================

    1.여기에 "- 쉬운 방법 HTML 테이블에 형식 쿼리 출력"라는 제목의 기사에서 그것을 할 수있는 하나의 방법입니다. 당신은 테이블의 목록과 행 수를 얻을이 예에서 것들에 대한 자신의 쿼리의 세부 사항을 대체해야합니다.

    여기에 "- 쉬운 방법 HTML 테이블에 형식 쿼리 출력"라는 제목의 기사에서 그것을 할 수있는 하나의 방법입니다. 당신은 테이블의 목록과 행 수를 얻을이 예에서 것들에 대한 자신의 쿼리의 세부 사항을 대체해야합니다.

    declare @body varchar(max)
    
    set @body = cast( (
    select td = dbtable + '</td><td>' + cast( entities as varchar(30) ) + '</td><td>' + cast( rows as varchar(30) )
    from (
          select dbtable  = object_name( object_id ),
                 entities = count( distinct name ),
                 rows     = count( * )
          from sys.columns
          group by object_name( object_id )
          ) as d
    for xml path( 'tr' ), type ) as varchar(max) )
    
    set @body = '<table cellpadding="2" cellspacing="2" border="1">'
              + '<tr><th>Database Table</th><th>Entity Count</th><th>Total Rows</th></tr>'
              + replace( replace( @body, '&lt;', '<' ), '&gt;', '>' )
              + '</table>'
    
    print @body
    

    당신이 @body 일단, 당신은 당신이 원하는대로 이메일 메커니즘을 사용할 수 있습니다.

  2. ==============================

    2.난 당신이 다른 반응처럼 하드 코드 열 필요가 없습니다, HTML 테이블에 어떤 임의의 쿼리를 켤 수있는 동적 proc 디렉토리를했다.

    난 당신이 다른 반응처럼 하드 코드 열 필요가 없습니다, HTML 테이블에 어떤 임의의 쿼리를 켤 수있는 동적 proc 디렉토리를했다.

    -- Description: Turns a query into a formatted HTML table. Useful for emails. 
    -- Any ORDER BY clause needs to be passed in the separate ORDER BY parameter.
    -- =============================================
    CREATE PROC [dbo].[spQueryToHtmlTable] 
    (
      @query nvarchar(MAX), --A query to turn into HTML format. It should not include an ORDER BY clause.
      @orderBy nvarchar(MAX) = NULL, --An optional ORDER BY clause. It should contain the words 'ORDER BY'.
      @html nvarchar(MAX) = NULL OUTPUT --The HTML output of the procedure.
    )
    AS
    BEGIN   
      SET NOCOUNT ON;
    
      IF @orderBy IS NULL BEGIN
        SET @orderBy = ''  
      END
    
      SET @orderBy = REPLACE(@orderBy, '''', '''''');
    
      DECLARE @realQuery nvarchar(MAX) = '
        DECLARE @headerRow nvarchar(MAX);
        DECLARE @cols nvarchar(MAX);    
    
        SELECT * INTO #dynSql FROM (' + @query + ') sub;
    
        SELECT @cols = COALESCE(@cols + '', '''''''', '', '''') + ''['' + name + ''] AS ''''td''''''
        FROM tempdb.sys.columns 
        WHERE object_id = object_id(''tempdb..#dynSql'')
        ORDER BY column_id;
    
        SET @cols = ''SET @html = CAST(( SELECT '' + @cols + '' FROM #dynSql ' + @orderBy + ' FOR XML PATH(''''tr''''), ELEMENTS XSINIL) AS nvarchar(max))''    
    
        EXEC sys.sp_executesql @cols, N''@html nvarchar(MAX) OUTPUT'', @html=@html OUTPUT
    
        SELECT @headerRow = COALESCE(@headerRow + '''', '''') + ''<th>'' + name + ''</th>'' 
        FROM tempdb.sys.columns 
        WHERE object_id = object_id(''tempdb..#dynSql'')
        ORDER BY column_id;
    
        SET @headerRow = ''<tr>'' + @headerRow + ''</tr>'';
    
        SET @html = ''<table border="1">'' + @headerRow + @html + ''</table>'';    
        ';
    
      EXEC sys.sp_executesql @realQuery, N'@html nvarchar(MAX) OUTPUT', @html=@html OUTPUT
    END
    GO
    

    용법:

    DECLARE @html nvarchar(MAX);
    EXEC spQueryToHtmlTable @html = @html OUTPUT,  @query = N'SELECT * FROM dbo.People', @orderBy = N'ORDER BY FirstName';
    
    EXEC msdb.dbo.sp_send_dbmail
        @profile_name = 'Foo',
        @recipients = 'bar@baz.com;',
        @subject = 'HTML email',
        @body = @html,
        @body_format = 'HTML',
        @query_no_truncate = 1,
        @attach_query_result_as_file = 0;
    

    관련 : 다음은 CSV 문자열로 임의의 쿼리를 설정하는 유사한 코드입니다.

  3. ==============================

    3.이것은 당신에게 몇 가지 아이디어를 줄 수도 있습니다 -

    이것은 당신에게 몇 가지 아이디어를 줄 수도 있습니다 -

    CREATE TABLE #Temp 
    ( 
      [Rank]  [int],
      [Player Name]  [varchar](128),
      [Ranking Points] [int],
      [Country]  [varchar](128)
    )
    
    
    INSERT INTO #Temp
    SELECT 1,'Rafael Nadal',12390,'Spain'
    UNION ALL
    SELECT 2,'Roger Federer',7965,'Switzerland'
    UNION ALL
    SELECT 3,'Novak Djokovic',7880,'Serbia'
    
    
    DECLARE @xml NVARCHAR(MAX)
    DECLARE @body NVARCHAR(MAX)
    
    
    SET @xml = CAST(( SELECT [Rank] AS 'td','',[Player Name] AS 'td','',
           [Ranking Points] AS 'td','', Country AS 'td'
    FROM  #Temp ORDER BY Rank 
    FOR XML PATH('tr'), ELEMENTS ) AS NVARCHAR(MAX))
    
    
    SET @body ='<html><body><H3>Tennis Rankings Info</H3>
    <table border = 1> 
    <tr>
    <th> Rank </th> <th> Player Name </th> <th> Ranking Points </th> <th> Country </th></tr>'    
    
    
    SET @body = @body + @xml +'</table></body></html>'
    
    
    EXEC msdb.dbo.sp_send_dbmail
    @profile_name = 'SQL ALERTING', -- replace with your SQL Database Mail Profile 
    @body = @body,
    @body_format ='HTML',
    @recipients = 'bruhaspathy@hotmail.com', -- replace with your email address
    @subject = 'E-mail in Tabular Format' ;
    
    
    DROP TABLE #Temp
    
  4. ==============================

    4.JustinStolle 코드를 기반으로 (감사합니다), 나는 열 이름을 지정하지 않고도 일반적인 될 수있는 솔루션을 원했습니다.

    JustinStolle 코드를 기반으로 (감사합니다), 나는 열 이름을 지정하지 않고도 일반적인 될 수있는 솔루션을 원했습니다.

    이 샘플은 임시 테이블의 데이터를 사용하지만 필요에 따라 물론 그것을 조정할 수 있습니다.

    여기에 내가 무엇을 가지고 있습니다 :

    DECLARE @htmlTH VARCHAR(MAX) = '',
            @htmlTD VARCHAR(MAX)
    
    --get header, columns name
    SELECT @htmlTH = @htmlTH + '<TH>' +  name + '</TH>' FROM tempdb.sys.columns WHERE object_id = OBJECT_ID('tempdb.dbo.#results')
    
    --convert table to XML PATH, ELEMENTS XSINIL is used to include NULL values
    SET @htmlTD = (SELECT * FROM #results FOR XML PATH('TR'), ELEMENTS XSINIL)
    
    --convert the way ELEMENTS XSINIL display NULL to display word NULL
    SET @htmlTD = REPLACE(@htmlTD, ' xsi:nil="true"/>', '>NULL</TD>')
    SET @htmlTD = REPLACE(@htmlTD, '<TR xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">', '<TR>')
    
    --FOR XML PATH will set tags for each column name, <columnName1>abc</columnName1><columnName2>def</columnName2>
    --this will replace all the column names with TD (html table data tag)
    SELECT @htmlTD = REPLACE(REPLACE(@htmlTD, '<' + name + '>', '<TD>'), '</' + name + '>', '</TD>')
    FROM tempdb.sys.columns WHERE object_id = OBJECT_ID('tempdb.dbo.#results')
    
    
    SELECT '<TABLE cellpadding="2" cellspacing="2" border="1">'
         + '<TR>' + @htmlTH + '</TR>'
         + @htmlTD
         + '</TABLE>'
    
  5. ==============================

    5.가정하자 누군가가 여기에 자신의 길을 발견하고, 내 읽어 보시기 바랍니다 ... 그것은 편집하고 작업하는 표시 응답 SQL의 사용을 이해하지 못합니다. 테이블 : 직원, 열 : staffname, staffphone 및 staffDOB

    가정하자 누군가가 여기에 자신의 길을 발견하고, 내 읽어 보시기 바랍니다 ... 그것은 편집하고 작업하는 표시 응답 SQL의 사용을 이해하지 못합니다. 테이블 : 직원, 열 : staffname, staffphone 및 staffDOB

    declare @body varchar(max)
    
    --    Create the body
    set @body = cast( (
    select td = dbtable + '</td><td>' + cast( phone as varchar(30) ) + '</td><td>' + cast( age as varchar(30) )
    from (
          select dbtable  = StaffName ,
                   phone = staffphone,
                   age          = datepart(day,staffdob)
          from staff
          group by staffname,StaffPhone,StaffDOB  
          ) as d
    for xml path( 'tr' ), type ) as varchar(max) )
    set @body = '<table cellpadding="2" cellspacing="2" border="1">'
                  + '<tr><th>Database Table</th><th>Entity Count</th><th>Total Rows</th></tr>'
                  + replace( replace( @body, '&lt;', '<' ), '&gt;', '>' )
                  + '<table>'
    print @body
    
  6. ==============================

    6.나는 위의 마헤 예를 사용하여 여러 테이블을 인쇄했습니다. 다른 사람의 편의를 위해 게시

    나는 위의 마헤 예를 사용하여 여러 테이블을 인쇄했습니다. 다른 사람의 편의를 위해 게시

    USE MyDataBase
    
    DECLARE @RECORDS_THAT_NEED_TO_SEND_EMAIL TABLE (ID INT IDENTITY(1,1),
                                                    POS_ID INT, 
                                                    POS_NUM VARCHAR(100) NULL, 
                                                    DEPARTMENT VARCHAR(100) NULL, 
                                                    DISTRICT VARCHAR(50) NULL,
                                                    COST_LOC VARCHAR(100) NULL,
                                                    EMPLOYEE_NAME VARCHAR(200) NULL)
    
    INSERT INTO @RECORDS_THAT_NEED_TO_SEND_EMAIL(POS_ID,POS_NUM,DISTRICT,COST_LOC,DEPARTMENT,EMPLOYEE_NAME) 
    SELECT uvwpos.POS_ID,uvwpos.POS_NUM,uvwpos.DISTRICT, uvwpos.COST_LOC,uvwpos.DEPARTMENT,uvemp.LAST_NAME + ' ' + uvemp.FIRST_NAME 
    FROM uvwPOSITIONS uvwpos LEFT JOIN uvwEMPLOYEES uvemp 
    on uvemp.POS_ID=uvwpos.POS_ID 
    WHERE uvwpos.ACTIVE=1 AND uvwpos.POS_NUM LIKE 'sde%'AND (
    (RTRIM(LTRIM(LEFT(uvwpos.DEPARTMENT,LEN(uvwpos.DEPARTMENT)-1))) <> RTRIM(LTRIM(uvwpos.COST_LOC))) 
    OR (uvwpos.DISTRICT IS NULL) 
    OR (uvwpos.COST_LOC IS NULL)   )
    
    DECLARE @RESULT_DISTRICT_ISEMPTY varchar(4000)
    DECLARE @RESULT_COST_LOC_ISEMPTY varchar(4000)
    DECLARE @RESULT_COST_LOC__AND_DISTRICT_NOT_MATCHING  varchar(4000)
    DECLARE @BODY NVARCHAR(MAX)
    DECLARE @HTMLHEADER VARCHAR(100)
    DECLARE @HTMLFOOTER VARCHAR(100)
    SET @HTMLHEADER='<html><body>'
    SET @HTMLFOOTER ='</body></html>'
    SET @RESULT_DISTRICT_ISEMPTY  = '';
    SET @BODY =@HTMLHEADER+ '<H3>PositionNumber where District is Empty.</H3>
    <table border = 1> 
    <tr>
    <th> POS_ID </th> <th> POS_NUM </th> <th> DEPARTMENT </th> <th> DISTRICT </th> <th> COST_LOC </th></tr>'   
    
    SET @RESULT_DISTRICT_ISEMPTY = CAST(( SELECT [POS_ID] AS 'td','',RTRIM([POS_NUM]) AS 'td','',
         ISNULL(LEFT(DEPARTMENT,LEN(DEPARTMENT)-1),'          ') AS 'td','', ISNULL([DISTRICT],'        ')  AS 'td','',ISNULL([COST_LOC],'           ') AS 'td'
    FROM  @RECORDS_THAT_NEED_TO_SEND_EMAIL 
    WHERE DISTRICT IS NULL
    FOR XML PATH('tr'), ELEMENTS ) AS VARCHAR(MAX))
    
    SET @BODY = @BODY + @RESULT_DISTRICT_ISEMPTY +'</table>'
    
    
    DECLARE @RESULT_COST_LOC_ISEMPTY_HEADER VARCHAR(400)
    SET @RESULT_COST_LOC_ISEMPTY_HEADER  ='<H3>PositionNumber where COST_LOC is Empty.</H3>
    <table border = 1> 
    <tr>
    <th> POS_ID </th> <th> POS_NUM </th> <th> DEPARTMENT </th> <th> DISTRICT </th> <th> COST_LOC </th></tr>'   
    
    SET @RESULT_COST_LOC_ISEMPTY = CAST(( SELECT [POS_ID] AS 'td','',RTRIM([POS_NUM]) AS 'td','',
         ISNULL(LEFT(DEPARTMENT,LEN(DEPARTMENT)-1),'          ') AS 'td','', ISNULL([DISTRICT],'        ')  AS 'td','',ISNULL([COST_LOC],'           ') AS 'td'
    FROM  @RECORDS_THAT_NEED_TO_SEND_EMAIL 
    WHERE COST_LOC IS NULL
    FOR XML PATH('tr'), ELEMENTS ) AS VARCHAR(MAX))
    
    SET @BODY = @BODY + @RESULT_COST_LOC_ISEMPTY_HEADER+ @RESULT_COST_LOC_ISEMPTY +'</table>'
    
    DECLARE @RESULT_COST_LOC__AND_DISTRICT_NOT_MATCHING_HEADER VARCHAR(400)
    SET @RESULT_COST_LOC__AND_DISTRICT_NOT_MATCHING_HEADER='<H3>PositionNumber where Department and Cost Center are Not Macthing.</H3>
    <table border = 1> 
    <tr>
    <th> POS_ID </th> <th> POS_NUM </th> <th> DEPARTMENT </th> <th> DISTRICT </th> <th> COST_LOC </th></tr>'   
    SET @RESULT_COST_LOC__AND_DISTRICT_NOT_MATCHING = CAST(( SELECT [POS_ID] AS 'td','',RTRIM([POS_NUM]) AS 'td','',
         ISNULL(LEFT(DEPARTMENT,LEN(DEPARTMENT)-1),'          ') AS 'td','', ISNULL([DISTRICT],'        ')  AS 'td','',ISNULL([COST_LOC],'           ') AS 'td'
    FROM  @RECORDS_THAT_NEED_TO_SEND_EMAIL 
    WHERE 
    (RTRIM(LTRIM(LEFT(DEPARTMENT,LEN(DEPARTMENT)-1))) <> RTRIM(LTRIM(COST_LOC)))
    FOR XML PATH('tr'), ELEMENTS ) AS VARCHAR(MAX))
    
    SET @BODY = @BODY + @RESULT_COST_LOC__AND_DISTRICT_NOT_MATCHING_HEADER+ @RESULT_COST_LOC__AND_DISTRICT_NOT_MATCHING  +'</table>'
    
    
    SET @BODY = @BODY + @HTMLFOOTER
    
    USE DDDADMINISTRATION_DB
    --SEND EMAIL
    exec DDDADMINISTRATION_DB.dbo.uspSMTP_NOTIFY_HTML
                                  @EmailSubject = 'District,Department & CostCenter Discrepancies', 
                                  @EmailMessage = @BODY, 
                                  @ToEmailAddress  = 'Slohani@azdes.gov', 
                                  @FromEmailAddress  = 'Slohani@azdes.gov' 
    
    
    EXEC msdb.dbo.sp_send_dbmail
    @profile_name = 'MY POROFILE', -- replace with your SQL Database Mail Profile 
    @body = @BODY,
    @body_format ='HTML',
    @recipients = 'Recepients@internalmail.com', -- replace with your email address
    @subject = 'District,Department & CostCenter Discrepancies' ;
    
  7. ==============================

    7.다른 모든 답변은 변수와 SET 작업을 사용합니다. 다음은 SELECT 문 내에서 할 수있는 방법이다. 그냥 기존의 선택의 열로이 놓습니다.

    다른 모든 답변은 변수와 SET 작업을 사용합니다. 다음은 SELECT 문 내에서 할 수있는 방법이다. 그냥 기존의 선택의 열로이 놓습니다.

        (SELECT 
            '<table style=''font-family:"Verdana"; font-size: 10pt''>'
                        + '<tr bgcolor="#9DBED4"><th>col1</th><th>col2</th><th>col3</th><th>col4</th><th>col5</th></tr>'
                        + replace( replace( body, '&lt;', '<' ), '&gt;', '>' )
                        + '</table>'
        FROM
        (
            select cast( (
                select td = cast(col1 as varchar(5)) + '</td><td align="right">' + col2 + '</td><td>' + col3 + '</td><td align="right">' + cast(col4 as varchar(5)) + '</td><td align="right">' + cast(col5 as varchar(5)) + '</td>'
                from (
                        select col1  = col1,
                                col2 = col2,
                                col3 = col3,
                                col4 = col4,
                                col5 = col5
                        from m_LineLevel as onml
                        where onml.pkey = oni.pkey
                        ) as d
                for xml path( 'tr' ), type ) as varchar(max) ) as body
        ) as bodycte) as LineTable
    
  8. ==============================

    8.여기 내 일반적인 아래의 스크립트를 사용했다. 나는 두 테이블에서 스크립트를 실행하기 위해 이것을 사용 / 메일을 통해 두 개의 HTML 테이블과 같은 SQL 작업 및 전송 결과와 전망을 제공합니다. 당신이 메일 프로필을 작성해야합니다 당연히이 프로그램을 실행하기 전에.

    여기 내 일반적인 아래의 스크립트를 사용했다. 나는 두 테이블에서 스크립트를 실행하기 위해 이것을 사용 / 메일을 통해 두 개의 HTML 테이블과 같은 SQL 작업 및 전송 결과와 전망을 제공합니다. 당신이 메일 프로필을 작성해야합니다 당연히이 프로그램을 실행하기 전에.

    DECLARE @mailfrom varchar(max)
    DECLARE @subject varchar(100)
    DECLARE @tableHTML NVARCHAR(MAX), @tableHTML1 NVARCHAR(MAX), @tableHTML2 NVARCHAR(MAX), @mailbody NVARCHAR(MAX)
    DECLARE @Table1 NVARCHAR(MAX), @Table2 NVARCHAR(MAX)
    DECLARE @jobName varchar(100)
    SELECT @jobName = name from msdb..sysjobs where job_id = $(ESCAPE_NONE(JOBID))
    
    -- If the result set is not empty then fill the Table1 HTML table
    IF (SELECT COUNT(*) FROM [Database].[Schema].[Table1]) > 0
    BEGIN
    SET @Table1 = N''
    SELECT @Table1 = @Table1 + '<tr style="font-size:13px;background-color:#FFFFFF">' + 
        '<td>' + ColumnText + '</td>' +
        '<td>' + CAST(ColumnNumber as nvarchar(30)) + '</td>' + '</tr>'  
    FROM [Database].[Schema].[Table1]
    ORDER BY ColumnText,ColumnNumber
    
    SET @tableHTML1 = 
    N'<table border="1" align="Left" cellpadding="2" cellspacing="0" style="color:black;font-family:arial,helvetica,sans-serif;text-align:left;" >' +
    N'<tr style ="font-size:13px;font-weight: normal;background: #FFFFFF"> 
    <th align=left>ColumnTextHeader1</th>
    <th align=left>ColumnNumberHeader2</th> </tr>' + @Table1 + '</table>'
    END
    ELSE
    BEGIN
    SET @tableHTML1 = N''
    SET @Table1 = N''
    END
    
    
    -- If the result set is not empty then fill the Table2 HTML table
    IF (SELECT COUNT(*) FROM [Database].[Schema].[Table2]) > 0
    BEGIN
    SET @Table2 = N''
    SELECT @Table2 = @Table2 + '<tr style="font-size:13px;background-color:#FFFFFF">' + 
        '<td>' + ColumnText + '</td>' +
        '<td>' + CAST(ColumnNumber as nvarchar(30)) + '</td>' + '</tr>'  
    FROM [Database].[Schema].[Table2]
    ORDER BY ColumnText,ColumnNumber
    
    SET @tableHTML2 = 
    N'<table border="1" align="Left" cellpadding="2" cellspacing="0" style="color:black;font-family:arial,helvetica,sans-serif;text-align:left;" >' +
    N'<tr style ="font-size:13px;font-weight: normal;background: #FFFFFF"> 
    <th align=left>ColumnTextHeader1</th>
    <th align=left>ColumnNumberHeader2</th> </tr>' + @Table2 + '</table>'
    END
    ELSE
    BEGIN
    SET @tableHTML2 = N''
    SET @Table2 = N''
    END
    
    SET @tableHTML = @tableHTML1 + @tableHTML2
    
    -- If result sets from Table1 and Table2 are empty, then don't sent mail.
    IF (SELECT @tableHTML) <> ''
    BEGIN
    SET @mailbody = N' Write mail text here<br><br>' + @tableHTML
    SELECT @mailfrom = 'SQL Server <' + cast(SERVERPROPERTY('ComputerNamePhysicalNETBIOS') as varchar(50)) + '@domain.com>'
    SELECT @subject = N'Mail Subject [Job: ' + @jobName + ']'
        EXEC msdb.dbo.sp_send_dbmail
        @profile_name= 'mailprofilename',
        @recipients= '<mailaddress@domain.com>',
        @from_address = @mailfrom,
        @reply_to = '<mailaddress@domain.com>',
        @subject = @subject,
        @body = @mailbody,
        @body_format = 'HTML'
    --   ,@importance = 'HIGH'
    END
    
  9. ==============================

    9.코드의 조각을 따라, 나는 각 테이블과 테이블 메타 데이터 정보의 HTML 테이블 이름을 포함 문서의 파일 및 목적을 생성하기위한 준비했습니다. 도움이 될 수도 있습니다!

    코드의 조각을 따라, 나는 각 테이블과 테이블 메타 데이터 정보의 HTML 테이블 이름을 포함 문서의 파일 및 목적을 생성하기위한 준비했습니다. 도움이 될 수도 있습니다!

    use Your_Database_Name;
    print '<!DOCTYPE html>'
    PRINT '<html><body>'
    SET NOCOUNT ON
    DECLARE @tableName VARCHAR(30)
    DECLARE tableCursor CURSOR LOCAL FAST_FORWARD FOR
        SELECT T.name AS TableName 
          FROM sys.objects AS T
         WHERE T.type_desc = 'USER_TABLE'
         ORDER BY T.name
    OPEN tableCursor
    FETCH NEXT FROM tableCursor INTO @tableName
    WHILE @@FETCH_STATUS = 0 BEGIN
        print '<table>'
        print '<tr><td><b>Table Name: <b></td><td>'+@tableName+'</td></tr>'
        print '<tr><td><b>Prupose: <b></td><td>????YOu can Fill later????</td></tr>'
        print '</table>'
    
        print '<table>'
        print '<tr><th>ColumnName</th><th>DataType</th><th>Size</th><th>PrecScale</th><th>Nullable</th><th>Default</th><th>Identity</th><th>Remarks</th></tr>'
        SELECT  concat('<tr><td>',
                LEFT(C.name, 30) /*AS ColumnName*/,'</td><td>',
               LEFT(ISC.DATA_TYPE, 10) /*AS DataType*/,'</td><td>',
               C.max_length /*AS Size*/,'</td><td>',
               CAST(P.precision AS VARCHAR(4)) + '/' + CAST(P.scale AS VARCHAR(4)) /*AS PrecScale*/,'</td><td>',
               CASE WHEN C.is_nullable = 1 THEN 'Null' ELSE 'No Null' END /*AS [Nullable]*/,'</td><td>',
               LEFT(ISNULL(ISC.COLUMN_DEFAULT, ' '), 5)  /*AS [Default]*/,'</td><td>',
               CASE WHEN C.is_identity = 1 THEN 'Identity' ELSE '' END /*AS [Identity]*/,'</td><td></td></tr>')
        FROM   sys.objects AS T
               JOIN sys.columns AS C ON T.object_id = C.object_id
               JOIN sys.types AS P ON C.system_type_id = P.system_type_id and c.user_type_id = p.user_type_id
               JOIN INFORMATION_SCHEMA.COLUMNS AS ISC ON T.name = ISC.TABLE_NAME AND C.name = ISC.COLUMN_NAME
        WHERE  T.type_desc = 'USER_TABLE'
          AND  T.name = @tableName
        ORDER BY T.name, ISC.ORDINAL_POSITION
        print '</table>'
        print '</br>'
        FETCH NEXT FROM tableCursor INTO @tableName
    
    END
    
    CLOSE tableCursor
    DEALLOCATE tableCursor
    SET NOCOUNT OFF
    PRINT '</body></html>'
    
  10. from https://stackoverflow.com/questions/7070053/convert-a-sql-query-result-table-to-an-html-table-for-email by cc-by-sa and MIT license