【问题标题】:How to SELECT FROM stored procedure如何从存储过程中选择
【发布时间】:2010-12-02 07:41:44
【问题描述】:

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

CREATE PROCEDURE MyProc
AS
BEGIN
    SELECT * FROM MyTable
END

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

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

类似:

SELECT * FROM (EXEC MyProc) AS TEMP

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

【问题讨论】:

  • 我不确定您打算在这里做什么,因为当您执行该过程时,您正在取回行。您是否想在 SELECT 语句中执行该过程,以便将其绑定到可分页对象?
  • 您不想将值作为参数传递是否有特殊原因?按照您建议的方式执行此操作有点效率低下 - 您将选择比您需要的更多的数据,然后不会全部使用。
  • 如果有人想将 sp 输出插入到 TABLE 变量中,在你的 sp 中有很多列,请按 Ctrl+T 将结果输出为文本,然后复制第一列行并删除多余的空格从那里,您将轻松获得列名。要返回网格输出,请按Ctrl+D
  • 注意所有进入这里的人: atm 下面只提供了大约三个答案:1. 使用函数(接受的答案),2. 使用表变量或临时表和INSERT EXEC iff your sproc isn't too complicated3. cheat and use OPENQUERY。但是每个答案都重复了惊人的次数,其中许多都获得了惊人的赞成票数。你已经被警告过了。 ????

标签: sql sql-server sql-server-2005 stored-procedures


【解决方案1】:

你可以

  1. 创建一个表变量来保存 存储过程中的结果集和 那么
  2. 插入的输出 将过程存储到表变量中, 然后
  3. 使用表变量 和其他人一模一样 表...

... sql ....

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

【讨论】:

  • INSERT #TINSERT @T 的问题是不能嵌套INSERT EXEC 语句。如果存储过程中已经有一个INSERT EXEC,这将不起作用。
  • 这可能是最便携的解决方案,最接近基本 SQL。它还有助于维护强大的列类型定义。应该有比上述更多的赞成票。
  • table variables 在 sp 重新编译方面看起来比临时表更有用。所以我同意,这个答案应该有更多的赞成票。
【解决方案2】:

您可以使用User-defined functionview 代替过程。

一个过程可以返回多个结果集,每个结果集都有自己的架构。它不适合在SELECT 语句中使用。

【讨论】:

  • 此外,如果在转换为 UDF 后,您发现需要存储过程语义,您可以随时使用过程包装 UDF。
  • 如果我们需要向多个存储过程发送参数并将它们组合成一个大存储过程怎么办?可以查看、获取参数,就像存储过程一样
  • @mrN 视图不带参数,但 UDF 可以。
  • 你好,我确实需要这样做而不将sp转换为视图或函数,可以吗?
  • 虽然您的回答是真实的陈述,但它并没有回答问题......“从存储过程中选择”这肯定不是理想的,但它就是这样...... @Aamir 的回答是正确答案。无论是那个还是问题都需要改变......这对我来说似乎有点荒谬。
【解决方案3】:

您要么想要Table-Valued function,要么将您的 EXEC 插入临时表:

INSERT INTO #tab EXEC MyProc

【讨论】:

  • INSERT #TINSERT @T 的问题是不能嵌套INSERT EXEC 语句。如果存储过程中已经有一个INSERT EXEC,这将不起作用。
【解决方案4】:

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

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

然后你需要将存储过程的结果插入到你刚刚定义的表类型中

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

最后只需从您的表格类型中选择

Select * from @MyTableType

【讨论】:

  • 这对我来说是最好的解决方案,因为您不需要指定服务器名称、连接字符串或必须配置任何链接的服务器以使其工作 - 这是我不做的事情'不想做只是为了取回一些数据。谢谢!很棒的答案!
  • 不错的答案ღ❤ೋღ❤ღೋ❤ღ
  • 当存储过程太难时 - 这种方法不起作用,例如,当存储过程使用两个临时表时。
【解决方案5】:

你必须阅读OPENROWSETOPENQUERY

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

【讨论】:

  • 如何动态获取 YOURSERVERNAME?你不能指望总是要知道。这不会每隔一个星期二休息吗?所以如果我有 100 台不同名称的服务器......
  • 如果我的数据库未配置为允许这样做怎么办?
  • 尝试@@servername动态获取
【解决方案6】:

没有必要使用临时表。

这是我的解决方案

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

【讨论】:

  • 这需要你将你的服务器作为一个链接服务器添加到它自己,但它就像一个魅力!谢谢!
  • 对此有一些重要的警告:stackoverflow.com/questions/2374741/…
  • 嗯 ...我收到错误“错误 7411:服务器 'YourServerName' 未配置为数据访问。”我需要改变什么?
  • 您是否将您的服务器添加为链接服务器? YourServerName 是您的服务器的名称。您必须将 YourServerName 更改为您的真实服务器名称。
  • @Matt: sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;
【解决方案7】:

您可以将输出从 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 )
    

    【讨论】:

      【解决方案9】:

      你可以用 OPENROWSET 作弊:

      SELECT ...fieldlist...
      FROM OPENROWSET('SQLNCLI', 'connection string', 'name of sp')
      WHERE ...
      

      当然,这仍然会每次都运行整个 SP。

      【讨论】:

      • SQL Server 阻止了对组件“Ad Hoc Distributed Queries”的 STATEMENT 'OpenRowset/OpenDatasource' 的访问,因为该组件作为该服务器安全配置的一部分被关闭。系统管理员可以使用 sp_configure 启用“即席分布式查询”。有关启用“即席分布式查询”的详细信息,请在 SQL Server 联机丛书中搜索“即席分布式查询”。
      【解决方案10】:

      如果“数据访问”为假,

      EXEC sp_serveroption 'SQLSERVERNAME', 'DATA ACCESS', TRUE
      

      之后,

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

      它有效。

      【讨论】:

        【解决方案11】:

        使用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
        

        【讨论】:

          【解决方案12】:

          为了简单起见并使其可重新运行,我使用了系统 StoredProcedure "sp_readerrorlog" 来获取数据:

          -----USING Table Variable
          DECLARE @tblVar TABLE (
             LogDate DATETIME,
             ProcessInfo NVARCHAR(MAX),
             [Text] NVARCHAR(MAX)
          )
          INSERT INTO @tblVar Exec sp_readerrorlog
          SELECT LogDate as DateOccured, ProcessInfo as pInfo, [Text] as Message FROM @tblVar
          
          
          
          -----(OR): Using Temp Table
          IF OBJECT_ID('tempdb..#temp') IS NOT NULL  DROP TABLE #temp;
          CREATE TABLE #temp (
             LogDate DATETIME,
             ProcessInfo NVARCHAR(55),
             Text NVARCHAR(MAX)
          )
          INSERT INTO #temp EXEC sp_readerrorlog
          SELECT * FROM #temp
          

          【讨论】:

            【解决方案13】:

            听起来您可能只需要使用view。视图允许将查询表示为表,以便可以查询视图。

            【讨论】:

              【解决方案14】:

              例如,如果您的服务器名为 SERVERX,我就是这样做的...

              EXEC sp_serveroption 'SERVERX', 'DATA ACCESS', TRUE;
              DECLARE @CMD VARCHAR(1000);
              DECLARE @StudentID CHAR(10);
              SET @StudentID = 'STUDENT01';
              SET @CMD = 'SELECT * FROM OPENQUERY([SERVERX], ''SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE MYDATABASE.dbo.MYSTOREDPROC ' + @StudentID + ''') WHERE SOMEFIELD = SOMEVALUE';
              EXEC (@CMD);
              

              为了检查这是否有效,我注释掉了EXEC() 命令行,并用SELECT @CMD 替换它,以便在尝试执行命令之前查看该命令!这是为了确保所有正确数量的单引号都在正确的位置。 :-)

              我希望对某人有所帮助。

              【讨论】:

                猜你喜欢
                • 2010-12-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-11-29
                • 1970-01-01
                相关资源
                最近更新 更多