Listing 1: T-SQL Code That Automates the Creation of a Stored Procedure to Perform a Table Update BEGIN CALLOUT A IF OBJECTPROPERTY(OBJECT_ID(N'[dbo].[sp_CreateUpdateProc]'), N'IsProcedure') = 1 DROP PROCEDURE [dbo].[sp_CreateUpdateProc] GO SET QUOTED_IDENTIFIER ON GO SET ANSI_NULLS ON GO END CALLOUT A BEGIN CALLOUT B CREATE PROCEDURE [dbo].[sp_CreateUpdateProc] @TABLE_NAME [nvarchar] (128) , @TABLE_SCHEMA SYSNAME='DBO' AS /* ** ** sp_CreateUpdateProc 'authors', 'dbo' ** */ END CALLOUT B BEGIN CALLOUT C SET NOCOUNT ON DECLARE @RowNo int, @pRowNo int, @lastRow int, @PK_Flag int, @FirstLine int DECLARE --- @TABLE_SCHEMA SYSNAME , @COLUMN_NAME SYSNAME , @DATA_TYPE SYSNAME , @TABLE_TYPE SYSNAME , @MSG [nvarchar] (128) , @CHARACTER_MAXIMUM_LENGTH [int] , @NUMERIC_PRECISION [tinyint] , @NUMERIC_SCALE [int] , @DATETIME_PRECISION [smallint] DECLARE @ln [nvarchar] (255), @objectname SYSNAME, @sWhere [nvarchar] (255), @ProcName SYSNAME IF @TABLE_SCHEMA IS NULL SET @TABLE_SCHEMA = 'dbo' END CALLOUT C BEGIN CALLOUT D SET @objectname = '[' + @TABLE_SCHEMA + '].[' + @TABLE_NAME + ']' IF OBJECT_ID( @objectname ) IS NULL BEGIN SET @MSG = 'OBJECT ' + RTRIM( @objectname ) + ' DOES NOT EXIST ' RAISERROR (@MSG , 16, 1) RETURN (-1) END END CALLOUT D BEGIN CALLOUT E IF OBJECTPROPERTY(OBJECT_ID( @objectname ), N'IsProcedure') = 1 BEGIN SET @MSG = 'OBJECT ' + RTRIM( @objectname ) + ' IS NOT A TABLE ' RAISERROR (@MSG , 16, 1) RETURN (-1) END END CALLOUT E BEGIN CALLOUT F CREATE TABLE #TB_SCHEMA ( [RowNo] [int] NOT NULL , [TABLE_SCHEMA] SYSNAME NOT NULL, [TABLE_NAME] SYSNAME NOT NULL, [COLUMN_NAME] SYSNAME NOT NULL, [IsIdentity] [int] NOT NULL , [PK_Flag] [int] DEFAULT(0) , [DATA_TYPE] SYSNAME NOT NULL, [CHARACTER_MAXIMUM_LENGTH] [int] NULL , [NUMERIC_PRECISION] [tinyint] NULL , [NUMERIC_SCALE] [int] NULL , [DATETIME_PRECISION] [smallint] NULL ) END CALLOUT F BEGIN CALLOUT G INSERT #TB_SCHEMA (RowNo ,TABLE_SCHEMA , TABLE_NAME , COLUMN_NAME , IsIdentity , PK_Flag , DATA_TYPE , CHARACTER_MAXIMUM_LENGTH , NUMERIC_PRECISION , NUMERIC_SCALE , DATETIME_PRECISION) SELECT ORDINAL POSITION ,TABLE_SCHEMA , TABLE_NAME , COLUMN_NAME , COLUMNPROPERTY(OBJECT_ID(TABLE_NAME), COLUMN_NAME, 'IsIdentity' ) AS IsIdentity , 0 , DATA_TYPE , CHARACTER_MAXIMUM_LENGTH , NUMERIC_PRECISION , NUMERIC_SCALE , DATETIME_PRECISION FROM INFORMATION_SCHEMA.COLUMNS WHERE [TABLE_NAME] = @TABLE_NAME AND [TABLE_SCHEMA] = @TABLE_SCHEMA END CALLOUT G BEGIN CALLOUT H UPDATE #TB_SCHEMA SET PK_Flag = 1 WHERE EXISTS (SELECT * FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc ON cu.TABLE_CATALOG = tc.TABLE_CATALOG AND cu.TABLE_SCHEMA = tc.TABLE_SCHEMA AND cu.TABLE_NAME = tc.TABLE_NAME AND cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME WHERE cu.TABLE_NAME = #TB_SCHEMA.TABLE_NAME AND cu.TABLE_SCHEMA = #TB_SCHEMA.TABLE_SCHEMA AND cu.COLUMN_NAME = #TB_SCHEMA.COLUMN_NAME AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY') END CALLOUT H BEGIN CALLOUT I IF NOT EXISTS(SELECT * FROM #TB_SCHEMA WHERE PK_Flag = 1) BEGIN SET @MSG = 'OBJECT ' + RTRIM(@TABLE_NAME) + ' DOES NOT HAVE A PRIMARY KEY ' RAISERROR (@MSG , 16, 1) RETURN (-1) END END CALLOUT I BEGIN CALLOUT J DELETE FROM #TB_SCHEMA WHERE (IsIdentity = 1 AND PK_Flag = 0) OR DATA_TYPE IN ('text', 'ntext', 'image', 'timestamp', 'rowversion') END CALLOUT J BEGIN CALLOUT K SET @ProcName = 'p_Update ' + @TABLE_NAME SET @ProcName = REPLACE(@ProcName, ' ', '_') SET @ln = 'if OBJECTPROPERTY(OBJECT_ID(N''[' + @TABLE_SCHEMA + '].[' + @ProcName + ']''), N''IsProcedure'') = 1' PRINT @ln SET @ln = 'DROP PROCEDURE [' + @TABLE_SCHEMA + '].[' + @ProcName + ']' PRINT @ln PRINT 'GO' SET @ln = 'CREATE PROCEDURE [' + @TABLE_SCHEMA + '].[' + @ProcName + ']' PRINT @ln END CALLOUT K BEGIN CALLOUT L SET @RowNo = 0 SELECT @LastRow = MAX(RowNo) FROM #TB_SCHEMA SELECT @RowNo = MIN(RowNo) FROM #TB_SCHEMA WHILE @RowNo > 0 BEGIN SELECT @TABLE_SCHEMA = TABLE_SCHEMA , @TABLE_NAME = TABLE_NAME , @COLUMN_NAME = COLUMN_NAME , @DATA_TYPE = [DATA_TYPE] , @CHARACTER_MAXIMUM_LENGTH = CHARACTER_MAXIMUM_LENGTH , @NUMERIC_PRECISION = NUMERIC_PRECISION , @NUMERIC_SCALE = NUMERIC_SCALE , @DATETIME_PRECISION = DATETIME_PRECISION FROM #TB_SCHEMA WHERE RowNo = @RowNo SET @ln = SPACE(20) + '@' + REPLACE(RTRIM(@COLUMN_NAME), ' ', '_') + ' [' + RTRIM(@DATA_TYPE) + ']' IF CHARINDEX('CHAR', @DATA_TYPE) > 0 OR CHARINDEX('BINARY', @DATA_TYPE) > 0 SET @ln = @ln + ' (' + RTRIM(CONVERT(CHAR,@CHARACTER_MAXIMUM_LENGTH)) + ')' IF @DATA_TYPE IN ('DECIMAL', 'NUMERIC') ---, 'MONEY', 'SMALLMONEY') SET @ln = @ln + ' (' + RTRIM(CONVERT(CHAR,@NUMERIC_PRECISION)) + ', ' + RTRIM(CONVERT(CHAR,@NUMERIC_SCALE)) + ') ' IF @rowNo < @lastRow SET @ln = @ln + ' ,' PRINT @ln SET @pRowNo = @RowNo SET @RowNo = 0 SELECT @RowNO = MIN(RowNo) FROM #TB_SCHEMA WHERE RowNo > @pRowNo END PRINT 'AS' PRINT 'DECLARE @ERRORCODE [int], @ERRMSG [varchar] (128)' PRINT '---> Place data validation logic here <---' END CALLOUT L BEGIN CALLOUT M SET @RowNo = 0 SELECT @LastRow = MAX(RowNo) FROM #TB_SCHEMA SELECT @RowNO = MIN(RowNo) FROM #TB_SCHEMA SET @sWhere = '' SET @ln = ' UPDATE [' + RTRIM(@TABLE_SCHEMA) + '].[' + RTRIM(@TABLE_NAME) + ']' PRINT @ln SET @firstLine = 1 WHILE @RowNo > 0 BEGIN SELECT @TABLE_SCHEMA = TABLE_SCHEMA , @TABLE_NAME = TABLE_NAME , @COLUMN_NAME = COLUMN_NAME , @PK_Flag = PK_Flag FROM #TB_SCHEMA WHERE RowNo = @RowNo IF @PK_Flag = 1 IF @sWhere = '' SET @sWhere = ' WHERE [' + RTRIM(@COLUMN_NAME) + '] = @' + REPLACE(RTRIM(@COLUMN_NAME), ' ', '_') ELSE SET @sWhere = @sWhere + ' AND [' + RTRIM(@COLUMN_NAME) + '] = @' + REPLACE(RTRIM(@COLUMN_NAME), ' ', '_') ELSE BEGIN IF @FirstLine = 1 BEGIN SET @ln = SPACE(6) + 'SET [' + RTRIM(@COLUMN_NAME) + '] = @' + REPLACE(RTRIM(@COLUMN_NAME), ' ', '_') SET @FirstLine = 0 END ELSE SET @ln = SPACE(9) + '[' + RTRIM(@COLUMN_NAME) + '] = @' + REPLACE(RTRIM(@COLUMN_NAME), ' ', '_') IF @rowNo < @lastRow SET @ln = @ln + ' ,' PRINT @ln END SET @pRowNo = @RowNo SET @RowNo = 0 SELECT @RowNO = MIN(RowNo) FROM #TB_SCHEMA WHERE RowNo > @pRowNo END END CALLOUT M BEGIN CALLOUT N IF @sWhere <> '' PRINT @sWhere PRINT '---> Modify line above to change search arguments <---' PRINT '---> Modify lines below to customize error handling logic <---' PRINT ' SET @ERRORCODE = @@ERROR' PRINT ' IF @ERRORCODE <> 0 ' PRINT ' BEGIN' PRINT ' SET @ERRMSG = ''Update failed - '' + OBJECT_NAME(@@PROCID)' PRINT ' SET @ERRMSG = @ERRMSG + '' Error Code: '' + RTRIM(CONVERT(CHAR, @ERRORCODE)) ' PRINT ' RAISERROR (@ERRMSG, 16, 1)' PRINT ' RETURN (-1)' PRINT ' END' PRINT ' ELSE' PRINT ' RETURN (0)' PRINT 'GO' SET NOCOUNT OFF RETURN(0) GO SET ANSI_NULLS ON GO END CALLOUT N