Konvertieren Sie eine SQL-Abfrageergebnistabelle in eine HTML-Tabelle für E-Mail

Lesezeit: 15 Minuten

Ich führe eine SQL-Abfrage aus, die eine Ergebnistabelle zurückgibt. Ich möchte die Tabelle in einer E-Mail mit dbo.sp_send_dbMail senden.

Gibt es in SQL eine einfache Möglichkeit, eine Tabelle in eine HTML-Tabelle umzuwandeln? Derzeit konstruiere ich es manuell mit COALESCE und füge die Ergebnisse in ein Varchar ein, das ich als emailBody verwende.

Gibt es einen besseren Weg, dies zu tun?

  • Vielleicht möchten Sie diese Antwort sehen. Ein XQuer FLWOR basierter Ansatz, der SELECT als Parameter mit Unterstützung für Header, CSS und Hyperlinks verwendet.

    – Schnugo

    9. Februar 18 um 22:08 Uhr

Konvertieren Sie eine SQL Abfrageergebnistabelle in eine HTML Tabelle fur E Mail
MgSam

Ich habe eine dynamische Prozedur erstellt, die jede zufällige Abfrage in eine HTML-Tabelle umwandelt, sodass Sie keine Spalten wie in den anderen Antworten fest codieren müssen.

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

Verwendung:

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="[email protected];",
    @subject="HTML email",
    @body = @html,
    @body_format="HTML",
    @query_no_truncate = 1,
    @attach_query_result_as_file = 0;

Verwandte: Hier ist ein ähnlicher Code, um eine beliebige Abfrage in eine CSV-Zeichenfolge umzuwandeln.

  • Das ist etwas, wonach ich gesucht habe und was ich schreiben wollte. Dies ist eine flexiblere Version dessen, was Sie normalerweise sehen. Ich habe bearbeitet, um die Zeile für die RealQuery zu reparieren, es ist wirklich eine Zeile, die, wenn jemand sie kopiert und einfügt, nicht so funktioniert, wie sie ist. Guter Code, sehr guter Code.

    – joel

    23. April 15 um 18:15 Uhr


  • Dies erzeugt keine Zellen für NULL Werte. Um dies zu beheben, ändern Sie ELEMENTS) zu ELEMENTS XSINIL). Die Nullzellen haben dann das Attribut xsi:nil="true", die möglicherweise durch ein spezielles Styling ersetzt werden könnten. Tolles Verfahren!

    – Nathan

    24. April 15 um 22:25 Uhr


  • Exzellent! Wenn Sie eine gespeicherte Prozedur ausführen möchten, können Sie außerdem die Ergebnisse Ihrer gespeicherten Prozedur in eine temporäre Tabelle einfügen und stattdessen aus dieser auswählen

    – Ben

    5. Mai 15 um 20:14 Uhr

  • Ausgezeichneter SP, das sollte die beste Antwort sein!

    – mdelafuq

    24. August 16 um 18:56 Uhr

  • Vielleicht bin ich nur dumm, aber ich verstehe nicht, wie ich diese Antwort umsetzen soll, selbst nachdem ich die Anweisungen gelesen habe. Sie ergeben für mich keinen Sinn. Ist das Rubin? Binde ich einfach die @query an die Abfragezeichenfolge und führe die Datei aus? Es wäre schön, eine idiotenfreundliche Anleitung zu haben.

    – John Curry

    19. Januar 18 um 22:16 Uhr

Konvertieren Sie eine SQL Abfrageergebnistabelle in eine HTML Tabelle fur E Mail
Justin Stolle

Hier ist eine Möglichkeit, dies aus einem Artikel mit dem Titel “Formatieren Sie die Abfrageausgabe in eine HTML-Tabelle – der einfache Weg [archive]“. Sie müssten die Details Ihrer eigenen Abfrage durch die in diesem Beispiel ersetzen, die eine Liste von Tabellen und eine Zeilenanzahl erhält.

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

Sobald du hast @bodykönnen Sie dann einen beliebigen E-Mail-Mechanismus verwenden.

  • Es ist immer sehr gefährlich zu erstellen XML auf Saitenbasis … Ihr ersetzt < und >aber es gibt noch viel mehr gefährliche Charaktere wie die &. Du kannst nachschauen [this answer] für einen anderen Ansatz.

    – Schnugo

    9. Februar 18 um 22:10 Uhr

  • Ich mag den Ansatz. Können Sie die Funktionalität hinzufügen, um bestimmten Zeilen eine Klasse hinzuzufügen (dh jede zweite Zeile, um eine andere CSS-Klasse zu haben)? Ich weiß, dass ich Ihre Lösung abstrahieren kann, um dynamisches SQL zu verwenden, obwohl dies den Zweck zunichte macht.

    – Eli

    13. März 19 um 16:54 Uhr

  • @Eli, in keiner Weise würde das als “hacky” angesehen werden, als dies bereits ist.

    – Justin Stolle

    14. März 19 um 20:53 Uhr

Das könnte Ihnen eine Vorstellung geben –

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="[email protected]", -- replace with your email address
@subject="E-mail in Tabular Format" ;


DROP TABLE #Temp

  • Interessanter Ansatz, obwohl ich nicht verstehe, warum Sie nach jedem Feld die zusätzliche Leerzeichenfolge haben. Können Sie bitte die Funktionalität / Notwendigkeit dieses Stücks erklären? Ein weiteres Stück, das ich brauche, konnte Ihre Lösung daher nicht verwenden, war das Hinzufügen einer Klasse zu bestimmten Zeilen (dh jede zweite Zeile, um eine andere CSS-Klasse zu haben).

    – Eli

    13. März 19 um 16:52 Uhr

  • @Eli Ich würde vermuten, dass MS SQL XML gleichnamige Felder zu einem kombiniert. Ein Leerzeichen oder ein Nullwert ohne Namen wird nicht serialisiert und getrennt td Werte in ihre eigenen Spalten und nicht in eine Verkettung.

    – Zachary Scott

    28. Dezember 2020 um 22:36 Uhr

Hier unten mein häufig verwendetes Skript. Ich verwende dies, um Skripte auf zwei Tabellen/Ansichten mit einem SQL-Job auszuführen und die Ergebnisse als zwei HTML-Tabellen per E-Mail zu senden. Natürlich sollten Sie ein E-Mail-Profil erstellen, bevor Sie dies ausführen.

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="<[email protected]>",
    @from_address = @mailfrom,
    @reply_to = '<[email protected]>',
    @subject = @subject,
    @body = @mailbody,
    @body_format="HTML"
--   ,@importance="HIGH"
END

basierend auf JustinStolle-Code (danke), wollte ich eine Lösung, die generisch sein könnte, ohne die Spaltennamen angeben zu müssen.

Dieses Beispiel verwendet die Daten einer temporären Tabelle, kann aber natürlich nach Bedarf angepasst werden.

Hier ist, was ich bekommen habe:

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

1643912526 977 Konvertieren Sie eine SQL Abfrageergebnistabelle in eine HTML Tabelle fur E Mail
FA LE TI NR

Angenommen, jemand hat sich hierher verirrt und versteht die Verwendung der markierten Antwort-SQL nicht, bitte lesen Sie meine … es ist bearbeitet und funktioniert. Tabelle:Personal, Spalten:Personalname,PersonalTelefon und PersonalGeburtstag

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

Konvertieren Sie eine SQL Abfrageergebnistabelle in eine HTML Tabelle fur E Mail
Sandeep

Ich habe versucht, mehrere Tabellen mit dem obigen Mahesh-Beispiel zu drucken. Veröffentlichung zur Bequemlichkeit anderer

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="[email protected]", 
                              @FromEmailAddress="[email protected]" 


EXEC msdb.dbo.sp_send_dbmail
@profile_name="MY POROFILE", -- replace with your SQL Database Mail Profile 
@body = @BODY,
@body_format="HTML",
@recipients="[email protected]", -- replace with your email address
@subject="District,Department & CostCenter Discrepancies" ;

.

758590cookie-checkKonvertieren Sie eine SQL-Abfrageergebnistabelle in eine HTML-Tabelle für E-Mail

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy