如何从存储过程中选择数据

438

我有一个返回行的存储过程:

CREATE PROCEDURE MyProc
AS
BEGIN
    SELECT * FROM MyTable
END

我的实际过程有点复杂,这就是为什么需要一个存储过程的原因。

是否可以通过调用此过程来选择输出?

例如:

SELECT * FROM (EXEC MyProc) AS TEMP

我需要使用 SELECT TOP XROW_NUMBER 和额外的 WHERE 子句来对我的数据进行分页,而且我不想将这些值作为参数传递。


1
有没有特别的原因,你不想将值作为参数传递?按照你建议的方式做有点低效 - 你会选择比你需要的更多的数据,然后并没有全部使用。 - Mark Bell
2
请查看此处:http://www.sommarskog.se/share_data.html - pylover
2
如果有人想将sp输出插入到一个具有许多列的TABLE变量中,请按Ctrl+T以文本形式输出结果,然后复制第一列行并从中删除额外的空格,您就可以轻松获得列名。要返回网格输出,请按Ctrl+D - Ashraful
12
警告所有进入此处的人:目前仅提供三种答案:1.使用函数(被接受的答案),2.使用表变量或临时表并 INSERT EXEC [如果 你的存储过程不是太复杂],3. 作弊并使用 OPENQUERY。但是每个答案都被重复许多次,其中许多答案得到了惊人的赞数。你已经被警告了。 - ruffin
1
@ruffin,自然而然地,在最终找到你的评论之前,我以困难的方式发现了你所说的真相。 - egmfrs
显示剩余2条评论
16个回答

289

您可以执行以下步骤来处理存储过程的结果集:

  1. 创建一个表变量来保存存储过程的结果集。
  2. 将存储过程的输出插入到表变量中。
  3. 像使用其他表一样使用表变量即可...

... SQL代码...

Declare @T Table ([column definitions here])
Insert @T Exec storedProcname params 
Select * from @T Where ...

61
INSERT #TINSERT @T 的问题在于无法嵌套使用 INSERT EXEC 语句。 如果存储过程中已经有了一个 INSERT EXEC,那么这样将行不通。 - MOHCTP
2
这可能是最便携的解决方案,最接近基本的SQL。它还有助于维护强列类型定义。应该比上面的那些投票更多。 - user2074102
这里使用表变量比临时表在存储过程重新编译方面更有用。所以我同意,这个答案应该有更多的赞。 - resnyanskiy

182

您可以使用用户定义的函数视图来代替存储过程。

存储过程可以返回多个具有自己模式的结果集,不适合在SELECT语句中使用。


8
另外,如果将其转换为UDF后发现需要存储过程语义,您可以随时使用存储过程包装该UDF。 - Joel Coehoorn
如果我们需要将参数发送到多个存储过程并将它们组合成一个大的存储过程,该怎么办?可以像存储过程一样查看、获取参数。 - mrN
3
视图不接受参数,但用户定义的函数(UDF)可以。 - Mehrdad Afshari
3
你好,我真的需要在不将存储过程转换为视图或函数的情况下完成这个任务,这是否可能? - luisgepeto
@LuisBecerril 我也是。底层存储过程受到保护,我没有权限更改它(甚至查看脚本)。 - jf328
3
虽然你的回答是正确的陈述,但它并没有回答问题...“SELECT FROM存储过程”。这确实不理想,但也只能如此。 @Aamir的回答是正确的。或者需要更改问题...但我觉得这有点荒谬。 - Urasquirrel

95

您可能想要一个表值函数,或者将EXEC语句插入到临时表中:

INSERT INTO #tab EXEC MyProc

55
使用INSERT #TINSERT @T的问题在于无法嵌套INSERT EXEC语句。 如果存储过程中已经有一个INSERT EXEC,那么这样做将行不通。 - MOHCTP

73

你需要声明一个表类型,其中包含与存储过程返回的列数量相同的列。 表类型中的列的数据类型和存储过程返回的列应该是相同的。

declare @MyTableType as table
(
FIRSTCOLUMN int
,.....
)  

那么您需要将存储过程的结果插入到您刚定义的表类型中

Insert into @MyTableType 
EXEC [dbo].[MyStoredProcedure]

最终只需从您的表类型中进行选择

Select * from @MyTableType

这对我来说是最好的解决方案,因为您不需要指定服务器名称、连接字符串或配置任何链接服务器才能使其工作-这些都是我不想做的事情,只是为了获取一些数据。谢谢!答案太棒了! - Matt
很好的答案 ღ❤ೋღ❤ღೋ❤ღ - Nahid
当存储过程太复杂时,这种方法就不起作用了,例如当存储过程使用两个临时表。 - nick_n_a
1
它只能在存储过程内部工作。在查询控制台中(作为单独的查询),它会导致错误:“无法嵌套INSERT EXEC语句”。 - Kate

56

你必须了解 OPENROWSETOPENQUERY

SELECT  * 
INTO    #tmp FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')

7
如何动态获取“YOURSERVERNAME”?您不能指望始终知道它。这样做会不会导致每个星期二都出问题?所以,如果我有100台服务器,每台服务器的名称都不同... - Urasquirrel
2
还有,如果我的数据库没有配置允许这个怎么办? - Urasquirrel
10
使用@@servername动态获取服务器名称。 - Siddhartha Gandhi

38

不必使用临时表。

这是我的解决方案。

SELECT  *  FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
WHERE somefield = anyvalue

3
需要将您的服务器作为链接服务器添加到自身,但这很容易实现!谢谢! - vaheeds
1
以下是一些关于此问题的重要注意事项:https://dev59.com/BkzSa4cB1Zd3GeqPllfm - Keith Adler
1
嗯...我收到了错误信息“错误7411:服务器'YourServerName'未配置数据访问权限。”我需要改变什么? - Matt
@Matt: sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE; - alexkovelsky
@alexkovelsky - 谢谢,调用 EXEC sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE; 确实使错误消失了。但是现在当我执行 SELECT * FROM OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters') 时,我得到一个语法错误 - 即使像这里 D节 中提到的通过查询 SELECT * FROM OPENQUERY (Server, 'SELECT name FROM dbo.Customers'); 也给我一个语法错误。还有什么其他的缺失吗? - Matt
显示剩余2条评论

30
你可以将 sp 的输出复制到临时表中。
CREATE TABLE #GetVersionValues
(
    [Index] int,
    [Name]  sysname,
    Internal_value  int,
    Character_Value sysname
)
INSERT #GetVersionValues EXEC master.dbo.xp_msver 'WindowsVersion'
SELECT * FROM #GetVersionValues
drop TABLE #GetVersionValues

8
尝试将您的过程转换为以下返回表格的内联函数:
CREATE FUNCTION MyProc()
RETURNS TABLE AS
RETURN (SELECT * FROM MyTable)
然后你可以称其为:
SELECT * FROM MyProc()
您还可以选择按以下方式向函数传递参数:
CREATE FUNCTION FuncName (@para1 para1_type, @para2 para2_type , ... ) 

并将其称为

SELECT * FROM FuncName ( @para1 , @para2 )

8
如果“数据访问”为false,
EXEC sp_serveroption 'SQLSERVERNAME', 'DATA ACCESS', TRUE

之后,

SELECT  *  FROM OPENQUERY(SQLSERVERNAME, 'EXEC DBNAME..MyProc @parameters')

它有效。


7
使用 OPENQUERY,并在执行之前设置 SET FMTONLY OFF; SET NOCOUNT ON; 尝试使用以下示例代码:
SELECT top(1)*
FROM
OPENQUERY( [Server], 'SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE  [database].[dbo].[storedprocedure]  value,value ')
如果您遇到“服务器未配置数据访问”错误,请使用以下方法:
EXEC sp_serveroption 'YourServer', 'DATA ACCESS', TRUE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,