不要试图找出所有不同的变化...只需取出所有不符合所需模式的值并去掉所有非数字字符,留下 6 个数字,所有数字都在正确的位置。在那里形成,只需使用 STUFF 函数将冒号放在它们所属的位置。
SET NOCOUNT ON;
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
DROP TABLE #TestData;
CREATE TABLE #TestData (
TimeVal VARCHAR(20)
);
INSERT #TestData (TimeVal) VALUES
('23:44:33'),
('12:17 09'),
('20 00 20'),
(' : : '),
('111913'),
('12:17'),
('12: 09'),
(' :17 09');
-- before values...
SELECT [Before] = td.TimeVal FROM #TestData td;
-- update problem values...
UPDATE td SET
td.TimeVal = CASE LEN(rr.TimeVal)
WHEN 6 THEN STUFF(STUFF(rr.TimeVal, 5, 0, ':'), 3, 0, ':')
ELSE '21:12:00'
END
FROM
#TestData td
CROSS APPLY ( VALUES (REPLACE(REPLACE(td.TimeVal, ' ', ''), ':', '')) ) rr (TimeVal)
WHERE
td.TimeVal NOT LIKE '[0-9][0-9]:[0-9][0-9]:[0-9][0-9]';
-- after values...
SELECT [After] = td.TimeVal FROM #TestData td;
结果前后...
Before
--------------------
23:44:33
12:17 09
20 00 20
: :
111913
12:17
12: 09
:17 09
After
--------------------
23:44:33
12:17:09
20:00:20
21:12:00
11:19:13
21:12:00
21:12:00
21:12:00
至于如何最好地针对 90M 行执行此操作...很难说如果不了解您的环境的更多信息。什么是恢复模式?你的服务器规格是什么?非聚集索引如何包含此列?
和你一起去 DBA,他/她会比任何人都知道数据库将如何处理更新......另外,如果你通过填充日志文件和/或 tempdb 锁定实例,他们会为你而来驱动器。你希望他们参与进来。
也就是说,我会同意其他人建议将其分成几块的观点。当我必须对大型表进行大规模更新时,我使用类似的循环过程并将进度记录到一个简单的日志表中,以便 1)我可以在进度进行时跟踪进度,并且 2)我知道最后提交的事务集如果我需要关闭它,稍后再关闭。
类似下面的...
-- create a log table to make it easy to know where you arw in the update process.
CREATE TABLE dbo.TimeValUpdate_LOG (
BegID INT,
EndID INT,
RowsUpdated INT,
BegTime DATETIME,
EndTime DATETIME,
SecsToComplete AS DATEDIFF(SECOND, BegTime, EndTime)
);
-- update script...
DECLARE
@BegID INT = 0,
@EndID INT = 500000,
@BegTime DATETIME,
@EndTime DATETIME;
WHILE EXISTS (SELECT 1 FROM dbo.RealTable rt WHERE rt.PrimaryKey > @BegID)
BEGIN
BEGIN TRY
BEGIN TRANSACTION;
--===================================
SET @BegTime = CURRENT_TIMESTAMP;
INSERT dbo.TimeValUpdate_LOG (BegID, EndID, BegTime) VALUES (@BegID, @EndID, @BegTime);
--=============================================================================
-- update problem values...
UPDATE rt SET
rt.TimeVal = CASE LEN(rr.TimeVal)
WHEN 6 THEN STUFF(STUFF(rr.TimeVal, 5, 0, ':'), 3, 0, ':')
ELSE '21:12:00'
END
FROM
dbo.RealTable rt
CROSS APPLY ( VALUES (REPLACE(REPLACE(rt.TimeVal, ' ', ''), ':', '')) ) rr (TimeVal)
WHERE
rt.PrimaryKey >= @BegID
AND rt.PrimaryKey < @EndID
AND rt.TimeVal NOT LIKE '[0-9][0-9]:[0-9][0-9]:[0-9][0-9]';
--=============================================================================
UPDATE tul SET
tul.RowsUpdated = @@ROWCOUNT,
tul.EndTime = CURRENT_TIMESTAMP
FROM
dbo.TimeValUpdate_LOG tul
WHERE
tul.BegID = @BegID
AND tul.EndID = @EndID;
--===================================
SET @BegID = @EndID + 1;
SET @EndID = @BegID + 500000;
--===================================
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
DECLARE @ErrorNumber INT = ERROR_NUMBER();
DECLARE @ErrorLine INT = ERROR_LINE();
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
DECLARE @ErrorState INT = ERROR_STATE();
PRINT 'Actual error number: ' + CAST(@ErrorNumber AS VARCHAR(10));
PRINT 'Actual line number: ' + CAST(@ErrorLine AS VARCHAR(10));
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH;
END;