在存储过程之间共享数据
Sharing data between stored procedures
我有一个名为 dbo.Match
的存储过程。
看起来像这样:
CREATE Procedure [dbo].[MATCH]
@parameterFromUser nvarchar(30),
@checkbool int
As
Begin
--SOME CODE
select RowId,
PercentMatch
from @Matches
End
正在从另一个存储过程调用此过程:
CREATE Procedure MatchMotherFirstName
@MotherFN nvarchar(20) , @checkbool int
As begin
SELECT @constVal = FunctionWeight
FROM dbo.FunctionWeights
WHERE FunctionWeights.FunctionId = 20;
/*
Some code to execute `dbo.Match` procedure in above procedure called `MatchMotherFirstName` , retrieve `RowNumber` and `PercentMatch`,
Insert into #Temp in their respective fields , and calculate `PercentMatch * constVal`,
and insert in corresponding column called `percentage` in `#Temp`
*/
End
我需要在上面的过程中执行dbo.Match
存储过程,检索RowID
和PecrntMatch值,@constval
我们上面的值,乘以@constVal
和percentmatch
并将其存储在 #Temp
的 Percentage
列中,并将 dbo.Match procedure
的结果插入临时 table。 dbo.Match
returns 只有 RowId
和 PercentMatch
。
临时结构table:
create table #Temp
(
Rownumber int not null,
ValFromUser nvarchar(30),
ColumnName nvarchar(30),
ValFromFunc decimal(18, 4),
FuncWeight decimal(18, 4), -- @constVal here
Percentage decimal(18, 4) not null, -- calculated value here i.e (FuncWeight * ValFromFunc)
);
在 #Temp
中,我需要插入 @constVal
的值以及计算列并插入,即 PercentMatch * contVal
仅用于在此执行调用中插入的行。
我怎样才能以最有效的方式在上述过程中做到这一点?
编辑: 为了清楚起见,如果 dbo.Match
是函数而不是程序:
if @MotherFN is not null
begin
SELECT @constVal = FunctionWeight
FROM dbo.FunctionWeights
WHERE FunctionWeights.FunctionId = 20;
INSERT INTO #Temp2
(RowNumber,ValFromUser,ColumnName,ValFromFunc,FuncWeight,percentage)
SELECT RowId,
@MotherFN ,
'mothersfirstname'
,PercentMatch,
@constVal,
PercentMatch * @constVal
FROM dbo.MatchMatch(@MotherFN, 0)
end
就像我可以检索 Percentmatch
、@constval
的值并将它们相乘以插入 #Temp 一样,我如何在执行 dbo.Match
过程而不是调用时执行此操作dbo.Match
函数 ?
嗯,一般来说,如果您只需要做简单的事情,那么创建复杂的逻辑没有任何价值。在您描述的场景中,我倾向于认为最好的方法是使用物理 table,可以随时通过 dbo.Match 和 dbo.MatchMotherFirstName 过程访问。如果你不想在逻辑执行后将它留在数据库中,请根据需要使用 CREATE/DROP 语句到 CREATE/DROP table
您有 3 个足够简单的选项。一个有相当大的性能损失,一个需要在服务器上更新配置,一个需要更改匹配存储过程。
选项 1
在 MatchMotherFirstName 过程中为匹配结果声明一个 table。
CREATE TABLE #tmpMatchResults (Col1 , Col2....)
Insert into #tmpMatchResults
EXEC [dbo].[MATCH]
这会影响性能,但无需对 Match proc 代码或服务器配置进行任何更改即可运行。如果你只期望很少的行,这就可以了
选项 2
使用 OpenRowSet 或 OpenQuery
Select * FROM OPENROWSET(connection,'Exec database.dbo.MATCH')
这需要更改配置以允许数据访问
选项 3
更新 MATCH 存储过程以将结果推送到临时 table
CREATE Procedure [dbo].[MATCH]
--SOME CODE
select RowId, PercentMatch from #tmpMatches
确保不要在过程结束时降低温度 table
然后在您的 MatchMotherFirstName 过程中,当会话处于活动状态时,您可以调用该过程
EXEC dbo.MATCH @param
结果集
SELECT * FROM #tmpMatches
有些人会争辩说您应该在 MATCH proc 调用结束时清理(删除 table)温度 table。您可以在 MATCH 过程中包含一个参数以保留结果或执行 table 清理。
您有多种选择,从难以置信的简单到过于复杂。执行您描述的操作的最简单(也是最有效)的方法是:
不要这样做:只需在查询中包含该计算。为什么它需要在 table 定义中?
在创建临时 table 时添加一个计算列。这要求您还包含一个字段来存储“常量值”,以便它可以被计算列引用。如果计算有点昂贵 and/or 会有很多行并且经常从中选择(并且可能在 WHERE and/or ORDER BY 子句中使用),那么你可以使计算列 PERSISTED
这样它是根据 INSERT
和更新计算列中引用的字段的任何 UPDATE
计算的。
在创建 table 之后,在临时 table 添加一个计算列。这允许将“常量值”嵌入到计算列中,这样就不需要 [ConstantValue]
列。如果计算有点昂贵 and/or 会有很多行并且经常从中选择(并且可能在 WHERE and/or ORDER BY 子句中使用),那么你可以使计算列 PERSISTED
这样它是根据 INSERT
和更新计算列中引用的字段的任何 UPDATE
计算的。
P.S。以防万一您发现自己在问“为什么不一步而不是两步动态创建临时 table?”:在动态 SQL 中创建的本地临时 table 将不复存在在那个 Dynamic SQL 的 EXEC
之后。全局临时 table 将在动态 SQL 执行后继续存在,但随后 table 名称将在所有会话之间共享,因此同时执行此代码的另一个会话将在名称上出错冲突。在这种情况下,您需要通过 NEWID()
生成一个 GUID 以用作全局临时 table 名称,并将该值也连接到动态 SQL 中,但随后您将被要求将 Dynamic SQL 用于所有对全局温度 table 的引用(包括 INSERT...EXEC
),这只是徒劳无功。
测试设置
IF (OBJECT_ID(N'tempdb..#InnerProc') IS NOT NULL)
BEGIN
DROP PROCEDURE #InnerProc;
END;
GO
IF (OBJECT_ID(N'tempdb..#TempResults1') IS NOT NULL)
BEGIN
DROP TABLE #TempResults1;
END;
IF (OBJECT_ID(N'tempdb..#TempResults2') IS NOT NULL)
BEGIN
DROP TABLE #TempResults2;
END;
IF (OBJECT_ID(N'tempdb..#TempResults3') IS NOT NULL)
BEGIN
DROP TABLE #TempResults3;
END;
GO
CREATE PROCEDURE #InnerProc
AS
SET NOCOUNT ON;
SELECT TOP 20 so.[object_id], so.[modify_date]
FROM [master].[sys].[objects] so
ORDER BY so.[modify_date] DESC;
GO
选项 1
CREATE TABLE #TempResults1
(
[ObjectId] INT NOT NULL,
[ModifyDate] DATETIME NOT NULL
);
DECLARE @ConstantValue1 INT;
SET @ConstantValue1 = 13;
INSERT INTO #TempResults1 ([ObjectId], [ModifyDate])
EXEC #InnerProc;
SELECT 1 AS [Test], *, DATEADD(DAY, @ConstantValue1, [ModifyDate]) AS [SomeCalculation]
FROM #TempResults1;
选项 2
CREATE TABLE #TempResults2
(
[ObjectId] INT NOT NULL,
[ModifyDate] DATETIME NOT NULL,
[ConstantValue] INT NULL, -- will be added via UPDATE
[SomeCalculation] AS (DATEADD(DAY, [ConstantValue], [ModifyDate])) -- PERSISTED ??
);
INSERT INTO #TempResults2 ([ObjectId], [ModifyDate])
EXEC #InnerProc;
SELECT 2 AS [Test], * FROM #TempResults2;
UPDATE #TempResults2
SET [ConstantValue] = 13;
SELECT 2 AS [Test], * FROM #TempResults2;
选项 3
DECLARE @ConstantValue3 INT;
SET @ConstantValue3 = 13;
CREATE TABLE #TempResults3
(
[ObjectId] INT NOT NULL,
[ModifyDate] DATETIME NOT NULL
);
INSERT INTO #TempResults3 ([ObjectId], [ModifyDate])
EXEC #InnerProc;
SELECT 3 AS [Test], * FROM #TempResults3;
-- The next 3 lines could be done just after the CREATE TABLE and before the INSERT,
-- but doing it now allows for seeing the "before" and "after" with the data.
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'ALTER TABLE #TempResults3 ADD [SomeCalculation] AS (DATEADD(DAY, '
+ CONVERT(NVARCHAR(10), @ConstantValue3) + N', [ModifyDate])); --PERSISTED';
EXEC (@SQL);
SELECT 3 AS [Test], * FROM #TempResults3;
我有一个名为 dbo.Match
的存储过程。
看起来像这样:
CREATE Procedure [dbo].[MATCH]
@parameterFromUser nvarchar(30),
@checkbool int
As
Begin
--SOME CODE
select RowId,
PercentMatch
from @Matches
End
正在从另一个存储过程调用此过程:
CREATE Procedure MatchMotherFirstName
@MotherFN nvarchar(20) , @checkbool int
As begin
SELECT @constVal = FunctionWeight
FROM dbo.FunctionWeights
WHERE FunctionWeights.FunctionId = 20;
/*
Some code to execute `dbo.Match` procedure in above procedure called `MatchMotherFirstName` , retrieve `RowNumber` and `PercentMatch`,
Insert into #Temp in their respective fields , and calculate `PercentMatch * constVal`,
and insert in corresponding column called `percentage` in `#Temp`
*/
End
我需要在上面的过程中执行dbo.Match
存储过程,检索RowID
和PecrntMatch值,@constval
我们上面的值,乘以@constVal
和percentmatch
并将其存储在 #Temp
的 Percentage
列中,并将 dbo.Match procedure
的结果插入临时 table。 dbo.Match
returns 只有 RowId
和 PercentMatch
。
临时结构table:
create table #Temp
(
Rownumber int not null,
ValFromUser nvarchar(30),
ColumnName nvarchar(30),
ValFromFunc decimal(18, 4),
FuncWeight decimal(18, 4), -- @constVal here
Percentage decimal(18, 4) not null, -- calculated value here i.e (FuncWeight * ValFromFunc)
);
在 #Temp
中,我需要插入 @constVal
的值以及计算列并插入,即 PercentMatch * contVal
仅用于在此执行调用中插入的行。
我怎样才能以最有效的方式在上述过程中做到这一点?
编辑: 为了清楚起见,如果 dbo.Match
是函数而不是程序:
if @MotherFN is not null
begin
SELECT @constVal = FunctionWeight
FROM dbo.FunctionWeights
WHERE FunctionWeights.FunctionId = 20;
INSERT INTO #Temp2
(RowNumber,ValFromUser,ColumnName,ValFromFunc,FuncWeight,percentage)
SELECT RowId,
@MotherFN ,
'mothersfirstname'
,PercentMatch,
@constVal,
PercentMatch * @constVal
FROM dbo.MatchMatch(@MotherFN, 0)
end
就像我可以检索 Percentmatch
、@constval
的值并将它们相乘以插入 #Temp 一样,我如何在执行 dbo.Match
过程而不是调用时执行此操作dbo.Match
函数 ?
嗯,一般来说,如果您只需要做简单的事情,那么创建复杂的逻辑没有任何价值。在您描述的场景中,我倾向于认为最好的方法是使用物理 table,可以随时通过 dbo.Match 和 dbo.MatchMotherFirstName 过程访问。如果你不想在逻辑执行后将它留在数据库中,请根据需要使用 CREATE/DROP 语句到 CREATE/DROP table
您有 3 个足够简单的选项。一个有相当大的性能损失,一个需要在服务器上更新配置,一个需要更改匹配存储过程。
选项 1 在 MatchMotherFirstName 过程中为匹配结果声明一个 table。
CREATE TABLE #tmpMatchResults (Col1 , Col2....)
Insert into #tmpMatchResults
EXEC [dbo].[MATCH]
这会影响性能,但无需对 Match proc 代码或服务器配置进行任何更改即可运行。如果你只期望很少的行,这就可以了
选项 2 使用 OpenRowSet 或 OpenQuery
Select * FROM OPENROWSET(connection,'Exec database.dbo.MATCH')
这需要更改配置以允许数据访问
选项 3 更新 MATCH 存储过程以将结果推送到临时 table
CREATE Procedure [dbo].[MATCH]
--SOME CODE
select RowId, PercentMatch from #tmpMatches
确保不要在过程结束时降低温度 table
然后在您的 MatchMotherFirstName 过程中,当会话处于活动状态时,您可以调用该过程
EXEC dbo.MATCH @param
结果集
SELECT * FROM #tmpMatches
有些人会争辩说您应该在 MATCH proc 调用结束时清理(删除 table)温度 table。您可以在 MATCH 过程中包含一个参数以保留结果或执行 table 清理。
您有多种选择,从难以置信的简单到过于复杂。执行您描述的操作的最简单(也是最有效)的方法是:
不要这样做:只需在查询中包含该计算。为什么它需要在 table 定义中?
在创建临时 table 时添加一个计算列。这要求您还包含一个字段来存储“常量值”,以便它可以被计算列引用。如果计算有点昂贵 and/or 会有很多行并且经常从中选择(并且可能在 WHERE and/or ORDER BY 子句中使用),那么你可以使计算列
PERSISTED
这样它是根据INSERT
和更新计算列中引用的字段的任何UPDATE
计算的。在创建 table 之后,在临时 table 添加一个计算列。这允许将“常量值”嵌入到计算列中,这样就不需要
[ConstantValue]
列。如果计算有点昂贵 and/or 会有很多行并且经常从中选择(并且可能在 WHERE and/or ORDER BY 子句中使用),那么你可以使计算列PERSISTED
这样它是根据INSERT
和更新计算列中引用的字段的任何UPDATE
计算的。P.S。以防万一您发现自己在问“为什么不一步而不是两步动态创建临时 table?”:在动态 SQL 中创建的本地临时 table 将不复存在在那个 Dynamic SQL 的
EXEC
之后。全局临时 table 将在动态 SQL 执行后继续存在,但随后 table 名称将在所有会话之间共享,因此同时执行此代码的另一个会话将在名称上出错冲突。在这种情况下,您需要通过NEWID()
生成一个 GUID 以用作全局临时 table 名称,并将该值也连接到动态 SQL 中,但随后您将被要求将 Dynamic SQL 用于所有对全局温度 table 的引用(包括INSERT...EXEC
),这只是徒劳无功。
测试设置
IF (OBJECT_ID(N'tempdb..#InnerProc') IS NOT NULL)
BEGIN
DROP PROCEDURE #InnerProc;
END;
GO
IF (OBJECT_ID(N'tempdb..#TempResults1') IS NOT NULL)
BEGIN
DROP TABLE #TempResults1;
END;
IF (OBJECT_ID(N'tempdb..#TempResults2') IS NOT NULL)
BEGIN
DROP TABLE #TempResults2;
END;
IF (OBJECT_ID(N'tempdb..#TempResults3') IS NOT NULL)
BEGIN
DROP TABLE #TempResults3;
END;
GO
CREATE PROCEDURE #InnerProc
AS
SET NOCOUNT ON;
SELECT TOP 20 so.[object_id], so.[modify_date]
FROM [master].[sys].[objects] so
ORDER BY so.[modify_date] DESC;
GO
选项 1
CREATE TABLE #TempResults1
(
[ObjectId] INT NOT NULL,
[ModifyDate] DATETIME NOT NULL
);
DECLARE @ConstantValue1 INT;
SET @ConstantValue1 = 13;
INSERT INTO #TempResults1 ([ObjectId], [ModifyDate])
EXEC #InnerProc;
SELECT 1 AS [Test], *, DATEADD(DAY, @ConstantValue1, [ModifyDate]) AS [SomeCalculation]
FROM #TempResults1;
选项 2
CREATE TABLE #TempResults2
(
[ObjectId] INT NOT NULL,
[ModifyDate] DATETIME NOT NULL,
[ConstantValue] INT NULL, -- will be added via UPDATE
[SomeCalculation] AS (DATEADD(DAY, [ConstantValue], [ModifyDate])) -- PERSISTED ??
);
INSERT INTO #TempResults2 ([ObjectId], [ModifyDate])
EXEC #InnerProc;
SELECT 2 AS [Test], * FROM #TempResults2;
UPDATE #TempResults2
SET [ConstantValue] = 13;
SELECT 2 AS [Test], * FROM #TempResults2;
选项 3
DECLARE @ConstantValue3 INT;
SET @ConstantValue3 = 13;
CREATE TABLE #TempResults3
(
[ObjectId] INT NOT NULL,
[ModifyDate] DATETIME NOT NULL
);
INSERT INTO #TempResults3 ([ObjectId], [ModifyDate])
EXEC #InnerProc;
SELECT 3 AS [Test], * FROM #TempResults3;
-- The next 3 lines could be done just after the CREATE TABLE and before the INSERT,
-- but doing it now allows for seeing the "before" and "after" with the data.
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'ALTER TABLE #TempResults3 ADD [SomeCalculation] AS (DATEADD(DAY, '
+ CONVERT(NVARCHAR(10), @ConstantValue3) + N', [ModifyDate])); --PERSISTED';
EXEC (@SQL);
SELECT 3 AS [Test], * FROM #TempResults3;