从存储过程的结果集中select列

我有一个存储过程,返回80列和300行。 我想写一个select,获得这些列中的2。 就像是

SELECT col1, col2 FROM EXEC MyStoredProc 'param1', 'param2' 

当我使用上面的语法,我得到的错误:

“无效的列名称”。

我知道最简单的解决scheme将是更改存储过程,但我没有写,我不能改变它。

有什么办法可以做我想要的吗?

  • 我可以做一个临时表来放置结果,但是因为有80列,所以我需要制作一个80列的临时表才能得到2列。 我想避免跟踪所有返回的列。

  • 我试图使用WITH SprocResults AS ....如马克build议,但我得到了2个错误

    关键字“EXEC”附近的语法不正确。
    )附近语法不正确。

  • 我试图声明一个表variables,我得到了以下错误

    插入错误:提供的值的列名或数量与表定义不匹配

  • 如果我尝试
    SELECT * FROM EXEC MyStoredProc 'param1', 'param2'
    我得到的错误:

    关键字'exec'附近的语法不正确。

你能分解查询吗? 将存储的proc结果插入表variables或临时表中。 然后,从表variables中select2列。

 Declare @tablevar table(col1,.. insert into @tablevar(col1,..) exec MyStoredProc 'param1', 'param2' SELECT col1, col2 FROM @tablevar 

这里有一个很好的文档链接,解释所有不同的方法来解决你的问题(虽然很多不能使用,因为你不能修改现有的存储过程。)

如何在存储过程之间共享数据

Gulzar的答案是可行的(在上面的链接中有logging),但是写起来会很麻烦(你需要在@tablevar(col1,…)语句中指定所有80个列名。如果一个列被添加到模式或者输出被改变了,它将需要在你的代码中被更新,否则会出错。

 CREATE TABLE #Result ( ID int, Name varchar(500), Revenue money ) INSERT #Result EXEC RevenueByAdvertiser '1/1/10', '2/1/10' SELECT * FROM #Result ORDER BY Name DROP TABLE #Result 

资源:
http://stevesmithblog.com/blog/select-from-a-stored-procedure/

这适用于我:(即我只需要sp_help_job返回30+的2列)

 SELECT name, current_execution_status FROM OPENQUERY (MYSERVER, 'EXEC msdb.dbo.sp_help_job @job_name = ''My Job'', @job_aspect = ''JOB'''); 

在此之前,我需要运行这个:

 sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE; 

….更新sys.servers表。 (即在OPENQUERY中使用自引用似乎被默认禁用。)

对于我这个简单的要求,我遇到了Lance优秀链接的OPENQUERY部分所描述的问题。

罗西尼,如果你需要dynamic设置这些input参数,那么使用OPENQUERY变得更加繁琐:

 DECLARE @innerSql varchar(1000); DECLARE @outerSql varchar(1000); -- Set up the original stored proc definition. SET @innerSql = 'EXEC msdb.dbo.sp_help_job @job_name = '''+@param1+''', @job_aspect = N'''+@param2+'''' ; -- Handle quotes. SET @innerSql = REPLACE(@innerSql, '''', ''''''); -- Set up the OPENQUERY definition. SET @outerSql = 'SELECT name, current_execution_status FROM OPENQUERY (MYSERVER, ''' + @innerSql + ''');'; -- Execute. EXEC (@outerSql); 

我不确定使用sp_serveroption直接更新现有sys.servers自引用与使用sp_addlinkedserver (如Lance的链接中所述)创build重复/别名之间的差异(如果有的话)。

注1:我比OPENROWSET更喜欢OPENQUERY,因为OPENQUERY不需要proc中的连接string定义。

注2:说完这一切:通常我只是使用INSERT … EXEC :)是的,这是额外的打字10分钟,但如果我能帮助它,我宁愿不跳过:
(a)报价单内的报价单,以及
(b)系统表,和/或偷偷摸摸的自引用链接服务器设置(即这些,我需要恳求我的情况,我们的全能DBA 🙂

但是在这个例子中,我不能使用INSERT … EXEC结构,因为sp_help_job已经在使用了。 (“一个INSERT EXEC语句不能被嵌套。”)

知道为什么如此困难可能会有帮助。 存储过程只能返回文本(打印“文本”),或者可能返回多个表,或者根本不返回任何表。

所以像SELECT * FROM (exec sp_tables) Table1这样的东西是行不通的

(假设SQL Server)

在T-SQL中使用存储过程的结果的唯一方法是使用INSERT INTO ... EXEC语法。 这使您可以select插入临时表或表variables,并从那里select所需的数据。

为了达到这个目的,首先创build一个#test_table如下所示:

 create table #test_table( col1 int, col2 int, . . . col80 int ) 

现在执行程序并把值放在#test_table

 insert into #test_table EXEC MyStoredProc 'param1', 'param2' 

现在您从#test_table获取值:

 select col1,col2....,col80 from #test_table 

如果您可以修改存储过程,则可以轻松地将所需的列定义作为参数,并使用自动创build的临时表:

 CREATE PROCEDURE sp_GetDiffDataExample @columnsStatement NVARCHAR(MAX) -- required columns statement (eg "field1, field2") AS BEGIN DECLARE @query NVARCHAR(MAX) SET @query = N'SELECT ' + @columnsStatement + N' INTO ##TempTable FROM dbo.TestTable' EXEC sp_executeSql @query SELECT * FROM ##TempTable DROP TABLE ##TempTable END 

在这种情况下,您不需要手动创build临时表 – 它会自动创build。 希望这可以帮助。

快速'@Column_Name'将是添加一个新的参数'@Column_Name'并让调用函数定义要检索的列名称。 在你的sproc的返回部分,你会有if / else语句,只返回指定的列,或者是空的 – 返回全部。

 CREATE PROCEDURE [dbo].[MySproc] @Column_Name AS VARCHAR(50) AS BEGIN IF (@Column_Name = 'ColumnName1') BEGIN SELECT @ColumnItem1 as 'ColumnName1' END ELSE BEGIN SELECT @ColumnItem1 as 'ColumnName1', @ColumnItem2 as 'ColumnName2', @ColumnItem3 as 'ColumnName3' END END 

如果你这样做的手动validation的数据,你可以用LINQPad做到这一点。

在LinqPad中创build到数据库的连接,然后创build与以下类似的C#语句:

 DataTable table = MyStoredProc (param1, param2).Tables[0]; (from row in table.AsEnumerable() select new { Col1 = row.Field<string>("col1"), Col2 = row.Field<string>("col2"), }).Dump(); 

参考资料http://www.global-webnet.net/blogengine/post/2008/09/10/LINQPAD-Using-Stored-Procedures-Accessing-a-DataSet.aspx

对于SQL Server,我发现这工作正常:

创build一个临时表(或永久表,实际上并不重要),并对存储过程做一个插入语句。 SP的结果集应该匹配表中的列,否则会出错。

这是一个例子:

 DECLARE @temp TABLE (firstname NVARCHAR(30), lastname nvarchar(50)); INSERT INTO @temp EXEC dbo.GetPersonName @param1,@param2; -- assumption is that dbo.GetPersonName returns a table with firstname / lastname columns SELECT * FROM @temp; 

而已!

尝试这个

 use mydatabase create procedure sp_onetwothree as select 1 as '1', 2 as '2', 3 as '3' go SELECT a.[1], a.[2] FROM OPENROWSET('SQLOLEDB','myserver';'sa';'mysapass', 'exec mydatabase.dbo.sp_onetwothree') AS a GO 

正如问题中提到的那样,在执行存储过程之前很难定义80列临时表。

所以另一种方法是根据存储过程结果集填充表。

 SELECT * INTO #temp FROM OPENROWSET('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;' ,'EXEC MyStoredProc') 

如果您遇到任何错误,您需要通过执行以下查询来启用临时分布式查询。

 sp_configure 'Show Advanced Options', 1 GO RECONFIGURE GO sp_configure 'Ad Hoc Distributed Queries', 1 GO RECONFIGURE GO 

要使用这两个参数执行sp_configure来更改configuration选项或运行RECONFIGURE语句,您必须被授予ALTER SETTINGS服务器级权限

现在,您可以从生成的表格中select特定的列

 SELECT col1, col2 FROM #temp 

我会剪切和粘贴原始的SP,并删除除了你想要的2之外的所有列。 要么。 我会把结果集,映射到一个适当的业务对象,然后LINQ出两列。

如果你只需要这样一次,最简单的方法就是:

在导入和导出向导中导出为ex​​cel,然后将该excel导入到表中。