T-SQL 语句打印带有对齐数据的全表

问题描述 投票:0回答:1

对于上下文,我正在尝试创建一封电子邮件,用户可以在其中以表格形式查看查询的数据。我希望数据(每列)在每行的相同位置对齐(因此是一个表格)。每列中的数据长度可能不同。现在,我专注于发送电子邮件。我专注于简化文本对齐和/或表查询。如果您想添加有关发送数据库电子邮件的信息,请随意;我还没有移动到那部分。

编辑:我使用循环,因为每个解决方案都分配了一个用户。每个解决方案可以有不同的用户。该项目的目标是向每个用户发送一封电子邮件,仅列出该用户的解决方案。 (我对可以更改的内容的发言权有限。)电子邮件是基于到期日期的时间触发事件。

打印时,我将其格式化为打印:

解决方案:1234-12-1 |状态 ID:1 |到期时间:2024 年 1 月 1 日
解决方案:1234-12-2 |状态 ID:12 |到期时间:2024 年 1 月 1 日
解决方案:56789-1 |状态 ID:1 |到期时间:2024 年 1 月 1 日
解决方案:56789-2-22 |状态 ID:1 |到期时间:2024 年 1 月 1 日
解决方案:987-654,一个|状态 ID:12 |到期时间:2024 年 1 月 1 日

我的基本目标是:(越好越好,但它有效)。

解决方案 |状态 ID |到期日
'------------------------------------------------
1234-12-1 | 1a | 2024年1月1日
1234-12-2 | 12b | 12b 2024年1月1日
56789-1 | 1a | 2024年1月1日
56789-2-22 | 1a | 2024年1月1日
987-654,一个| 12b | 12b 2024年1月1日

我正在使用 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-server t-sql string-formatting text-alignment
1个回答
1
投票

根据我收到的多条评论,避免使用 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
© www.soinside.com 2019 - 2024. All rights reserved.