Reputation: 3111
I've inherited a stored proc and I need to add and assign a new variable. The piece of the code that's relevant is:
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>';
As you can see, it's a complicated query. @tableRows is used later on to create the body of an email. Now, I need to get s.sched_desc (see line 7 of SELECT statement) and assign it to a second variable, so that I can use it in the Subject line of the same email. I've tried adding
+ (SELECT @sched_desc = SELECT [sched_desc])
to the bottom of the SELECT statement but it's no good (incorrect syntax near parenthesis). I've also tried
+ '<td>' + (SELECT @sched_desc = CAST(s.[sched_desc] AS VARCHAR(100))) + '</td>'
but again it's expecting another parenthesis. I know I can do this by turning this whole thing into a string and then executing it with sp_executesql (see this example) but I'd prefer to avoid dynamic sql if possible. On the other hand, I really don't want to execute this query twice. Is there another way to get around this?
Upvotes: 0
Views: 193
Reputation: 725
Your stated task would be more easily accomplished and supported by employing a templating language and some basic string interpolation.
It is not possible to set a variable value within the process of setting another variable's value, but you can do so within the same SELECT
.
In your query, add a comma after the closing quote and then set your @sched_desc variable:
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]
...
The second variable assignment has access to the same data as the original query, but it will need to be included in whatever selecting process is used to retrieve the value of @tableRows.
As an additional note, I will strongly advise you to identify alternatives to using NOLOCK
- here are some links to get you started on that path:
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/
Upvotes: 2
Reputation: 10024
Paneerakbari is correct that you can assign (and build up) more than one variable in the select. Here is a simplified example that may make things clearer.
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
Result:
@Subject = 'More'
@TableRows = '<table><tr><td>This stuff</td></tr><tr><td>That stuff</td></tr><tr><td>More stuff</td></tr></table>'
For readability and maintainability, I often find it useful to move complex intermediate calculations into a CROSS APPLY block, the results of which can then be referenced in the final 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
Upvotes: 2