有时工作需要需要把当前表的数据,移到历史表中,而历史表基本是以时间(年)为后缀来命名历史表的,如 A_2011,A_2012,在移数据时,要按数据的时间,移到不同的表中,且由于如果数据有同步。一次处理的数据不能太大。否则同步链会被Block.所以需要批理处理。
下面是一个通用的写法,可以作为参考!(这个应该是出自邹建大侠之手,因为需要写这样的处理,去找了下类似代码,找到的)
-- row batch: 100
-- row Process limit: 50000
-- data keep days: 90
-- */
CREATE PROCEDURE dbo.TransferNInvoiceToHistoryBeforeDay
@FromDate char(10)
AS
SET NOCOUNT ON;
-- current trancount
DECLARE
@__trancount int;
SELECT
@__trancount = @@TRANCOUNT;
BEGIN TRY
DECLARE
@row_batch int,
@row_limit int,
@row_process int,
@row_count int,
@date_begin datetime,
@date_end datetime;
-- row batch and data keep date
SELECT
@row_batch = 100, -- each batch process rows
@row_limit = 50000, -- total row process limit
@date_end = @FromDate,--DATEDIFF(Day, 90, GETDATE()), -- process top date
@row_process = 0; -- process rows total
-- ===========================================
-- get process begin date and rows
SELECT
@date_begin = MIN(InvoiceDate),
@row_count = COUNT(*)
FROM 需要处理的当前表名 WITH(NOLOCK)
WHERE InvoiceDate < @date_end;
IF @row_count = 0
RETURN;
ELSE IF @date_begin IS NULL
BEGIN
RAISERROR(N'column InvoiceDate include NULL value, please fix it', 16, 1)
END
IF @row_limit IS NULL OR @row_limit <= 0
SET @row_limit = @row_count;
RAISERROR('%d rows need process, current process limit %d rows', 10, 1, @row_count, @row_limit) WITH NOWAIT
-- ===========================================
-- process by year
DECLARE
@date datetime;
SET @date = @date_begin;
WHILE @row_process < @row_limit
AND @date < @date_end
BEGIN
-- process date and sql
DECLARE
@sql nvarchar(4000),
@_date_begin datetime,
@_date_end datetime;
SELECT
@_date_begin = @date,
@_date_end = CASE
WHEN DATEDIFF(Year, @_date_begin, @date_end) = 0 THEN @date_end
ELSE DATEADD(Year, YEAR(@_date_begin) - 1899, 0)
END,
@date = @_date_end,
@row_count = @row_batch,
@sql = N'
DECLARE @tb_id TABLE(
invoiceNumber int
PRIMARY KEY
);
INSERT @tb_id
SELECT TOP(@row_batch)
invoiceNumber
FROM Nact.dbo.NewEgg_InvoiceMaster A
WHERE InvoiceDate >= @_date_begin
AND InvoiceDate < @_date_end;
DELETE A
OUTPUT deleted.*
INTO 历史表名不带时间部份' + RTRIM(Year(@_date_begin)) + N'
FROM 当前表名 A,
@tb_id B
WHERE A.invoiceNumber = B.invoiceNumber;
';
-- ===========================================
-- process by batch for year
WHILE @row_process < @row_limit
AND @row_count = @row_batch
BEGIN
-- move data
IF @__trancount = 0
BEGIN TRAN;
ELSE
SAVE TRAN __TRAN_SavePoint;
EXEC sys.sp_executesql
@sql,
N'
@row_batch int,
@_date_begin datetime,
@_date_end datetime
',
@row_batch, @_date_begin, @_date_end;
SELECT
@row_count = @@ROWCOUNT,
@row_process = @row_process + @row_count;
IF XACT_STATE() = 1 AND @__trancount = 0
COMMIT;
END
END
IF @__trancount = 0
BEGIN
IF XACT_STATE() = -1
ROLLBACK TRAN;
ELSE
BEGIN
WHILE @@TRANCOUNT > 0
COMMIT TRAN;
END
END
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
BEGIN
IF @__trancount = 0
ROLLBACK TRAN;
ELSE IF XACT_STATE() = 1 AND @@TRANCOUNT > @__trancount
ROLLBACK TRAN __TRAN_SavePoint;
END
DECLARE
@__error_number int,
@__error_message nvarchar(2048),
@__error_severity int,
@__error_state int,
@__error_line int,
@__error_procedure nvarchar(126),
@__user_name nvarchar(128),
@__host_name nvarchar(128);
SELECT
@__error_number = ERROR_NUMBER(),
@__error_message = ERROR_MESSAGE(),
@__error_severity = ERROR_SEVERITY(),
@__error_state = ERROR_STATE(),
@__error_line = ERROR_LINE(),
@__error_procedure = ERROR_PROCEDURE(),
@__user_name = SUSER_SNAME(),
@__host_name = HOST_NAME();
RAISERROR(
N'User: %s, Host: %s, Procedure: %s, Error %d, Level %d, State %d, Line %d, Message: %s ',
@__error_severity,
1,
@__user_name,
@__host_name,
@__error_procedure,
@__error_number,
@__error_severity,
@__error_state,
@__error_line,
@__error_message);
END CATCH
GO