【问题标题】:Use SQL to filter the results of a stored procedure使用 SQL 过滤存储过程的结果
【发布时间】:2023-03-15 08:59:02
【问题描述】:

我在 Stack Overflow 上查看了与此问题相关的其他问题,但似乎没有一个人能清楚地回答这个问题。

我们有一个名为 sp_who2 的系统存储过程,它返回服务器上所有正在运行的进程的信息结果集。我要过滤存储过程返回的数据;从概念上讲,我可能会这样做:

SELECT * FROM sp_who2
WHERE login='bmccormack'

不过,这种方法行不通。有什么好的做法可以实现查询存储过程返回数据的目标,最好不用查看原始存储过程的代码并修改它。

【问题讨论】:

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


    【解决方案1】:

    将数据放在 Table 变量或 Temp 表中并对其进行过滤。

    【讨论】:

      【解决方案2】:

      没有好的方法可以做到这一点。这是存储过程的限制。您的选择是:

      1. 将程序切换到User Defined Function。今天,在世界各地,人们都在制作应该是函数的存储过程。这是一个教育问题。你的情况就是一个很好的例子。如果您的过程是一个 UDF,您可以执行以下操作,就像您直观地认为您应该能够做到的那样:

        SELECT * FROM udf_who2()
        WHERE login='bmccormack'
        
      2. 如果你真的不能触摸你的过程,并且必须在 sql 中完成,那么你将不得不变得时髦。制作另一个存储过程来包装您的原始过程。在新过程中调用现有过程并将值放入临时表中,然后使用所需过滤器对该表运行查询,并将结果返回给外部世界。

      从 SQL Server 2005 开始,用户定义的函数是您封装数据检索的方式。存储过程以及视图是在特定情况下使用的专用工具。它们在正确的时间都非常方便,但不是第一选择。有些人可能会认为上面的示例 (A) 获取函数的所有结果,然后 (B) 对该结果集进行过滤,就像子查询一样。 情况并非如此。 SQL server 2005+ 优化了该查询;如果login 上有索引,则在查询执行计划中看不到表扫描;效率很高。

      编辑:我应该补充一点,UDF 的内部结构类似于 SP。如果它与您想要避免的 SP 的 逻辑 混淆,您仍然可以将其更改为函数。有几次,我使用了我不想理解的大而可怕的程序代码,并成功地将它转移到一个函数中。唯一的问题是如果过程修改除了返回结果之外的任何东西; UDF 不能修改数据库中的数据。

      【讨论】:

      • 需要注意的是,内联表值函数和多语句表值函数之间可能存在很大差异。内联 TVF 可以像视图一样进行优化,它们的行为更接近(参数化)视图而不是函数。
      • @Case Roux 非常好!如果它是一个多语句函数,选项 1 会增加简单性,但可能不会提高性能。对于大量行,可能是一条狗。如果性能很重要,选项 2 可能会更快。视情况而定,一如既往。
      • 如果存储过程使用临时表,这可能不起作用。因为用户定义的函数不能创建临时表。
      【解决方案3】:

      您可以发送OPENROWSET(),但会涉及一些安全/性能问题。

      SELECT * 
      FROM OPENROWSET ('SQLOLEDB', 'Server=(local);TRUSTED_CONNECTION=YES;', 'exec mystoredproc')
      

      传统上,将其添加到临时变量/表中即可。

      【讨论】:

        【解决方案4】:

        临时表的过滤是可能的方式。

        -- Create tmp table from sp_who results
        CREATE TABLE #TmpWho
        (spid INT, ecid INT, status VARCHAR(150), loginame VARCHAR(150),
        hostname VARCHAR(150), blk INT, dbname VARCHAR(150), cmd VARCHAR(150), request_id INT)
        INSERT INTO #TmpWho
        EXEC sp_who
        
        -- filter temp table where spid is 52
        SELECT * FROM #TmpWho
        WHERE spid = 52
        
        DROP TABLE #TmpWho
        

        【讨论】:

          【解决方案5】:

          OPENROWSET() 是方式:

          SELECT *
          FROM
              OPENROWSET('SQLNCLI', 'Server=(local);TRUSTED_CONNECTION=YES;', 'exec sp_who')
          WHERE loginame = 'test' AND dbname = 'Expirement';
          

          您还需要在工作前启用高级配置:

          sp_configure 'show advanced options', 1;  
          RECONFIGURE;
          GO
          sp_configure 'Ad Hoc Distributed Queries', 1; 
          RECONFIGURE;
          GO 
          

          【讨论】:

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