Workaround for Identity column in APS
While working on a problem which involves migrating SSIS package from SQL Server to APS, there was extensive use of Identity column in data warehouse, and as there is no support for Identity column in APS till now, I have to come up with some workaround.
Adding to this problem there is one more limitation, that while dumping data to APS using SQL Server PDW Destination Adapter you have to provide a mapping for destination column (which in normal scenario one will left it out for Identity columns), which means that for identity column you have to provide a dummy column with a dummy value.
So, I have written a stored procedure, which will update the Identity column value from dummy value to the next biggest value already present in the table + 1 (and if table does not have any entry, then it will take 1 as the starting point)
This SP expects 4 parameters
- TableName: Table Name
- Shema: Schema of the table
- IdentityColName: Identity column name
- UpdatableValue: Dummy value which needs to be updated
CREATE PROC [dbo].[uspUpdateIdentityColumnValue] @TableName [varchar](100),@Schema [varchar](100),@IdentityColName [varchar](100),@UpdatableValue [int] AS BEGIN /***************************************************************************** PROCEDURE NAME: [uspUpdateIdentityColumnValue] AUTHOR: Siddharth CREATED: 09/22/2015
Example: DECLARE @IdentityColName varchar(100) = 'TableID' ,@TableName varchar(100) = ‘TableName' ,@Schema varchar(100) = 'dbo' ,@UpdatableValue int = -1 EXEC [dbo].[uspUpdateIdentityColumnValue] @TableName,@Schema,@IdentityColName,@UpdatableValue
VERSION HISTORY: Date Change Description Sep 22, 2015 Created ****************************************************************************/
BEGIN TRY DECLARE @ErrorMessage NVARCHAR(4000); DECLARE @ErrorSeverity INT; DECLARE @ErrorState INT;
DECLARE @TempTableName varchar(100) ,@TableFullName varchar(100) ,@TempTableFullName varchar(100) ,@Sql nvarchar(4000) ,@IdentityColDataType varchar(50) ,@ColNames varchar(1000) = '' ,@Index int = 1 ,@Count int
---------Create table names SET @TempTableName = @TableName + '_Tmp_001' SET @TempTableFullName = @Schema + '.'+@TempTableName SET @TableFullName = @Schema + '.'+@TableName
IF object_id('tempdb.dbo.#ColNames') IS NOT NULL DROP TABLE dbo.#ColNames
----------------Get All column names CREATE TABLE dbo.#ColNames WITH(LOCATION = USER_DB, CLUSTERED COLUMNSTORE INDEX,DISTRIBUTION = REPLICATE) AS SELECT ROW_NUMBER() OVER(ORDER BY COLUMN_NAME) ID, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE Table_NAME = @TableName AND TABLE_SCHEMA = @Schema AND COLUMN_NAME != @IdentityColName
SET @IdentityColDataType = (SELECT DATA_Type FROM INFORMATION_SCHEMA.COLUMNS WHERE Table_NAME = @TableName AND TABLE_SCHEMA = @Schema AND COLUMN_NAME = @IdentityColName)
-----------------concatenate the list of columns SET @Count = (SELECT COUNT(*) FROM #ColNames) WHILE(@Index<=@Count) BEGIN SET @ColNames = @ColNames + (SELECT COLUMN_NAME FROM #ColNames WHERE Id = @Index) + ',' SET @Index+=1 END SET @ColNames = (SELECT SUBSTRING(@ColNames,1,LEN(@ColNames)-1))
IF OBJECT_ID(@TempTableFullName) IS NOT NULL BEGIN SET @Sql = N'DROP TABLE ' + @TempTableFullName EXEC sp_executesql @Sql END
SET @Sql = ' DECLARE @MaxID int
SET @MaxID = (SELECT ISNULL(MAX(' + @IdentityColName + '),0) FROM ' + @TableFullName +' WHERE ' + @IdentityColName + '! = ' + CAST(@UpdatableValue AS varchar(5))+ ')
CREATE TABLE ' + @TempTableFullName + ' WITH (CLUSTERED COLUMNSTORE INDEX, DISTRIBUTION = REPLICATE) AS
SELECT ' + @IdentityColName + ',' + @ColNames+' FROM ' + @TableFullName + ' WHERE ' + @IdentityColName + '! = ' + CAST(@UpdatableValue AS varchar(5)) + ' UNION SELECT ISNULL(CAST(ROW_NUMBER() OVER(ORDER BY ' + @IdentityColName + ') + @MaxID AS ' + @IdentityColDataType + '),-1) AS ''' +@IdentityColName + ''',' + @ColNames+' FROM ' + @TableFullName + ' WHERE ' + @IdentityColName + ' = ' + CAST(@UpdatableValue AS varchar(5)) + ' ' --SELECT @SQl IF LEN(@Sql) > 3999 BEGIN SET @ErrorMessage = 'String exceeds limit' SET @ErrorSeverity = 16 SET @ErrorState = -1
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState ); END ELSE BEGIN EXEC sp_executeSQL @Sql SET @Sql = N' IF OBJECT_ID(''' + @TableFullName + ''') IS NOT NULL DROP TABLE ' + @TableFullName + '
IF OBJECT_ID(''' + @TempTableFullName + ''') IS NOT NULL RENAME OBJECT ' + @TempTableFullName + ' TO ' + @TableName + ' ' EXEC sp_executesql @Sql END IF object_id('tempdb.dbo.#ColNames') IS NOT NULL DROP TABLE dbo.#ColNames
END TRY BEGIN CATCH
SET @ErrorMessage = ERROR_MESSAGE() SET @ErrorSeverity = ERROR_SEVERITY() SET @ErrorState = ERROR_STATE()
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState );
IF(@@TRANCOUNT > 0) ROLLBACK; END CATCH END
|
Limitations
- In the script, I am using dynamic SQL, and there is a limitation on the maximum size of nvarchar i.e. 4000. So the script might break in case the script exceeds the limit