我试图编写简单的筛选功能,允许用户输入要筛选的列和值。困难的部分是动态选择要筛选的列。
我在网上找到了几个解决方案,但不确定要实施哪个。我更倾向于强调性能而非可维护性。如有任何意见,烦请指教。
假设我有一个名为“t”的表,它有5个VARCHAR列:“c1”,“c2”,“c3”,“c4”和“c5”。
解决方案1-简单方法
我可以使用动态SQL。类似以下内容:
DECLARE @sql VARCHAR(MAX) = 'SELECT * FROM t WHERE ' + @columnName + ' = ''' + @columnValue + ''';'
EXEC (@sql);
这大概意味着:
SELECT *
FROM t
WHERE c1 = 'asdf'
;
我不想使用这种解决方案,原因如下。我主要是将其作为一个简单的参考点,然后再深入探究。
- 它不能防止SQL注入。
- 即使我对columnValue进行参数化,每个列都会有5个不同的执行计划缓存,因为你无法对@columnName进行参数化。
解决方案2 - OR语句
可以使用一系列只有两个参数的OR语句。所以假设:
@columnName = 'c1'
@columnValue = 'asdf'
然后SQL将变为:
SELECT *
FROM t
WHERE (@columnName = 'c1' AND c1 = @columnValue)
OR (@columnName = 'c2' AND c2 = @columnValue)
OR (@columnName = 'c3' AND c3 = @columnValue)
OR (@columnName = 'c4' AND c4 = @columnValue)
OR (@columnName = 'c5' AND c5 = @columnValue)
OR (@columnName IS NULL AND 0 = 0)
;
在可能的情况下,我通常尽量避免使用OR。我记得在某个地方读到它存在性能问题,但我不是DBA,无法证实。你有什么想法吗?
解决方案3 - COALESCE
这种解决方案依赖于每列都有一个参数。因此,参数应该类似于:
@c1 = 'asdf';
@c2 = NULL;
@c3 = NULL;
@c4 = NULL;
@c5 = NULL;
SQL的意思是:
SELECT *
FROM t
WHERE c1 = COALESCE(@c1, c1)
AND c2 = COALESCE(@c2, c2)
AND c3 = COALESCE(@c3, c3)
AND c4 = COALESCE(@c4, c4)
AND c5 = COALESCE(@c5, c5)
;
有人对实现哪种方法有意见吗?我倾向于使用COALESCE,但是我没有具体的数据或经验。也许有更好的方法吗?
sys.columns
视图来验证列名。 - HABO