2011-08-15 30 views
21

Tôi đang chạy truy vấn SQL trả về một bảng kết quả. Tôi muốn gửi bảng trong một email bằng cách sử dụng dbo.sp_send_dbMail.Chuyển đổi bảng kết quả truy vấn SQL thành bảng HTML cho email

Có cách nào đơn giản trong SQL để biến bảng thành bảng HTML không? Hiện tại, tôi đang xây dựng nó bằng cách sử dụng COALESCE và đưa kết quả vào một varchar mà tôi sử dụng làm emailBody.

Có cách nào tốt hơn để thực hiện việc này không?

+0

Bạn có thể muốn xem [câu trả lời này] (https://stackoverflow.com/a/39487565/5089204). Phương thức dựa trên 'XQuer FLWOR' lấy tham số SELECT làm tham số với sự hỗ trợ cho header, CSS và hyper-links. – Shnugo

Trả lời

13

Đây là một cách để làm điều đó từ một bài viết có tiêu đề "Format query output into an HTML table - the easy way". Bạn sẽ cần phải thay thế các chi tiết của truy vấn của riêng bạn cho những người trong ví dụ này, trong đó có một danh sách các bảng và một số hàng.

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 

Khi bạn có @body, bạn có thể sử dụng bất kỳ cơ chế email nào bạn muốn.

+0

Luôn luôn rất nguy hiểm khi tạo 'XML' trên cơ sở chuỗi ... Bạn đang thay thế '<' and '>', nhưng có nhiều ký tự nguy hiểm hơn như '&'. Bạn có thể kiểm tra [câu trả lời này] để biết cách tiếp cận khác. – Shnugo

11

này có thể cung cấp cho bạn một số ý tưởng -

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 
46

tôi đã thực hiện một proc động mà biến bất kỳ truy vấn ngẫu nhiên vào một bảng HTML, vì vậy bạn không cần phải hardcode cột như trong các câu trả lời khác.

-- 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'', @[email protected] 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', @[email protected] OUTPUT 
END 
GO 

Cách sử dụng:

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; 

liên quan: Đây là mã tương tự để biến bất kỳ truy vấn tùy ý vào một CSV string.

+0

Đây là điều tôi đã tìm kiếm và đã có kế hoạch viết. Đây là phiên bản linh hoạt hơn của những gì bạn thường thấy.Tôi đã chỉnh sửa để sửa dòng cho RealQuery thực sự là một dòng mà nếu ai đó sao chép và dán sẽ không hoạt động như vậy. Tốt mã, Rất tốt mã. – joel

+1

Điều này không tạo ra các ô cho giá trị 'NULL'. Để sửa lỗi này, thay đổi 'ELEMENTS)' thành 'ELEMENTS XSINIL)'. Các ô trống sẽ có thuộc tính 'xsi: nil =" true "', có thể được thay thế bằng kiểu dáng đặc biệt. Thủ tục tuyệt vời! – Nathan

+1

Tuyệt vời! Ngoài ra, nếu bạn muốn chạy một thủ tục được lưu trữ, bạn có thể chèn kết quả thủ tục lưu trữ của bạn vào một bảng tạm thời và chọn từ đó thay vì – Ben

0

dựa trên mã JustinStolle (cảm ơn bạn), tôi muốn một giải pháp có thể chung chung mà không phải chỉ định tên cột.

Mẫu này đang sử dụng dữ liệu của bảng tạm thời nhưng tất nhiên, mẫu có thể được điều chỉnh theo yêu cầu.

Đây là những gì tôi nhận:

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

Giả sử ai đó tìm thấy con đường của mình ở đây và không hiểu việc sử dụng câu trả lời SQL rõ rệt, vui lòng đọc tôi ... nó được thay đổi nội dung và các công trình. Bảng: nhân viên, cột: tên nhân viên, nhân viên và nhân viênDOB

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 
0

Tôi đã thử in Nhiều bảng bằng Mahesh Ví dụ trên. Đăng để thuận tiện cho những người khác

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 [email protected]+ '<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' ; 
0

Tất cả các câu trả lời khác sử dụng biến và hoạt động SET. Đây là một cách để làm điều đó trong một tuyên bố chọn. Chỉ cần thả cột này vào làm cột trong lựa chọn hiện có của bạn.

(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 
Các vấn đề liên quan