[英]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 行。 運行總查詢的示例:
現在,您可以在 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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.