SQL:选择要从存储过程返回的不同列
假设我有一个包含多个列的表SQL:选择要从存储过程返回的不同列,sql,sql-server,stored-procedures,dynamic-columns,Sql,Sql Server,Stored Procedures,Dynamic Columns,假设我有一个包含多个列的表mytable(这不完全正确,请参见编辑): 我创建了一个从该表返回数据的存储过程。问题是,有时我需要它只返回id和data列,有时我需要其他信息,如description,created\u at等 我的想法是创建三个虚拟变量@display\u description,@display\u created\u date,@display\u view\u times。当一个伪变量等于1时,我显示相应的列。例如,对于命令 exec my_procedure @disp
mytable
(这不完全正确,请参见编辑):
我创建了一个从该表返回数据的存储过程。问题是,有时我需要它只返回id
和data
列,有时我需要其他信息,如description
,created\u at
等
我的想法是创建三个虚拟变量@display\u description
,@display\u created\u date
,@display\u view\u times
。当一个伪变量等于1时,我显示相应的列。例如,对于命令
exec my_procedure @display_description = 1
我期望产量
id data description
1 10 'help wanted'
2 20 'customer registered'
...
我如何在程序中实施它:
if @display_description = 1
select id, data, description from mytable
else
select id, data from mytable
问题是,如果我想有3个开关(每列一个),我必须在if
语句中写入8个条件。(我的select
语句是一个复杂的语句。此外,如果我希望显示viewsed\u times
等列,则必须计算它们。因此,编写许多if
语句会使查询非常笨拙,我希望避免这种情况)
是否有一种基于开关选择列的简单方法?如果没有,您建议使用什么方法从存储过程返回不同数量的列
编辑:对不起,我很遗憾表mytable
已经存在,并且包含所有列。但事实并非如此,有些列在显示之前必须进行计算。例如,列查看次数
不存在。要显示它,我需要执行以下操作:
if @display_description = 1
~ several selects to calculate the column viewed_times ~
select id, data, description from mytable join table in which I just calculated the viewed_times column
else
select id, data from mytable
if @display_viewed_times = 1
begin
~ calculate column viewed_times ~
update my_table
~ add column viewed_times to the table my_table ~
end
计算这些列非常耗时,只有在需要显示这些列时,我才会这样做
这就是动态SQL可能无法工作的原因
更新:我用动态SQL接受了答案,但我做了以下几点:
if @display_description = 1
~ several selects to calculate the column viewed_times ~
select id, data, description from mytable join table in which I just calculated the viewed_times column
else
select id, data from mytable
if @display_viewed_times = 1
begin
~ calculate column viewed_times ~
update my_table
~ add column viewed_times to the table my_table ~
end
对于每个可选列。然后我使用
select * from my_table
根据开关的不同,它提供了不同的列数。一种方法是使用动态SQL。这是伪SQL,因为这里没有获得完整答案的信息。它也未经测试,因为我没有太多/任何数据来真正运行它
--Your input parameters
DECLARE @description bit, @createdate bit, @viewedtimes bit /*...etc...*/;
--Now the SP
DECLARE @SQL nvarchar(MAX);
SET @SQL = N'SELECT ' +
STUFF(CONCAT(N','+ NCHAR(10) + N' ' + CASE WHEN @description = 1 THEN QUOTENAME(N'description') END,
N','+ NCHAR(10) + N' ' + CASE WHEN @createdate = 1 THEN QUOTENAME(N'created_at') END,
N','+ NCHAR(10) + N' ' + CASE WHEN @viewedtimes = 1 THEN QUOTENAME(N'viewed_times') END),1,9,N'') + NCHAR(10) +
N'FROM YourTable' + NCHAR(10) +
N'WHERE...;';
PRINT @SQL; --your best debugging friend.
EXEC sp_executesql @SQL /*N'@someParam int', @someParam = @inParam*/;
确保在使用动态SQL时正确地参数化查询不要连接字符串
例如,正确的格式是N',其中yourColumn=@yourParam和OtherColumn=@otherParam'
,然后在sp_executesql
中提供@yourParam
和@otherParam
的值(如我在注释中所示)
但是,不要这样做:
N'WHERE yourColumn=''+@myParam+N''和otherColumn='+CONVERT(varchar(5),@secondParam)
。这将对SQL注入开放(它不是您的朋友)。我会将存储过程更改为表值函数,并修改外部的“选择自”
例如:
if($value1 === 1)
$sql = "SELECT c1, c2 FROM dbo.my_udf";
elseif($value1 ===2)
$sql = "SELECT c1, c3, c4 FROM dbo.my_udf";
您可以使用动态查询。还有,谷歌为什么不直接使用
select。从
?一个存储过程能给你带来什么价值?一个根据传递的参数返回不同结果集形状的存储过程是一个有缺陷的接口设计,IMHO。我必须同意@DanGuzman。将每个排列作为一个单独的过程编写,然后让调用应用程序决定调用哪个。@EricBrandt在这种情况下,我必须用基本相同的代码编写8个不同的过程(包括和不包括每列)。还是我搞错了?那不是T-SQL。看起来您假设OP使用的是应用程序语言(是PHP吗?),但是他们没有提到这一点。充其量,这是一个非常疯狂的猜测。对于同一件事,拥有多个功能也不是一个很好的可扩展解决方案。如果查询需要更改,则需要更改11个函数,而不是1个。当然,这不是T-SQL。我的建议是将SP修改为函数。代码仅显示如何从函数中选择不同的列。我无法发布所需函数的代码,因为没有SP的代码。您的答案在我描述的设置中肯定有效,我相信它会对有相同问题的人有所帮助。我忘了提到,必须计算表mytable
中的某些列(考虑到该过程的结果mytable
),并且计算可能很繁重,因此我只希望在显示时计算它。因此,@SQL中的代码将有几个SELECT
语句,我希望避免使用这些语句。@AlexandrKapshuk,而不是简单地使用QUOTENAME(N'description')
包含表达式。例如,CASE当@description=1时,则N'SUM(CASE[description]当“Cheese”时,则[Price]结束)作为[description]'结束
。您仍然可以在动态SQL中包含表达式。如果找不到其他解决方案,我可能会这样做。我希望避免这种情况的原因是,代码在转换为字符串时变得不可读。特别感谢关于注射的提示!我会把它放在里面的mind@AlexandrKapshuk你最好的朋友就是为了这个。