当前位置:  开发笔记 > 编程语言 > 正文

从存储过程的结果集中选择列

如何解决《从存储过程的结果集中选择列》经验,为你挑选了12个好方法。

我有一个存储过程返回80列和300行.我想写一个选择,获得其中2列.就像是

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

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

"无效的列名称".

我知道最简单的解决方案是更改存储过程,但我没有写它,我无法改变它.

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

我可以创建一个临时表来放置结果,但因为有80列所以我需要制作一个80列的临时表来获得2列.我想避免追踪返回的所有列.

WITH SprocResults AS ....按照马克的建议尝试使用,但我遇到了2个错误

关键字"EXEC"附近的语法不正确.
')'附近的语法不正确.

我尝试声明一个表变量,我得到以下错误

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

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

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

Gulzar Nazim.. 177

你能分开查询吗?将存储的proc结果插入表变量或临时表中.然后,从表变量中选择2列.

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

SELECT col1, col2 FROM @tablevar

当您不知道表定义时,它也不起作用 (22认同)

如果MyStoredProc调用任何其他存储过程,这将不起作用 (12认同)


Lance McNear.. 81

这是一个非常好的文档的链接,解释了解决问题的所有不同方法(尽管由于您无法修改现有的存储过程,因此很多方法都无法使用.)

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

Gulzar的答案将起作用(它在上面的链接中有记录),但编写麻烦(您需要在@tablevar(col1,...)语句中指定所有80个列名.并且将来如果将一个列添加到架构中或者输出已更改,则需要在代码中更新它,否则它将出错.



1> Gulzar Nazim..:

你能分开查询吗?将存储的proc结果插入表变量或临时表中.然后,从表变量中选择2列.

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

SELECT col1, col2 FROM @tablevar


当您不知道表定义时,它也不起作用
如果MyStoredProc调用任何其他存储过程,这将不起作用

2> Lance McNear..:

这是一个非常好的文档的链接,解释了解决问题的所有不同方法(尽管由于您无法修改现有的存储过程,因此很多方法都无法使用.)

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

Gulzar的答案将起作用(它在上面的链接中有记录),但编写麻烦(您需要在@tablevar(col1,...)语句中指定所有80个列名.并且将来如果将一个列添加到架构中或者输出已更改,则需要在代码中更新它,否则它将出错.



3> 小智..:
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/



4> Merenzo..:

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

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部分中描述的所有问题.

Rossini,如果你需要动态设置这些输入参数,那么使用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链接中所述)创建重复/别名之间的差异(如果有).

注1:我更喜欢OPENQUERY而不是OPENROWSET,因为OPENQUERY不需要proc中的连接字符串定义.

注2:说完所有这些:通常我会使用INSERT ... EXEC :)是的,这是10分钟的额外打字,但如果我可以帮助它,我宁愿不要用以下方式进行跳汰:
(a)引号内的引号引号,和
(b)sys表,和/或偷偷摸摸的自引用链接服务器设置(即对于这些,我需要向我们全能的DBA辩护:)

但是在这种情况下,我无法使用INSERT ... EXEC结构,因为sp_help_job已经使用了一个.("INSERT EXEC语句不能嵌套.")


我之前在dynamic-sql-generated-dynamic-sql-that-generated-dynamic-sql中连续有13个单引号...

5> 小智..:

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

所以类似的东西SELECT * FROM (exec sp_tables) Table1 不起作用


如果发生这种情况,SQL Server可以自由引发错误.例如,如果我写一个返回多个值的子查询.是的****可以**发生,但实际上它不会发生.即使它确实如此:提出错误并不困难.

6> 小智..:

要实现这一点,首先要创建#test_table如下:

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

现在执行procedure并将值放入#test_table:

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

现在您从#test_table以下位置获取值:

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


如果我只需要其他存储过程中的一列,该怎么办?
创建临时表而不是表变量是否有优势?

7> dyatchenko..:

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

CREATE PROCEDURE sp_GetDiffDataExample
      @columnsStatement NVARCHAR(MAX) -- required columns statement (e.g. "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

在这种情况下,您无需手动创建临时表 - 它是自动创建的.希望这可以帮助.



8> Brannon..:

(假设SQL Server)

在T-SQL中使用存储过程结果的唯一方法是使用INSERT INTO ... EXEC语法.这使您可以选择插入临时表或表变量,然后从中选择所需的数据.



9> 小智..:

快速入侵是添加一个新参数'@Column_Name'并让调用函数定义要检索的列名.在您的sproc的返回部分中,您将拥有if/else语句并仅返回指定的列,或者如果为空 - 返回all.

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



10> ShawnFeather..:

如果您正在执行此操作以手动验证数据,则可以使用LINQPad执行此操作.

在LinqPad中创建与数据库的连接,然后创建类似于以下内容的C#语句:

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

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



11> LTMOD..:

对于SQL Server,我发现这很好用:

创建临时表(或永久表,并不重要),并对存储过程执行insert into语句.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;

而已!



12> sqluser..:

正如问题中提到的那样,在执行存储过程之前很难定义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使用两个参数执行更改配置选项或运行RECONFIGURE语句,必须授予ALTER SETTINGS服务器级别权限

现在,您可以从生成的表中选择特定的列

SELECT col1, col2
FROM #temp

推荐阅读
手机用户2502852037
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有