我在应用程序使用的 SQL 服务器中有一个现有视图。我需要加入从存储过程返回的表。存储过程做了很多事情,比如在返回结果之前插入多个#temp 表。
我试图将存储过程转换为表值函数。但是插入到 TVF 内的临时表会导致编译错误。
有没有其他方法可以实现这一点。
谢谢
我在应用程序使用的 SQL 服务器中有一个现有视图。我需要加入从存储过程返回的表。存储过程做了很多事情,比如在返回结果之前插入多个#temp 表。
我试图将存储过程转换为表值函数。但是插入到 TVF 内的临时表会导致编译错误。
有没有其他方法可以实现这一点。
谢谢
您可以将存储过程的结果插入到临时表中,然后将其连接到视图中。
看看下面的例子
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
只是为了添加另一种方法来处理此类数据,您可以使用共享临时表或输出 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 with examples
另一个技巧是使用OPENQUERY
. 从我在这里的回答:
它需要使用属性设置为 trueOPENQUERY
的环回链接服务器。'DATA ACCESS'
您可以检查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了解其他信息和限制。