在sql查询中使用局部变量作为开关是不好的做法

时间:2016-02-23 21:30:58

标签: tsql user-defined-functions sql-server-2014

我在存储过程中有一个动态sql查询,我应该将其转换为表值函数(TVF)。 使用如下代码构建字符串:

 Declare @str = 'select * from tableName where table = ''words'''
 If @flag = 'ONE'
      set @str = @str + 'AND year_id = '+@year_id
 ELSE
 If @flag = 'TWO'
      set @str = @str + 'AND record_id = '+@record_id

 set @str = @str + 'order by year_id, record_id'
 exec (@str)

在TVF中,您无法运行insert语句,因此您无法将此exec查询的结果返回给用户(据我所知,至少可以随意纠正我)。

为了解决这个限制,我创建了一个过滤器,仅在局部变量具有给定值时才应用。

select * 
from tableName 
where table = 'words'
AND (
     (@flag = 'ONE' and year_id = @year_id)
    OR (@flag = 'TWO' and record_id = @record_id)
    )
Order by year_id, record_id

现在,看起来这对于更简单的查询是有效的,但是对于更复杂的查询,您需要为每个可能的动态sql字符串组合创建一个条件。

除了这个限制之外,以这种方式编写查询是否存在任何安全和/或性能风险?是否有更简单的方法为TVF编写这样的查询?

1 个答案:

答案 0 :(得分:1)

将动态SQL转换为ITVF的目的是消除这种废话。只需将ITVF写为

即可
create function schemaNme.funcName() returns table return
  select * from tableName where table = 'words';

让客户端直接添加任何所需的过滤条件:

select *
from schemaNme.funcName()  t
where t.year_id = @year_id;

这隐藏了数据如何从物理表组装成逻辑视图的细节,同时仍然允许客户端根据需要进行过滤。

从我在下面的补充评论中更新

ITVF是一个参数化视图,可能带有缓存的查询计划。与任何其他视图(或表格)一样,如果您希望动态修改访问机制,则必须使用动态SQL。但是,因为查询的内部已经在ITVF中为您封装了,所以在这种情况下,您可以简单地动态修改WHERE子句,这是一个稍微简单的任务