我有一个名为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
并将其存储在Percentage
的{{1}}列中,并将#Temp
的结果插入临时表中。 dbo.Match procedure
仅返回dbo.Match
和RowId
。
临时表的结构:
PercentMatch
在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
的值并将它们两者相乘以插入#Temp一样,我在执行@constval
过程时如何执行此操作而不是调用{{ 1}}功能?
答案 0 :(得分:1)
您有多种选择,从难以置信的容易到过于复杂。做你所描述的最简单(也是最有效)的方法是:
不要这样做:只需在查询中包含该计算。为什么需要在表定义中?
在创建临时表时添加计算列。这要求您还包含一个字段来存储"常数值"这样它就可以被计算列引用。如果计算有点昂贵和/或会有很多行并且经常从(并且可能在WHERE和/或ORDER BY子句中使用)中选择,那么您可以创建计算列PERSISTED
以便计算它在INSERT
以及更新计算列中引用的字段的任何UPDATE
。
在创建表后,在临时表中添加计算列。这允许嵌入"常数值"进入计算列,这样就不需要[ConstantValue]
列。如果计算有点昂贵和/或会有很多行并且经常从(并且可能在WHERE和/或ORDER BY子句中使用)中选择,那么您可以创建计算列PERSISTED
以便计算它在INSERT
和任何UPDATE
更新计算列中引用的字段。
P.S。万一你发现自己要求"为什么不只是一步而不是两步动态创建临时表?":在{{1}之后,动态SQL中创建的本地临时表将不复存在那个动态SQL。全局临时表将在执行动态SQL后继续存在,但随后表名将在所有会话中共享,因此同时执行此代码的另一个会话将在名称冲突时出错。在这种情况下,您需要通过EXEC
生成GUID以用作全局临时表名称,并将该值连接到动态SQL中,但是您将无法使用动态SQL进行所有引用全局临时表(包括NEWID()
),这只是更有效的工作。
测试设置
INSERT...EXEC
选项1
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
选项2
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;
选项3
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;
答案 1 :(得分:0)
嗯,总的来说,如果你只需要做简单的事情就没有创造复杂逻辑的价值。在您描述的场景中,我倾向于认为最好的方法是使用可以随时通过dbo.Match和dbo.MatchMotherFirstName过程访问的物理表。如果您不想在逻辑执行后将其保留在数据库中,请使用CREATE / DROP语句根据您的需要创建/删除表。
答案 2 :(得分:0)
你有3个足够简单的选择。其中一个具有相当大的性能,一个需要在服务器上进行配置更新,一个需要更改匹配存储过程。
选项1 在MatchMotherFirstName过程中,为匹配结果声明一个表。
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存储过程以将结果推送到临时表
CREATE Procedure [dbo].[MATCH]
--SOME CODE
select RowId, PercentMatch from #tmpMatches
请确保不要将临时表放在proc
的末尾然后在MatchMotherFirstName过程中,当会话处于活动状态时,您可以调用proc
EXEC dbo.MATCH @param
,结果设置为
SELECT * FROM #tmpMatches
有些人会争辩说你应该在MATCH proc调用结束时清理(删除表)临时表。您可以在MATCH过程中包含一个参数来保存结果或进行表清理。