T-SQL如何在另一个变量赋值里面给一个变量赋值

T-SQL how to assign a variable inside another variable assignment

我继承了一个存储过程,我需要添加并分配一个新变量。相关的代码片段是:

DECLARE @tableRows VARCHAR(MAX) = '';
    SET @tableRows
        = N'<tr>
<bgcolor="#6081A0" style="FONT-FAMILY:arial,san-serif;FONT-WEIGHT:normal;color:#6081A0">  :: Resource Scheduler</tr>'
  + N'<tr>
Date: ' + CAST(CONVERT(NVARCHAR, DATENAME(WEEKDAY, @rpt_start_date)) AS VARCHAR(100)) + ' '
          + CAST(CONVERT(NVARCHAR, CAST(@rpt_start_date AS DATE), 100) AS VARCHAR(100)) + '</tr>'
          + '<table border="1" width="100%">'
          + '<tr bgcolor="#DC5E3F" style="FONT-FAMILY:arial,san-serif;FONT-WEIGHT:bold;color:white">'
          + '<td style="text-align:center;vertical-align:middle">START TIME</td>' 
  + '<td style="text-align:center;vertical-align:middle">END TIME</td>'
  + '<td style="text-align:center;vertical-align:middle">ROOM</td>' 
  + '<td>MEETING TITLE</td>' 
  + '<td style="text-align:center;vertical-align:middle">ATTENDEES</td>'
          + '<td>INVITEE' + CHAR(39) + 'S NAME</td><td>HOSTS NAMES</td>'
  + '<td>FOOD SERVICES REQUESTS</td>'
  + '<td>TECHNOLOGY REQUESTS</td>'
  + '<td>OFFICE SERVICES REQUESTS</td></tr>';

    SELECT @tableRows
        = @tableRows + '<tr ' + 'bgcolor=' +
  + IIF(ROW_NUMBER() OVER (ORDER BY s.[sched_id] DESC) % 2 = 0, '"lightgrey', '"white') + '">' 
  + '<td style="text-align:center;vertical-align:middle">' + CAST(CONVERT(NVARCHAR, CAST(srd.[mtg_start_date_local] AS TIME), 100) AS VARCHAR(100)) + '</td>' 
  + '<td style="text-align:center;vertical-align:middle">' + CAST(CONVERT(NVARCHAR, CAST(srd.[mtg_end_date_local] AS TIME), 100) AS VARCHAR(100)) + '</td>' 
  + '<td style="text-align:center;vertical-align:middle">' + CAST(r.[res_hdr] AS VARCHAR(100)) + '</td>' 
  + '<td>' + CAST(s.[sched_desc] AS VARCHAR(100)) + '</td>' 
  + '<td style="text-align:center;vertical-align:middle">' + CAST(s.[num_attendees] AS VARCHAR(100)) + '</td>' 
  + '<td>' + CAST(ru.[user_name] AS VARCHAR(100)) + '</td>'
  + '<td>' + CAST(hu.[user_name] AS VARCHAR(100)) + '</td>'
  + '<td>' + CAST(dbo.ufn_rsConcatCustomTabServices(@rs_customtab_food,s.[sched_id]) AS VARCHAR(4000)) + '</td>'
          + '<td>' + CAST(dbo.ufn_rsConcatCustomTabServices(@rs_customtab_tech,s.[sched_id]) AS VARCHAR(4000)) + '</td>'
  + '<td>' + CAST(dbo.ufn_rsConcatCustomTabServices(@rs_customtab_os,s.[sched_id]) AS VARCHAR(4000)) + '</td></tr>'
    FROM
            tbl_sched           s WITH (NOLOCK)
        INNER JOIN
            tbl_sched_res_date  srd WITH (NOLOCK)
                ON s.[sched_id] = srd.[sched_id]
        INNER JOIN
            tbl_sched_request  sr WITH (NOLOCK)
                ON s.[sched_id] = sr.[sched_id]
        INNER JOIN
            tbl_user            ru WITH (NOLOCK)
                ON sr.[req_for_user_id] = ru.[user_id]
        INNER JOIN
            tbl_user            hu WITH (NOLOCK)
                ON s.create_by = hu.[user_id]
        INNER JOIN
            tbl_res             r WITH (NOLOCK)
                ON srd.[res_id] = r.[res_id]
        INNER JOIN
            tbl_grp             g WITH (NOLOCK)
                ON r.[grp_id] = g.[grp_id]
        INNER JOIN
            tbl_loc             l WITH (NOLOCK)
                ON g.[loc_id] = l.[loc_id]
        INNER JOIN
            tbl_region          rg WITH (NOLOCK)
                ON l.[region_id] = rg.[region_id]
        LEFT OUTER JOIN -- changed from inner join 
            tbl_sched_udf_val   suv_f WITH (NOLOCK)
                ON suv_f.[sched_id] = s.[sched_id]
AND suv_f.[udf_id] =
   (
   SELECT
   u.[udf_id]
   FROM
   tbl_udf u WITH (NOLOCK)
   WHERE
   u.[udf_desc] LIKE @rs_customtab_food

   )
AND suv_f.[string_value] IS NOT NULL
AND suv_f.[string_value] = 'Yes'
        LEFT OUTER JOIN -- changed from inner join 
            tbl_sched_udf_val   suv_t WITH (NOLOCK)
                ON suv_t.[sched_id] = s.[sched_id]
AND suv_t.[udf_id] =
   (
   SELECT
   u.[udf_id]
   FROM
   tbl_udf u WITH (NOLOCK)
   WHERE
   u.[udf_desc] LIKE @rs_customtab_tech

   )
AND suv_t.[string_value] IS NOT NULL
AND suv_t.[string_value] = 'Yes'
        LEFT OUTER JOIN -- changed from inner join 
            tbl_sched_udf_val   suv_o WITH (NOLOCK)
                ON suv_o.[sched_id] = s.[sched_id]
AND suv_o.[udf_id] =
   (
   SELECT
   u.[udf_id]
   FROM
   tbl_udf u WITH (NOLOCK)
   WHERE
   u.[udf_desc] LIKE @rs_customtab_os

   )
AND suv_o.[string_value] IS NOT NULL
AND suv_o.[string_value] = 'Yes'
        LEFT OUTER JOIN
            tbl_sched_res_setup srs WITH (NOLOCK)
                ON (
                       s.[sched_id] = srs.[sched_id]
                       AND srd.[res_id] = srs.[res_id]
                   )
        LEFT OUTER JOIN
            tbl_setup           su WITH (NOLOCK)
                ON (srs.[setup_id] = su.[setup_id])
    WHERE
            l.[loc_id] = 13-- 1177 Sixth Ave ( ONLY )
            AND s.[deleted_flag] = 0
            AND r.[obsolete_flag] = 0
            AND g.[obsolete_flag] = 0
            AND l.[obsolete_flag] = 0
            AND rg.[obsolete_flag] = 0
            AND srd.[busy_start_date_local] >= CONVERT(NVARCHAR(20), @rpt_start_date, 112)
            AND srd.[busy_start_date_local] < CONVERT(NVARCHAR(20), @rpt_end_date, 112)
    ORDER BY
            srd.[mtg_start_date_local],
            r.[res_hdr];

SELECT @tableRows = @tableRows + '</table>';

如您所见,这是一个复杂的查询。 @tableRows 稍后用于创建电子邮件的正文。现在,我需要获取 s.sched_desc(参见 SELECT 语句的第 7 行)并将其分配给第二个变量,以便我可以在同一封电子邮件的主题行中使用它。我试过添加

+ (SELECT @sched_desc = SELECT [sched_desc])

到 SELECT 语句的底部,但这并不好(括号附近的语法不正确)。我也试过

 + '<td>' + (SELECT @sched_desc = CAST(s.[sched_desc] AS VARCHAR(100))) + '</td>'

但它又期待另一个括号。我知道我可以通过将整个事情变成一个字符串然后用 sp_executesql 执行它(参见 )来做到这一点,但如果可能的话我宁愿避免动态 sql。另一方面,我真的不想两次执行这个查询。还有其他方法可以解决这个问题吗?

使用模板语言和一些基本的字符串插值可以更轻松地完成和支持您规定的任务。

无法在设置另一个变量值的过程中设置变量值,但您可以在相同的过程中这样做SELECT

在您的查询中,在结束引号后添加一个逗号,然后设置您的@sched_desc 变量:

SELECT @tableRows = @tableRows + '<tr ' + 'bgcolor=' ... </td></tr>',
       @sched_desc = [sched_desc]
  FROM tbl_sched s WITH (NOLOCK)
 INNER JOIN tbl_sched_res_date  srd WITH (NOLOCK)
    ON s.[sched_id] = srd.[sched_id]
 ...

第二个变量赋值可以访问与原始查询相同的数据,但它需要包含在用于检索@tableRows 值的任何选择过程中。

作为附加说明,我强烈建议您确定使用 NOLOCK 的替代方法 - 这里有一些链接可以帮助您开始这条路:

https://www.brentozar.com/archive/2021/11/nolock-is-bad-and-you-probably-shouldnt-use-it/

https://www.brentozar.com/archive/2018/10/using-nolock-heres-how-youll-get-the-wrong-query-results/

https://www.brentozar.com/archive/2016/12/nolock-ever-right-choice/

https://www.brentozar.com/archive/2021/01/but-surely-nolock-is-okay-if-no-ones-changing-data-right/

Paneerakbari 是正确的,您可以在 select 中分配(和构建)多个变量。这是一个简化的示例,可以使事情更清楚。

DECLARE @TableRows VARCHAR(MAX) = '<table>'
DECLARE @Subject VARCHAR(MAX) = '' -- Only the last value is retained here

SELECT
    @TableRows = @TableRows + '<tr><td>' + A.Info + '</td></tr>',
    @Subject = A.Title
FROM (
    VALUES
        (1, 'This', 'This stuff'),
        (2, 'That', 'That stuff'),
        (3, 'More', 'More stuff')
) A(ID, Title, Info)
ORDER BY A.ID

SET @TableRows = @TableRows + '</table>'

SELECT @Subject, @TableRows

结果:

@Subject = 'More'
@TableRows = '<table><tr><td>This stuff</td></tr><tr><td>That stuff</td></tr><tr><td>More stuff</td></tr></table>'

为了可读性和可维护性,我经常发现将复杂的中间计算移动到 CROSS APPLY 块中很有用,然后可以在最终 select.

中引用其结果
DECLARE @TableRows VARCHAR(MAX) = '<table>'
DECLARE @Subject VARCHAR(MAX) = '' -- Only the last value is retained here

SELECT
    @TableRows = @TableRows + R.ComplexRowConstruction,
    @Subject = A.Title
FROM (
    VALUES
        (1, 'This', 'This stuff'),
        (2, 'That', 'That stuff'),
        (3, 'More', 'More stuff')
) A(ID, Title, Info)
CROSS APPLY (
    SELECT ComplexRowConstruction =
        '<tr>'
        + '<td>' + A.Info + '</td>'
        + '</tr>'
) R
ORDER BY A.ID

SET @TableRows = @TableRows + '</table>'

SELECT @Subject, @TableRows