我在应用程序使用的SQL服务器中有一个现有视图。我需要加入从存储过程返回的表。存储过程执行很多操作,例如在返回结果之前插入多个#temp表。
我尝试将存储过程转换为Table值函数。但是在TVF内插入临时表会导致编译错误。
还有其他方法可以达到这个目的。
由于
答案 0 :(得分:3)
您可以将存储过程中的结果插入到临时表中,然后将其连接到视图中。
看一下下面的例子
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
答案 1 :(得分:0)
另一个技巧是使用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了解其他信息和限制。
答案 2 :(得分:0)
只是要添加另一种方法来处理这样的数据,您可以使用共享临时表或输出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示例