【问题标题】:View joining with stored Procedure results查看加入存储过程的结果
【发布时间】:2013-08-07 12:40:13
【问题描述】:

我在应用程序使用的 SQL 服务器中有一个现有视图。我需要加入从存储过程返回的表。存储过程做了很多事情,比如在返回结果之前插入多个#temp 表。

我尝试将存储过程转换为表值函数。但是插入到 TVF 内的临时表会导致编译错误。

有没有其他方法可以实现这一点。

谢谢

【问题讨论】:

  • 好吧,您可以尝试先创建一个#temp 表,然后再创建INSERT #t EXEC dbo.procedure;,但随后您可能会遇到嵌套插入/执行问题。你为什么不尝试在 TVF 中编写一个版本的过程不使用使用#temp tables>
  • 对不起,没有直接的方法。仅通过例如中间结构,如表变量或临时表
  • @AaronBertrand StoredProc 根据逻辑将中间结果存储在多个#temp 表中。如果不使用 TVF 中的#tempTable,如何做到这一点。有没有其他选择
  • 当然,不要使用中间逻辑。没有看到逻辑就无法告诉你如何做到这一点。

标签: sql-server sql-server-2008 sql-server-2008-r2


【解决方案1】:

您可以将存储过程的结果插入到临时表中,然后将其连接到视图中。

看看下面的例子

SQL Fiddle DEMO

CREATE TABLE TADA(
  ID INT
);
INSERT INTO TADA VALUES (1),(2);

CREATE VIEW vw_TADA
AS
SELECT *
FROM TADA
WHERE ID <= 1;

CREATE PROCEDURE sp_TADA
AS
SELECT *
FROM TADA
WHERE ID > 1;

CREATE TABLE #TADA(
  ID INT
)
INSERT INTO #TADA EXEC sp_TADA

SELECT *
FROM vw_TADA
UNION ALL
SELECT *
FROM #TADA

【讨论】:

  • 但是如果该过程也执行插入/执行,那可能不起作用。
  • 是的,存储过程确实插入到临时表并具有 exec 语句。
【解决方案2】:

另一个技巧是使用OPENQUERY。来自my answer here

它需要使用OPENQUERY 和一个将'DATA ACCESS' 属性设置为true 的环回链接服务器。您可以检查sys.servers 以查看您是否已经有一个有效的服务器,但我们只需手动创建一个名为loopback 的服务器:

EXEC master..sp_addlinkedserver 
    @server = 'loopback',  
    @srvproduct = '',
    @provider = 'SQLNCLI',
    @datasrc = @@SERVERNAME;

EXEC master..sp_serveroption 
    @server = 'loopback', 
    @optname = 'DATA ACCESS',
    @optvalue = 'TRUE';

现在您可以将其作为链接服务器进行查询,您可以将任何查询(包括存储过程调用)的结果用作常规SELECT。所以你可以这样做(注意数据库前缀很重要,否则你会得到错误11529和2812):

SELECT * FROM OPENQUERY(loopback, 'EXEC db.dbo.procedure;') AS x;

现在您可以加入您的视图。

但老实说,如果您将程序重新编写为 TVF 并停止在逻辑中使用 #temp 表,那会更好。以上可能适用于您当前的实例,但它不适用于 SQL Server 2012(由于过程中的#temp 表而无法确定元数据),并且如果您有某些数据库或服务器,它将无法工作级别 DDL 触发(出于相同的原因)。

有关其他信息和限制,另请参阅 http://www.sommarskog.se/share_data.html#OPENQUERY

【讨论】:

    【解决方案3】:

    只是添加另一种方法来处理此类数据,您可以使用共享临时表或输出 xml 参数从存储过程中获取数据。实际上它需要修改你的程序,所以它可能不是一个选项。一般建议是尝试将您的过程重写为表函数(您可以将临时表更改为表变量)

    xml参数

    CREATE PROCEDURE sp_Process2
    (
      @Data xml = null output,
      @Fill_Data bit = 0
    )
    AS
    begin
       create table #Test1 (ID int, Name nvarchar(128), Col3 nvarchar(128))
    
       -- do some work
       insert into #Test1
       select 1, 'From Procedure', 'Unused'
    
       if @Fill_Data = 1 -- put data into xml parameter
       begin
          select @Data = 
          (
              select *
              from #Test1
              for xml raw('Data')
          )
       end
       else -- just return recordset
       begin
          select * from #Test1
       end
    end;
    

    共享表(动态 SQL 是完全可选的,只是将表名和列传递给过程)

    CREATE PROCEDURE sp_Process
    (
      @Table_Name nvarchar(128) = null,
      @Columns nvarchar(max) = null
    )
    AS
    begin
       declare @stmt nvarchar(max)
       create table #Test1 (ID int, Name nvarchar(128), Col3 nvarchar(128))
    
       -- do some work
       insert into #Test1
       select 1, 'From Procedure', 'Unused'
    
       if @Table_Name is not null -- put data into temporary table
       begin
          select @stmt = 'insert into ' + quotename(@Table_Name) + ' select ' + @Columns + ' from #Test1'
          exec sp_executesql @stmt = @stmt
       end
       else -- just return recordset
       begin
          select * from #Test1
       end
    end;
    

    参见sql fiddle 示例

    【讨论】:

      猜你喜欢
      • 2013-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-15
      • 1970-01-01
      • 2010-10-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多