在存储过程之间共享数据

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我们上面的值,乘以@constValpercentmatch 并将其存储在 #TempPercentage 列中,并将 dbo.Match procedure 的结果插入临时 table。 dbo.Match returns 只有 RowIdPercentMatch

临时结构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 清理。

您有多种选择,从难以置信的简单到过于复杂。执行您描述的操作的最简单(也是最有效)的方法是:

  1. 不要这样做:只需在查询中包含该计算。为什么它需要在 table 定义中?

  2. 在创建临时 table 时添加一个计算列。这要求您还包含一个字段来存储“常量值”,以便它可以被计算列引用。如果计算有点昂贵 and/or 会有很多行并且经常从中选择(并且可能在 WHERE and/or ORDER BY 子句中使用),那么你可以使计算列 PERSISTED 这样它是根据 INSERT 和更新计算列中引用的字段的任何 UPDATE 计算的。

  3. 在创建 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;