将SQL查询结果表转换为电子邮件的HTML表
我正在运行一个返回结果表的SQL查询。我想使用dbo.sp_send_dbMail通过电子邮件发送表 在SQL中是否有一种直接的方法将表转换为HTML表?目前,我正在使用COALESCE手动构建它,并将结果放入一个varchar中,用作emailBody将SQL查询结果表转换为电子邮件的HTML表,html,sql,sp-send-dbmail,Html,Sql,Sp Send Dbmail,我正在运行一个返回结果表的SQL查询。我想使用dbo.sp_send_dbMail通过电子邮件发送表 在SQL中是否有一种直接的方法将表转换为HTML表?目前,我正在使用COALESCE手动构建它,并将结果放入一个varchar中,用作emailBody 有没有更好的方法可以做到这一点?下面是一篇题为。您需要将自己查询的详细信息替换为本示例中的查询,该示例将获取表列表和行计数 declare @body varchar(max) set @body = cast( ( select td =
有没有更好的方法可以做到这一点?下面是一篇题为。您需要将自己查询的详细信息替换为本示例中的查询,该示例将获取表列表和行计数
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, '<', '<' ), '>', '>' )
+ '</table>'
print @body
一旦你有了@body,你就可以使用任何你想要的电子邮件机制。这可能会给你一些想法-
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
我做了一个动态过程,它将任何随机查询转换为HTML表,因此您不必像其他响应中那样硬编码列
-- 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
相关:这里有一个类似的代码,可以将任意查询转换为基于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>'
假设有人在这里找到了路,但不理解标记答案SQL的用法,请阅读我的。。。它是经过编辑和工作的。表:员工,列:员工姓名、员工电话和员工身份
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, '<', '<' ), '>', '>' )
+ '<table>'
print @body
我尝试使用上面的Mahesh示例打印多个表。为方便他人而张贴
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' ;
所有其他答案都使用变量和集合运算。下面是一种在select语句中执行此操作的方法。只需将其作为列放入现有的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, '<', '<' ), '>', '>' )
+ '</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
下面是我常用的脚本。我使用它在SQL作业的两个表/视图上运行脚本,并通过邮件将结果作为两个HTML表发送。当然,您应该在运行此操作之前创建邮件配置文件
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
在下面的代码段中,我准备为文档生成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>'
他用另一种方式回答。请注意:
print语句可能会将字符串截断为4000个字符,但例如,我的测试字符串的长度为9520个字符。
[tr/th]表示层次结构,例如。。。。
[@name]将字段添加为XML属性。
MS SQL XML连接相同名称的字段,因此字段之间的null可防止出现这种情况。
这是我一直在寻找和计划写的东西。这是您通常看到的更灵活的版本。我编辑以修复RealQuery的这一行,如果有人复制和粘贴它,这一行将无法正常工作。好的代码,非常好的代码。这不会为空值生成单元格。要解决此问题,请将元素更改为元素xsini。空单元格将具有属性xsi:nil=true,该属性可能会被特殊样式所替代。伟大的程序!杰出的此外,如果要运行存储过程,可以将存储过程结果插入到临时表中,并从该表中选择,这应该是最好的答案!也许我只是愚蠢,但即使在阅读了说明之后,我也不明白如何实现这个答案。它们对我来说毫无意义。这是红宝石吗?我是否将@query绑定到查询字符串并运行该文件?如果有一些对白痴友好的说明就好了。你可能想看看。一种基于XQuer FLWOR的方法,使用SELECT作为参数,支持标题、CSS和超链接。在字符串基础上创建XML总是非常危险的。。。您的角色正在替换,但还有许多更危险的角色,如&。你可以检查[这个答案]以找到另一种方法。我喜欢这种方法。您是否能够添加将类添加到特定行的功能,即每隔一行添加一个CSS类?我知道我可以将您的解决方案抽象为使用动态SQL,尽管这有点违背了目的。@Eli,无论如何,这都不会被认为比现在更“黑客化”。有趣的方法,尽管我不明白为什么在每个字段后都有额外的空字符串;你能解释一下那件衣服的功能/需要吗?因此,我需要的另一件事是无法使用您的解决方案,即在某些行中添加一个类,即每隔一行添加一个CSS类。@Eli我猜MS SQL XML将类似命名字段的字段组合为一个。没有名称的空白或空值将不会序列化,将td值分隔到它们自己的列中,而不是串联。
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>'
declare @body nvarchar(max)
select @body = cast((
select N'2' [@cellpadding], N'2' [@cellspacing], N'1' [@border],
N'Database Table' [tr/th], null [tr/td],
N'Entity Count' [tr/th], null [tr/td],
N'Total Rows' [tr/th], null,
(select object_name( object_id ) [td], null,
count( distinct name ) [td], null,
count( * ) [td], null
from sys.columns
group by object_name( object_id )
for xml path('tr'), type)
for xml path('table'), type
) as nvarchar(max))
print @body -- only shows up to 4000 characters depending