Technical Article

Smart data archiving stored procedure

,

This stored procedure uses a series of input parametes to generate, and optionally execute a series of SQL commands to move production data to an archive table.  The procedure assumes that the production and archive tables will have the same structure. 

The procedure uses the following input parameters:

@SourceTable:  This is the name of the table containing the production data to be archived.

@DestinationTable: This is the name of the archive table where data will be moved to.

@CutOffInterval:  This is the number of days/weeks/years to keep in the production table.

@CutOffType:  This defines what the value of @CutOffInterval represents, days/weeks/years.  Must be a valid datepart argument for the DATEADD function.

@DateColumnName:  This is the name of a datetime column in the source table that is used to determine which records to archive.

@PrintOnly:  Indicates whether to only print the generated SQL command (1) or to execute it as well (0).  Note that the default value is 1, print only.

This procedure has been tested on SQL 2000.  I'm guessing it would work on SQL 2005 but I don't have the environment to test it.  Also assumes that the source and destination tables are in the same database as the stored procedure.  See comments in the procedure and the script header for more information on what's going on.  Hope someone else finds this useful.

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[ArchiveData]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[ArchiveData]
GO

SET QUOTED_IDENTIFIER ON 
GO
SET ANSI_NULLS ON 
GO

/*
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
Stored Procedure dbo.ArchiveData

Created:  04/24/2007

Description:  This stroed procedure dynamically creates a SQL statement to archive data
from a production table to an archive table.  This assumes that the structure of the source
and destination tables are identical.  The SQL statement is constructed by retrieving the
column list for the tables from syscolumns (excluding computed columns).  The columns are
then appended into a single string via a cursor over the columns result set.  This string is
used to create a SQL statement in the following format:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION

INSERT INTO <destination table> (<column list>)
SELECT <column list>
FROM <source table>
WHERE <date column name> < <cut off date>

DELETE FROM <source table>
WHERE <date column name> < <cut off date>

IF @@ERROR = 0
  BEGIN
    COMMIT TRANSACTION
  END
ELSE
  BEGIN
    ROLLBACK TRANSACTION
  END

The generated SQL string is then executed via sp_executesql.

The procedure requires the following input parameters:

@SourceTable sysname - This is the table the data is archived from

@DestinationTable sysname - This is the table where the data is archived to

@CutOffInterval int - The number of days/months/years used to determine which records to archive

@CutOffType varchar(4) - The type of value specified in the @CutOffInterval variable.  This must be
                         a valid date part value for the DATEADD funtion (yy,m,d, etc)

@DateColumnName sysname - This is the name of the datetime column in the source table used to
                          determine which records are archived.  All records with a value in
                          this column less than the datetime calculated by the @CutOffInterval
                          and @CutOffType variables will be archived.

@PrintOnly bit - Indicates the procedure should generate and print the SQL commands to archive
                 but not actually execute them.  Useful if you want to customize the commands.  Note
                 that the default on this parameter is 1, so explicitly set to 0, this proc will only
                 print the SQL command, it will not execute it.

Revision History:

04/24/2007  Chris HouseInitial creation

---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
 */CREATE PROCEDURE dbo.ArchiveData

(
@SourceTable sysname,
@DestinationTable sysname,
@CutOffInterval int,
@CutOffType varchar(4),
@DateColumnName sysname,
@PrintOnly bit = 1
)

AS

DECLARE @SQL nvarchar(4000)  -- The SQL commands that will be executes
DECLARE @ColumnList varchar(4000)  -- The list of columns in the source and destination tables
DECLARE @Column sysname  -- The current column in the cursor loop
DECLARE @CRLF nvarchar(20)  -- CRLF to make the generated SQL look pretty when it's printed
DECLARE @CutOffSQL nvarchar(500)  -- Holds a SQL command that generates the cut off date
DECLARE @CutOffSQLParamList nvarchar(100)  -- The parameter list passed into sp_executesql when generating the cut off date time
DECLARE @CutOffDate nvarchar(20)  -- The cut off date, generated by using DATEADD with the @CutOffInterval and @CutOffType parameters

-- First we build a SQL string that when executed, will give us a datetime to use as the cut off, to determine which records are archived
SET @CutOffSQL = N'SELECT @CutOffDate = CONVERT(varchar(20),DATEADD(' + @CutOffType + ', -ABS(' + CAST(@CutOffInterval AS nvarchar(10)) + '), GETDATE()),100)'
SET @CutOffSQLParamList = N'@CutOffDate nvarchar(20) OUTPUT'
EXEC sp_executesql @CutOffSQL, @CutOffSQLParamList, @CutOffDate OUTPUT

SET @CRLF = CHAR(13) + CHAR(10)
SET @ColumnList = ''

-- Now we get a cursor of all columns in the source table, excluding computed colums
DECLARE column_cursor CURSOR FAST_FORWARD
FOR
SELECT SC.name
FROM syscolumns SC
INNER JOIN sysobjects SO ON SC.id = SO.id
WHERE ((SO.name = @SourceTable) AND (SC.iscomputed = 0))
ORDER BY SC.colorder

OPEN column_cursor

-- Next we loop through the cursor and create a list of columns that will be used in the INSERT and SELECT statements
FETCH NEXT FROM column_cursor INTO @Column

WHILE @@FETCH_STATUS = 0
  BEGIN
    SET @ColumnList = @ColumnList + QUOTENAME(@Column) + ','
    FETCH NEXT FROM column_cursor INTO @Column
  END

CLOSE column_cursor
DEALLOCATE column_cursor

-- Clean up the trailing comma on the column list
SET @ColumnList = SUBSTRING(@ColumnList,1,LEN(@ColumnList) - 1)

-- And now we build the SQL commands, complete with transaction handling
SET @SQL = 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE' + @CRLF
SET @SQL = @SQL + 'BEGIN TRANSACTION' + @CRLF
SET @SQL = @SQL + 'INSERT INTO ' + @DestinationTable + ' (' + @ColumnList + ')' + @CRLF
SET @SQL = @SQL + 'SELECT ' + @ColumnList + @CRLF
SET @SQL = @SQL + 'FROM ' + @SourceTable + @CRLF
SET @SQL = @SQL + 'WHERE ' + @DateColumnName + ' < ''' + @CutOffDate + '''' + @CRLF
SET @SQL = @SQL + 'DELETE FROM ' + @SourceTable + @CRLF
SET @SQL = @SQL + 'WHERE ' + @DateColumnName + ' < ''' + @CutOffDate + '''' + @CRLF
SET @SQL = @SQL + 'IF @@ERROR = 0' + @CRLF
SET @SQL = @SQL + '  BEGIN' + @CRLF
SET @SQL = @SQL + '    COMMIT TRANSACTION' + @CRLF
SET @SQL = @SQL + '  END' + @CRLF
SET @SQL = @SQL + 'ELSE' + @CRLF
SET @SQL = @SQL + '  BEGIN' + @CRLF
SET @SQL = @SQL + '    ROLLBACK TRANSACTION' + @CRLF
SET @SQL = @SQL + '  END' + @CRLF
PRINT @SQL

-- And finally, If @PrintOnly = 0, we execute the commands, otherwise the command string
-- will just be printed
IF @PrintOnly = 0
  BEGIN
    EXEC sp_executesql @SQL
  END




GO
SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

Rate

Share

Share

Rate