我需要在Store Procedure中的select语句中使用变量传递列名,但我不能使用动态查询

时间:2016-04-05 07:16:34

标签: sql sql-server database sql-server-2008

以下是我的SQL查询。我想从作为变量给出的列名中选择值。除了使用动态查询之外,有没有合适的方法呢?

SELECT EPV.EmployeeCode, @RateOfEmployee, @RateOfEmployer
FROM [HR_EmployeeProvisions] EPV

3 个答案:

答案 0 :(得分:5)

在不使用动态sql的情况下执行此操作的一种方法是使用CASE语句

但这很丑陋

SELECT EPV.EmployeeCode, case @RateOfEmployee  when 'RateOfEmployee' then RateOfEmployee
when 'X' then X 
..
end , case @RateOfEmployer  when 'RateOfEmployer' then RateOfEmployer
when 'Y' then Y
..
end 
FROM [HR_EmployeeProvisions] EPV

您必须检查CASE声明中的所有列。

答案 1 :(得分:5)

您无法在Sql server中参数化identifiers,我怀疑它是否可以在任何其他关系数据库中使用。

您最好的选择是使用动态Sql。

请注意,动态sql通常存在安全隐患,您必须为sql injection攻击保护您的代码。

我可能会这样做:

Declare @Sql nvarchar(500)
Declare numberOfColumns int;

select @numberOfColumns = count(1)
from information_schema.columns
where table_name = 'HR_EmployeeProvisions'
and column_name IN(@RateOfEmployee, @RateOfEmployer)

if @numberOfColumns = 2 begin

Select @Sql = 'SELECT EmployeeCode, '+ QUOTENAME(@RateOfEmployee) +' ,'+ QUOTENAME(@RateOfEmployer) +
'FROM HR_EmployeeProvisions'

exec(@Sql)
end

通过这种方式,您可以确保列名实际存在于表中,并使用QUOTENAME作为另一层安全。

注意:在您的表示层中,您应该处理由于列名无效而无法执行选择的选项。

答案 2 :(得分:3)

查看UNPIVOT子句 - 我不确定它是否适用于您的情况,但在某些情况下,它可用于通过列名查询值而无需动态SQL:

create table t1 (
  a int,
  b int,
  c int
);

insert into t1 values
(1, 11, 111),
(2, 22, 222),
(3, 33, 333);

select a, col_name, col_value from t1
unpivot (col_value for col_name in (b, c)) as dt;

结果:

| a | col_name | col_value |
|---|----------|-----------|
| 1 |        b |        11 |
| 1 |        c |       111 |
| 2 |        b |        22 |
| 2 |        c |       222 |
| 3 |        b |        33 |
| 3 |        c |       333 |

SQL Fiddle

如果您只需a中的值,具体取决于(动态)bc上的某些条件,您就可以构建该条件。如果您需要列bc中的值,则可以添加... WHERE col_name = ?。如果您需要更多列,则可能需要过滤未旋转表上的列值,而不是再次旋转它以将值返回到列中。