我有一个像这样的数据库表
Id Code Amount Formula
-------------------------------------
1 A01 20.00
2 A08 0.00 dbo.ufn_Test(40)
3 A03 0.00 dbo.ufn_Test(60)
我的Formula
列是一个字符串,其名称作为我的数据库中的函数,如何将结果返回到Amount
列?
我的表有大约100000行,所以当我使用while()
时,需要花费很多时间。
我正在使用SQL Server 2012
我使用了这样的动态SQL:
DECLARE @_j INT = 1
WHILE (@_j<=(SELECT MAX(Id) FROM #Ct_Lv))
BEGIN
SET @_CtLv = (SELECT Formula FROM #Ct_Lv WHERE Id = @_j)
DECLARE @sql NVARCHAR(MAX)
DECLARE @result NUMERIC(18, 2) = 0
SET @sql = N'set @result = N''''SELECT''' + @_CtLv
EXEC sp_executesql @sql, N'@result float output', @result out
UPDATE #Ct_Lv
SET Amount = @result
WHERE Id = @_j
SET @_j = @_j + 1
END
但是我的最大@_j = 100000,我运行了3个小时的代码并且它仍在运行
答案 0 :(得分:0)
有一件事,我想知道的是,id属性是标识列吗?
第二个最重要的部分是,您为每一行声明变量@sql和@result,并且您在每行迭代时获取最大值,这可能会降低性能。我不确定,我在这里给出的解决方案速度有多快,但你可以尝试一次。
Set Nocount On;
Declare @_count Int
,@_j Int
,@_cnt Int
,@_dynamicSql Varchar(Max)
,@_formula Varchar(Max)
,@_row25Cnt Int
Select @_count = Count(1)
,@_j = 0
,@_cnt = 0
,@_dynamicSql = ''
,@_formula = ''
,@_row25Cnt = 1
From #Ct_Lv As ct With (Nolock)
While (@_cnt < @_count)
Begin
Select Top 1
@_j = ct.Id
,@_formula = ct.Formula
From #Ct_Lv As ct With (Nolock)
Where ct.Id > @_j
Order By ct.Id Asc
Select @_dynamicSql = 'Update ct Set ct.Amount = f.result From #Ct_Lv As ct Join ( Select ' + Cast(@_j As Varchar(20)) + ' As Id, [fuctionResultAttribute] As result From ' + @_formula + ' ) As f On ct.Id = f.Id; '
If (@_row25Cnt = 25)
Begin
Exec (@_dynamicSql)
Select @_dynamicSql = ''
,@_row25Cnt = 0
End
Else If ((@_cnt + 1) = @_count)
Begin
Exec (@_dynamicSql)
Select @_dynamicSql = ''
,@_row25Cnt = 0
End
Select @_cnt = @_cnt + 1
,@_row25Cnt = @_row25Cnt + 1
End
在这里,我到目前为止所做的是,我通过Id循环Id并为每25行生成动态sql,一旦count达到25,将执行动态sql将更新你的金额。然后再次开始为接下来的25行生成动态sql,当count即将结束并且没有25行作为结束时,动态sql将在循环即将结束时执行,否则如果&#39;条件。
只有在每一行的公式列中只有一个公式时,我的解决方案上面的才会起作用。
答案 1 :(得分:0)
我只是建议如果Formula
字段每次调用相同的函数,那么最好只存储要传递给函数的参数,然后就可以轻松处理大量数据。
其他循环遍历大数据并不是执行任何操作的首选方法。因此,建议在表结构中使用其他技巧并存储数据。