3

如果这个问题有点含糊,我提前道歉 - 我相当确定这是一个概念问题,而不是语法问题。

我正在使用MSSQL(SQL Server 2008),并且我有一个存储过程,它采用用户定义的表类型的表值参数(它被一段传入数据表的.NET 代码调用)。

我遇到的问题如下:
我需要操作该表变量中的数据,但是变量本身是只读的(据我所知,必须是为了传递到存储过程中,因为它是用户定义的表类型)。

我已经考虑过从表中选择所有内容并在最后插入目标表之前操作 #temp 的明显解决@TVP方案#temp。但是,我希望能够调用多个存储过程来对数据进行操作,这意味着在调用者和被调用者之间来回传递表变量。需要完成的数据操作量很大,这就是我试图将其拆分为多个存储过程的原因。据我所知,这是不可能的,因为 TVP 必须装饰为 READONLY 并且#temp表不能作为参数传递给存储过程。我考虑过使用全局##temp表,但是可以使用不同的数据集同时多次调用此过程(这也是我不将其选择到临时物理表中的原因)。

从概念上讲,我在这里缺少什么吗?实现这一目标的最佳方法是什么?我愿意把它变成一个庞大的存储过程——但为了让它更易于维护,我不希望这样做。

回顾一下:

我有 P_CALLER、P_CALLEE_1 和 P_CALLEE_2(显然不是真实姓名)。

  1. P_CALLER 接收@SomeTable 作为 TVP。

  2. P_CALLER 需要将@SomeTable 传递给P_CALLEE_1 来操作数据,然后将修改后的结果传递回P_CALLER。

  3. P_CALLER 做同样的事情,这次调用 P_CALLEE_2,它也将它传回。

  4. P_CALLER 将最终插入到 DestinationTable。

我已经尝试用谷歌搜索找到答案,但似乎我发现的结果都与情况不符。任何意见,将不胜感激。

4

1 回答 1

1

您可以在父过程中创建一个临时表,并从子过程中对其进行操作。

这是一个粗略的例子;当然,在生产环境中,您可以通过一些防御性编程/事务处理等来加强这一点。

create type CustomTable as table (Id int primary key, Name varchar(10));
go

create procedure dbo.Worker1
as
begin
    delete from #work where Id > 5;
end
go

create procedure dbo.Worker2
as
begin
    insert into #work
        select -1, 'New One';
end
go

create procedure dbo.Driver (@input CustomTable readonly)
as
begin

    -- #work is created by dbo.Driver but visible to all child procs
    -- its also scoped to this instance of Driver
    select * into #work from @input; 

    -- do complicated work
    exec dbo.Worker1;
    exec dbo.Worker2;

    --return the final set (your insert into DestinationTable)
    select 'FINAL', * from #work;

end
return;

--usage

declare @table CustomTable;
insert into @table  
    values(1, 'One'),(2, 'Two'), (6, 'Six');

exec dbo.Driver @table;

回报:

      Id          Name
----- ----------- ----------
FINAL -1          New One
FINAL 1           One
FINAL 2           Two
于 2013-08-21T02:39:07.073 回答