0

我有一个有 4 列的表:

Col1  Col2      Col3       Col4
1      2      Col1+Col2     3
3      4      Col1*Col2     12
6      3      Col1/Col2     2

Col1, Col2 会有一些值,col3 会有一个公式,基于该公式我需要在 col4 中填充值。我已经尝试使用动态 SQL 逐行运行,但我的表中有数百万条记录,并且执行脚本需要很长时间。请提出处理这种情况的最简单和最快的方法。

4

4 回答 4

0

如果在 +,-,/,* 列中只有一个运算符,则可以为每个运算符编写更新查询

根据数据的分布,首先批量解决简单的操作,将加快处理速度


-- Bulk operation for Col1 * Col2
UPDATE Table
    Set Col4 = Col1 * Col2
WHERE LEN(Col4) - LEN(REPLACE(Col4, '*', '')) = 1 -- Only has one *
AND Like 'Col1%'
AND Like '%Col2'
-- Doesn't have other operator
AND NOT LIKE '%+%'
AND NOT LIKE '%*%'
AND NOT LIKE '%/%'

如果您有多个列/组合,则可以使用T4生成这些查询。

对于多个运算符,您将需要一个解析器,因为您需要注意运算符和其他规则的顺序。

于 2020-07-08T11:52:35.360 回答
0

col3如果SQL Server 可以理解和执行其中的表达式在语法上是正确的,则可以使用动态 SQL。CASE使用表达式创建查询。在 case 表达式中,每个分支检查字符串值col3并返回相应的表达式。您只需要与不同表达式一样多的分支。

DECLARE @query nvarchar(MAX);

SELECT @query = concat('UPDATE elbat', nchar(13), nchar(10),
                       '       SET col4 = CASE', nchar(13), nchar(10),
                       (SELECT DISTINCT
                               concat('                    WHEN col3 = ''', col3, '''', nchar(13), nchar(10),
                                      '                      THEN ', col3, nchar(13), nchar(10)) [text()]
                               FROM elbat
                               FOR XML PATH(''),
                                       TYPE).value('.', 'nvarchar(max)'),
                       '                  END;')
       WHERE EXISTS (SELECT *
                            FROM elbat);

PRINT @query;

EXEC(@query);

db<>小提琴

于 2020-07-12T13:55:21.240 回答
0

这是适合使用游标的(非常)罕见的情况之一。事实上,这相当复杂——一个可更新的游标以及动态 SQL。

这是想法:

declare @col1 int;
declare @col2 int;
declare @col3 nvarchar(max);
declare @sql nvarchar(max);
declare @col4 int;


DECLARE c CURSOR
FOR SELECT col1, col2, col3 FROM t FOR UPDATE;

OPEN c;

FETCH NEXT FROM c INTO @col1, @col2, @col3;

WHILE @@fetch_status = 0
BEGIN
    set @sql = 'select @col4=[col3] from (select @col1 as col1, @col2 as col2) t';
    
    set @sql = replace(@sql, '[col3]', @col3);
    
    exec sp_executesql @sql, N'@col1 int, @col2 int, @col4 int output',
                       @col1=@col1, @col2=@col2, @col4=@col4 output;

    SELECT @col1, @col2, @col3, @col4;
    
    UPDATE t
        set col4 = @col4
        WHERE current of c;
    
    FETCH NEXT FROM c INTO @col1, @col2, @col3;
END;

CLOSE c;
DEALLOCATE c;

这是一个 db<>fiddle

请注意,这不会很快。在这样的查询上获得性能是相当困难的,但是您可以将表分成块并使用单独的线程更新每个块。

于 2020-07-08T12:36:32.047 回答
0

您可以更改方法并在基于集合的模式下工作,也可以使用 C# 等编程语言

通过运行总查询,您可以计算数据的分布并使用 x 记录块以通过 Col3 更新。为了不进行锁升级,我建议一次使用 1000 行。运行总查询的示例:

https://codingsight.com/calculating-running-total-with-over-clause-and-partition-by-clause-in-sql-server/

现在,您可以在 C# 循环或其他编程语言中使用 Col3 作为条件以相等的块(之前计算)更新 Col4(您也可以在 SQL 中使用 while 循环,但不推荐)

PS 在运行该过程之前检查您的索引

于 2020-07-08T12:57:43.543 回答