簡體   English   中英

根據另一列 Sql 服務器中給出的公式更新表中的列

[英]Update a column in table based on formula given in another column Sql Server

我有一個有 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 逐行工作,但我的表中有數百萬條記錄,並且執行腳本需要很長時間。 請提出處理這種情況的最簡單和最快的方法。

如果在 +,-,/,* 列中只有一個運算符,則可以為每個運算符編寫更新查詢

根據數據的分布,首先批量解決簡單的操作,將加快處理速度


-- 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生成這些查詢。

對於多個運算符,您將需要一個解析器,因為您需要注意運算符和其他規則的順序。

這是 cursor 適合的(非常)罕見的情況之一。 事實上,這相當復雜——一個可更新的 cursor 以及動態 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。

請注意,這不會很快。 在這樣的查詢上獲得性能是相當困難的,但是您可以將表分成塊並使用單獨的線程更新每個塊。

您可以更改方法並在基於集合的模式下工作,也可以使用編程語言 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 在運行該過程之前檢查您的索引

如果col3中的表達式在語法上正確,SQL 服務器可以理解並執行它們,則可以使用動態 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<>小提琴

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM