This document describes the process (and SQLs) used to merge one or more Control products from one database to another.
WARNING: This article is for reference. The changes made will PERMANENTLY delete and/or affect your data. This is the exact procedure in almost NO cases and should only be carried out by a skilled implementer and SQL practitioner.
The following Database Tables are involved in pricing in Control. This grid outlines which are converted into the new system:
SQL
– Section: Declare Variables and Create Databases – – This section is used to – * Declare all variables the user needs to set – * Create the working database (ConvTemp) – * Restore the source database (if that option is set) – * Restore the destination database (if that option is set) – * Writes all user variables to a database table for other sections to use
– Create the Temporary Database used to hold all Working Data – USE master;
IF EXISTS(SELECT * FROM sys.DATABASES WHERE name 'ConvTemp') begin
''ALTER DATABASE ConvTemp SET single_user WITH rollback immediate; -- this will force all others users off!
DROP DATABASE ConvTemp;
''
end; CREATE DATABASE ConvTemp; go
DECLARE @SourceDatabase varchar(255); DECLARE @DestDatabase varchar(255); DECLARE @RestoreDestDatabase bit; DECLARE @RestoreDestBackupFile varchar(255); DECLARE @RestoreDestFilePath varchar(255); DECLARE @RestoreSourceDatabase bit; DECLARE @RestoreSourceBackupFile varchar(255); DECLARE @RestoreSourceFilePath varchar(255); DECLARE @RenameExistingProducts bit; DECLARE @RenameExistingParts bit; DECLARE @RenameExistingModifiers bit; DECLARE @RenameExistingSelectionLists bit; DECLARE @RenamePrefix varchar(255); DECLARE @RenameSuffix varchar(255); DECLARE @DeleteDestPricingForms bit; DECLARE @DeleteDestUDFLayouts bit; DECLARE @S varchar(max);
SET @SourceDatabase 'Scott_Latest_OOBData'; SET @DestDatabase 'Scott_Hansen_Updated';
SET @DeleteDestPricingForms 0; – Set this to 1 to delete ALL pricing forms in the destination before importing SET @DeleteDestUDFLayouts 0; – Set this to 1 to delete ALL UDF Layouts in the destination before importing SET @RenameExistingProducts 0; – Set this to 1 to rename ALL products in the destination with the prefix and suffix before importing SET @RenameExistingParts 0; – Set this to 1 to rename ALL parts in the destination with the prefix and suffix before importing SET @RenameExistingModifiers 0; – Set this to 1 to rename ALL modifiers in the destination with the prefix and suffix before importing SET @RenameExistingSelectionLists 0; – Set this to 1 to rename ALL selection lists in the destination with the prefix and suffix before importing SET @RenamePrefix 'Old_'; SET @RenameSuffix ; SET @RestoreDestDatabase 0; – Set this to 1 to delete the destination database and restore from backup SET @RestoreDestBackupFile 'D:\Data\SQL Data\Dev\Scott\HansenSigns11-13-2009backup.bak'; SET @RestoreDestFilePath 'D:\Data\SQL Data\Dev\Scott\'; – include trailing backslash SET @RestoreSourceDatabase 0; – Set this to 1 to delete the source database and restore from backup SET @RestoreSourceBackupFile 'D:\DATA\SQL DATA\Dev\Scott\New OOB Dataset 2009-10-09.bak'; SET @RestoreSourceFilePath 'D:\DATA\SQL DATA\Dev\Scott\'; – include trailing backslash use ConvTemp; if exists(select * from ConvTemp.sys.objects where name 'TestLog') drop table ConvTemp.dbo.TestLog; create table ConvTemp.dbo.TestLog (id int primary key identity, token varchar(50) not null, value varchar(max)); create index TestLog_TokenIndex on ConvTemp.dbo.TestLog (token); – Create Helper Functions to Store and Retrieve Data if exists(select * from sys.objects where name 'LogData') Drop procedure LogData; set @S 'CREATE PROCEDURE LogData @Token varchar(50), @Value varchar(max) '+ 'AS '+ 'BEGIN '+ 'SET NOCOUNT ON; '+ 'DELETE FROM TestLog '+ 'WHERE token @Token; '+ 'INSERT INTO TestLog (token, value) '+ 'SELECT @Token, @Value '+ 'END '; execute (@S); if exists(select * from sys.objects where name 'GetData') Drop Function GetData; set @S 'CREATE FUNCTION GetData (@Token varchar(50)) '+ 'RETURNS varchar(max) AS '+ 'BEGIN '+ 'RETURN( SELECT Value FROM TestLog WHERE token @Token ) '+ 'END ' execute (@S); exec LogData 'SourceDatabase', @SourceDatabase; exec LogData 'DestDatabase', @DestDatabase; exec LogData 'TempDatabase', 'ConvTemp'; SET @S GetDate(); exec LogData 'Imported Started', @S; exec LogData 'DeleteDestPricingForms' , @DeleteDestPricingForms; exec LogData 'DeleteDestUDFLayouts' , @DeleteDestUDFLayouts; exec LogData 'RenameExistingProducts' , @RenameExistingProducts; exec LogData 'RenameExistingParts' , @RenameExistingParts ; exec LogData 'RenameExistingModifiers', @RenameExistingModifiers; exec LogData 'RenameExistingSelectionLists', @RenameExistingSelectionLists; exec LogData 'RenamePrefix' , @RenamePrefix; exec LogData 'RenameSuffix' , @RenameSuffix; – Restore the Destination Database (used for testing) – IF (@RestoreDestDatabase1) BEGIN SET @S 'IF EXISTS(SELECT * FROM sys.DATABASES WHERE name '+@DestDatabase + ') ' + 'begin '+ 'ALTER DATABASE '+@DestDatabase+' SET single_user WITH rollback immediate; '+ 'DROP DATABASE '+@DestDatabase + '; ' + 'end; '+ 'restore DATABASE '+@DestDatabase + ' ' + 'FROM DISK '+@RestoreDestBackupFile + ' ' + 'WITH '+ 'Recovery, '+ 'Move EmptyDataSet_Data TO '+@RestoreDestFilePath+'StoreDataDest.MDF, ' + 'Move EmptyDataSet_Log TO '+@RestoreDestFilePath+'StoreDataDest.LDF '; EXECUTE (@S); END – Restore the Source Database (used for testing) – IF (@RestoreSourceDatabase1) BEGIN SET @S 'IF EXISTS(SELECT * FROM sys.DATABASES WHERE name '+@SourceDatabase + ') ' + 'begin '+ 'ALTER DATABASE '+@SourceDatabase+' SET single_user WITH rollback immediate; '+ 'DROP DATABASE '+@SourceDatabase + '; ' + 'end; '+ 'restore DATABASE '+@SourceDatabase + ' ' + 'FROM DISK '+@RestoreSourceBackupFile + ' ' + 'WITH '+ 'Recovery, '+ 'Move EmptyDataSet_Data TO '+@RestoreSourceFilePath+'StoreDataSource.MDF, ' + 'Move EmptyDataSet_Log TO '+@RestoreSourceFilePath+'StoreDataSource.LDF '; EXECUTE (@S); END ————————————————————————————– GO ————————————————————————————– – Section: Create_IDMap Stored Procedure – – This section defines a stored procedure that creates an IDMap table in the – in the temporary database. The IDMap table: – * Needs to be called for each table you want to create. – * Is names IDMap_xxxxxx where xxxxxx is the table name. – * Matches based on a text expression passed in – * Generates new IDs for records not found ————————————————————————————– CREATE PROCEDURE Create_IDMap @TableName varchar(50), @TextExpressionCompared varchar(max), @ClassTypeID int -1, @SourceDatabasePath varchar(255), @TargetDatabasePath varchar(255), @CreateNewIDs bit AS BEGIN DECLARE @DEBUG bit; DECLARE @MapTableName varchar(100); DECLARE @TempExpr varchar(max); DECLARE @ClassTypeIDStr varchar(10); DECLARE @S varchar(max); SET @DEBUG 0; Execute( 'USE '+@SourceDatabasePath ); SET @SourceDatabasePath @SourceDatabasePath+'.dbo.'; SET @TargetDatabasePath @TargetDatabasePath+'.dbo.'; IF @ClassTypeID -1 SET @MapTableName 'IDMap_'+@TableName ELSE SET @MapTableName 'IDMap_'+@TableName+'_'+cast(@ClassTypeID as varchar(10)); SET @ClassTypeIDStr CAST(@ClassTypeID as VarChar(10)); – SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements. IF (@DEBUG 1) SET NOCOUNT ON; IF OBJECT_ID(@MapTableName) IS NOT NULL Execute('DROP TABLE '+@MapTableName); – Create a mapping table SET @S 'USE ConvTemp; '+ 'CREATE TABLE '+@MapTableName+' '+ '( '+ ' TextValue varchar(255) NULL, '+ ' SourceID int NOT NULL, '+ ' TargetID int NULL, '+ ' IsNew bit NOT NULL, '+ ' IsChanged bit NOT NULL, '+ ' RowIndex int IDENTITY(1,1) NOT NULL '+ ') '+ '; '+ 'CREATE INDEX '+@MapTableName+'_SourceIDIndex ON '+@MapTableName+' (SourceID ASC) '+ '; '+ 'CREATE INDEX '+@MapTableName+'_TargetIDIndex ON '+@MapTableName+' (TargetID ASC) '+ '; '+ 'CREATE INDEX '+@MapTableName+'_TextValueIndex ON '+@MapTableName+' (TextValue ASC) '+ '; '+ 'CREATE INDEX '+@MapTableName+'_RowIndex ON '+@MapTableName+' (RowIndex ASC) '+ '; ' IF (@DEBUG 1) Print @S; Execute(@S); – In order to support combined fields, allow an expression in the TextExpressionCompared – To handle this, we have to accomodate the “Table.” prefix anywhere in the expression. – If the just pass in a field, then we need to pre-prend the “Table.” prefix. IF (PATINDEX('%TABLE.%', @TextExpressionCompared) 0) SET @TextExpressionCompared 'TABLE.'+@TextExpressionCompared; – Insert the Source values into the new Table SET @TempExpr REPLACE( REPLACE( @TextExpressionCompared, 'TABLE.', 'SRC.' ), 'DATABASE.', +@SourceDatabasePath+); SET @S 'INSERT INTO '+@MapTableName+' '+ 'SELECT DISTINCT ('+@TempExpr+'), ID, NULL, 0, 0 '+ 'FROM '+@SourceDatabasePath+@TableName+' AS SRC '+ 'WHERE ID > 0 ' IF (@ClassTypeID -1) SET @S @S + ' AND (ClassTypeID '+ @ClassTypeIDStr +')'; IF (@DEBUG 1) Print @S; Execute(@S); – In Case of Duplicates, Delete all but the highest SET @S 'DELETE FROM '+@MapTableName+' '+ 'WHERE RowIndex NOT IN (SELECT Min(RowIndex) FROM '+@MapTableName+' GROUP BY SourceID)'; IF (@DEBUG 1) Print @S; Execute(@S); – Do not Renumber System IDs regardless of the name. SET @S ' UPDATE '+@MapTableName+' SET TargetID SourceID, IsNew (CASE WHEN SourceID IN (SELECT ID FROM '+@TargetDatabasePath+@TableName+' ) THEN 0 ELSE 1 END) WHERE SourceID < 1000 ;' IF (@DEBUG 1) Print @S; Execute(@S); – Update the Map with the ID of the Destination Table SET @TempExpr REPLACE( REPLACE( @TextExpressionCompared, 'TABLE.', 'DestTable.' ), 'DATABASE.', +@TargetDatabasePath+); SET @S 'UPDATE MapTable '+ 'SET TargetID DestTable.ID '+ 'FROM '+@MapTableName+' MapTable '+ ' LEFT JOIN '+@TargetDatabasePath+@TableName+' DestTable '+ ' ON MapTable.TextValue ('+@TempExpr+') '+ 'WHERE TargetID IS NULL '; IF (@DEBUG 1) Print @S; Execute(@S); – Presumable, if there is no map field then the item does not exist. – In this case, give it a unique ID if desired IF (@CreateNewIDs1) BEGIN SET @S 'UPDATE '+@MapTableName+' '+ 'SET TargetID RowIndex + Coalesce1)