如何构建根据特定条件而变化的动态SQL表达式

时间:2019-02-22 22:21:27

标签: sql sql-server tsql

我需要构建一个查询,以选择根据某些条件而有所不同的表达式

DECLARE @program NVARCHAR(22) = 'test';
DECLARE @result NVARCHAR(10);
DECLARE @currency_results NVARCHAR(200) = '';
DECLARE @sql NVARCHAR(MAX)

--where program = @program ) and currncy = 'T';
DECLARE results CURSOR FAST_FORWARD FOR
    SELECT result 
    FROM calcresult 
    WHERE calcfile = (SELECT calc_file 
                      FROM program 
                      WHERE program = @program)
     AND currncy = 'T';

OPEN results;
FETCH NEXT FROM results INTO @result;

WHILE @@FETCH_STATUS = 0 
BEGIN
    SET @currency_results = @currency_results + '+' + @result ;
    PRINT @currency_results

    FETCH NEXT FROM results INTO @result
END

PRINT @currency_results

CLOSE results;
DEALLOCATE results;

SET @sql = 'SELECT ' + @currency_results + ' FROM tphase WHERE program = @program';

EXEC (@sql);

初始化@currency_results解决了最后一个问题。但是,现在我遇到了某种范围错误:

  

第1级第15行第2行137消息
  必须声明标量变量“ @program”

1 个答案:

答案 0 :(得分:0)

您已在构建SQL字符串的外部过程代码中声明了@program,但这并不意味着它在执行SQL时创建的作用域中可用。将@prgram声明放入您构建的sql字符串(您执行的那个)中

SET @sql = 'declare @program nvarchar(10) = ''' + @program + '''; 
select ' + @currency_results + ' from tphase where program = @program';

或者抛弃它,然后将任何值放在程序中的字符串sql中:

SET @sql = 'select ' + @currency_results + ' from tphase where program = ''' + @program + '''';

如果用户提供@program的值,请注意是否进行了sql注入-使用适当的方法来防止它注入-有关如何使用sp_executesql来运行参数化动态sql的信息,请参见https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql?view=sql-server-2017。它可能看起来像这样:

SET @sql = 'select ' + @currency_results + ' from tphase where program = @prog';
sp_executesql @sql, '@prog nvarchar(10)', @prog = @program;

我特意将其称为@prog和@program,以更清楚地显示变量“活动”的位置(prog仅存在于对sp_executesql的调用中,而程序仅存在于其外部)

附带说明,如果您不希望使用null值来使整个字符串为空,则使用CONCAT函数来连接字符串更为有用:

'A' + null + 'b' -- result: null string
CONCAT('A', null, 'b') -- result: Ab