将使用 exec 填充表的存储过程转换为标量值函数

Posted

技术标签:

【中文标题】将使用 exec 填充表的存储过程转换为标量值函数【英文标题】:Convert stored procedure which uses exec to populate table to scalar-valued function 【发布时间】:2016-11-23 21:20:26 【问题描述】:

我有这个存储过程:

ALTER procedure [dbo].[sp_checker2] 
    (@Item varchar(70), @location varchar(8))      
as      
    declare @Query varchar(2000)      
    set @location = 'XXX909'   

    declare @Table Table (Qty int)      
    set @Query = 'select TOP 1 * from openquery(xxxx,''SELECT NVL(b.t$st,0) from server.XXXXXID0001 a left join  
server.XXXXXID0002 b on a.t$item = b.t$item where b.t$cloc = '''''+ @location + ''''' and trim(a.t$item)='''''+ @Item + ''''''')'      

   insert into @Table exec (@Query)      
   if not exists (select * from @Table )
  begin
     set @Query = 'select TOP 1 * from openquery(xxxx,''SELECT NVL(b.t$st,0) from server.XXXXXID0001 a 
     left join server.XXXXXID0002 b on a.t$item = b.t$item where trim(a.t$item) = '''''+ @Item + ''''''' )'    

    insert into @Table exec (@Query)
    end
    select * from @Table

问题是我正在寻找这样的查询SELECT

SELECT 
    column1, column2, column3, column4, 
    (EXEC [dbo].[sp_checker2] 'param1=value of column3', 'param2=another value') AS column5 
FROM 
    table 
WHERE 
    column1 = 'data1' 
    AND column2 = 'data2' 
ORDER BY 
    column3

我知道在 SQL Server 的 SELECT 语句中执行存储过程是不可能的,我的替代方法是将存储过程转换为函数,但在存储过程内部我有一个 exec 到将数据插入表变量。有没有办法可以将此存储过程转换为函数?

附:我只在变量表中保存一行,即:如果项目存在,则保存其库存:“6500”

【问题讨论】:

旁注:您应该为您的存储过程使用sp_ 前缀。微软有reserved that prefix for its own use (see Naming Stored Procedures),你确实会在未来某个时候冒着名称冲突的风险。 It's also bad for your stored procedure performance。最好只是简单地避免 sp_ 并使用其他东西作为前缀 - 或者根本不使用前缀! 谢谢@marc_s,我会在接下来的手术中考虑这个重要的事实。 您的查询中有前 1 个,但它们没有排序依据。这意味着无法确定将返回哪一行。 【参考方案1】:

很难。在函数中不可能执行动态 SQL。我认为只有改变 WHERE 标准才有可能。您将能够更好地评估这对性能的影响。

CREATE FUNCTION [dbo].[f_checker2] (@item     varchar(70), 
                                    @location varchar(8))
  RETURNS @result TABLE (
                    Qty int
                  )
AS
BEGIN
  INSERT
    INTO @result
         select TOP(1) qty
           from openquery(xxxx, 'SELECT NVL(b.t$st,0)  AS qty,
                                        b.t$cloc       AS location,
                                        trim(a.t$item) AS item
                                   from server.XXXXXID0001 a 
                                        left join server.XXXXXID0002 b 
                                               on a.t$item = b.t$item')
   where location =  @location
     and item     =  @item

  if not exists (select * from @result)
    INSERT
      INTO @result
           select TOP(1) qty 
             from openquery(xxxx, 'SELECT NVL(b.t$st,0)  AS qty,
                                          b.t$cloc       AS location,
                                          trim(a.t$item) AS item
                                     from server.XXXXXID0001 a 
                                          left join server.XXXXXID0002 b 
                                                 on a.t$item = b.t$item')
     where item =  @item

  RETURN
END

GO 

【讨论】:

这是一个多语句表值函数,在这里性能会很差。 它成功了,但需要 10 分 17 秒才能完成。 @fbcomps 是否有进一步优化的机会?我非常感谢您的努力 完整的查询不可能在存储过程中运行,还是将其集成到视图中?

以上是关于将使用 exec 填充表的存储过程转换为标量值函数的主要内容,如果未能解决你的问题,请参考以下文章

从视图填充或创建表的 SQL Server 过程 - 性能问题

用于截断和重新填充表的 PLSQL 过程

如何在不使用存储过程的情况下在表函数中返回值 exec?

长存储过程在某些 exec 之后停止返回结果,为啥?

将算术公式从字符串转换为值

Google BigQuery SQL:如何将过程转换为返回表的函数?