提问人:Star Galaxy 提问时间:10/25/2023 最后编辑:Star Galaxy 更新时间:11/7/2023 访问量:76
T-SQL 语句打印包含对齐数据的完整表
T-SQL statement to Print full table with aligned data
问:
对于上下文,我正在尝试创建一封电子邮件,用户可以在其中以表格形式查看查询的数据。我希望数据(来自每列)在每行(因此,一个表)的相同位置对齐。每列中的数据长度可以不同。现在,我不专注于发送电子邮件。我专注于简化文本对齐和/或表格查询。如果您想添加有关发送数据库电子邮件的信息,请随意;我还没有转到那部分。
编辑:我正在使用循环,因为每个解决方案都分配了一个用户。每个解决方案可以有不同的用户。项目目标是向每个用户发送一封电子邮件,其中仅列出该用户的解决方案。(对于可以改变什么,我的发言权有限。电子邮件是基于到期日期的时间触发事件。
打印时,我将其格式化为打印为:
Solution: 1234-12-1 | Status ID: 1 | Expires: 01-01-2024 Solution: 1234-12-2 | Status ID: 12 | Expires: 01-01-2024 Solution: 56789-1 | Status ID: 1 | Expires: 01-01-2024 Solution: 56789-2-22 | Status ID: 1 | Expires: 01-01-2024 Solution: 987-654, a | Status ID: 12 | Expires: 01-01-2024
我的基本目标是:(越好越好,但它有效)。
Solution | Status ID | Expiration '----------------------------------- 1234-12-1 | 1a | 1-1-2024 1234-12-2 | 12b | 01-01-2024 56789-1 | 1a | 01-01-2024 56789-2-22 | 1a | 01-01-2024 987-654, a | 12b | 01-01-2024
我正在使用 Microsoft SSMS 2019、SQL Server 2019 和 Transact-SQL。这是我当前的代码,被精简到最低限度。我当前的代码工作正常,但没有达到我想要的目标。(它目前尚未设置为发送电子邮件,但我想在进行下一步之前获得正确的打印/显示格式。
DECLARE @_MaxTemp INT;
DECLARE @_Current INT = 1;
DECLARE @_SolutionName nvarchar(30);
DECLARE @_ExpirationDate nvarchar(20);
DECLARE @_StatusID nvarchar(5);
SELECT
IDENTITY(int,1,1) as TempID
,s.[Name] as SolutionName
,s.[StatusID] as StatusID
,n.[ExpirationDate] as ExpirationDate
INTO #temp
FROM [dbo].[Solution] AS s
INNER JOIN [dbo].[Notifications] AS n
ON s.[ID] = n.SolutionID
SET @_MaxTemp = (SELECT COUNT(TempID) FROM #Temp)
WHILE @_Current < @_MaxTemp
BEGIN
SET @_SolutionName = (SELECT SolutionName FROM #temp WHERE TempID = @_Current);
SET @_StatusID = (SELECT StatusID FROM #temp WHERE TempID = @_Current)
SET @_ExpirationDate = CAST((SELECT ExpirationDate FROM #TEMP WHERE TempID = @_Current) AS nvarchar(25));
SET @_
PRINT FORMATMESSAGE('Solution: %s | Status ID: %s | Expires: 01-01-2024', @_SolutionName, @_StatusID, @_ExpirationDate);
SET @_Current += 1;
END
DROP TABLE IF EXISTS #temp`
我没有循环,而是在下面尝试了一些简单的东西。毫不奇怪,它没有奏效。(“在这种情况下,不允许使用子查询。只允许使用标量表达式。
print (Select * from #temp)
我意识到我可以查询字符数,设置所需的长度,对其进行数学运算,并添加所需的空格来对齐它。但是,我需要对每个单元格重复此操作(将提取更多列,但示例不需要)。作为初学者,我的代码将变成意大利面条代码。
我尝试查看其他 stackoverflow 帖子,但它通常是关于拉取特定单元格/行、查询表描述或问题标题与问题上下文不匹配。它有 10 年的历史中的一些是改进/新方法尚不存在的,这无济于事。当我搜索 Microsoft 文档时,它是关于一般的打印语句、提取特定单元格/行或表格列表(而不是内容)。在一般搜索中,我遇到了类似的搜索问题。
答:
根据我收到的多条评论,避免使用 SQL“打印”来创建干净的格式化表。若要在 SSMS 外部向用户显示数据,请使用 HTML 和/或 XML 将数据格式化为所需的布局。
经过搜索,我发现一些网站提供了使用 SQL Server 生成 HTML/XML 的指导。
在评论中,Yitzhak Khabinsky 指出了另一个 StackOverflow 链接,该链接介绍了如何使用 XML 格式化 SQL 结果:
为了在 SQL Server 中发送电子邮件,Microsoft 提供了一些涵盖 SQL 数据库电子邮件的培训/文档:
编辑:我现在已经重构了代码。由于隐私原因,它已被简化,但仍然提供了一个答案。如建议,现在使用 HTML 格式和光标/获取。但是,由于管理决策,仍使用 SQL dbmail (SSMS)。
DECLARE @Solution nvarchar(10);
DECLARE @StatusID int;
DECLARE @ExpirationDate date;
DECLARE @HTML_file nvarchar(2000);
CREATE TABLE #temp (Solution nvarchar(10), StatusID int, ExpirationDate Date)
DECLARE message_cursor CURSOR LOCAL SCROLL FOR
SELECT
[Solution],
[StatusID],
[ExpirationDate]
FROM dbo.TableName
OPEN message_cursor
FETCH NEXT FROM message_cursor INTO @Solution, @StatusID, @ExpirationDate
WHILE @@FETCH_STATUS = 0
BEGIN
IF @StatusID = 1 --solution in-use
BEGIN
INSERT INTO #temp
VALUES
(@Solution,
@StatusID,
@ExpirationDate)
END
If @StatusID = 5 --solution disposed
BEGIN
--create HTML file to send out
SET @HTML_file = CONCAT(
N'<body>
<table style="border-collapse: collapse;border: 1px solid gray;">
<tr>
<th>Solution</th>
<th>Project #</th>
<th>Expiration Date</th>
</tr>'
,CAST ((SELECT
td = Solution, ''
,td = StatusID, ''
,td = ExpirationDate, ''
FROM #temp FOR XML PATH('tr'), type) AS nvarchar(MAX))
,'</table></body>')
--executes email to user
EXEC msdb.dbo.sp_send_dbmail
@profile_Name = 'profilename'
,@recipients = '[email protected]'
,@subject = 'Put your email title here'
,@body = @HTML_file
,@body_format = 'HTML';
DELETE FROM #temp
END
FETCH NEXT FROM email_cursor INTO @Solution, @StatusID,
@ExpirationDate
END
DROP TABLE #temp
CLOSE email_cursor
DEALLOCATE email_cursor
评论