Export SQL Server database diagram,
I know that some of you might want to do like me, export database diagram to be executed in other server. This case would meet when we want to have a very blank database but remain all database schema of an existing database one.
Normally we can do a back up then restore it as a new name then run the script to truncate all data in every tables but it will be difficult if it was build with diagram.
I have found on the net the sample on SQL Server 2000 and also 2005. It is a very helpfull for my case as I need to re-create database schemas on my new blank database.
1. SQL 2000
There have 2 store procedures and a function is needed
ufn_VarbinaryToVarcharHex
usp_ScriptDatabaseDiagrams
dtpropertiesTextToRowset
You can see original post by Clay Beatty
2. SQL 2005
UDP_SCRIPTDIAGRAM
Tool_VarbinaryToVarcharHex
Normally we can do a back up then restore it as a new name then run the script to truncate all data in every tables but it will be difficult if it was build with diagram.
I have found on the net the sample on SQL Server 2000 and also 2005. It is a very helpfull for my case as I need to re-create database schemas on my new blank database.
1. SQL 2000
There have 2 store procedures and a function is needed
ufn_VarbinaryToVarcharHex
CREATE FUNCTION dbo.ufn_VarbinaryToVarcharHex (@VarbinaryValue varbinary(4000)) RETURNS Varchar(8000) AS BEGIN Declare @NumberOfBytes Int Declare @LeftByte Int Declare @RightByte Int SET @NumberOfBytes = datalength(@VarbinaryValue) IF (@NumberOfBytes > 4) RETURN Payment.dbo.ufn_VarbinaryToVarcharHex(cast(substri ng(@VarbinaryValue,1, (@NumberOfBytes/2)) as varbinary(2000)))+ Payment.dbo.ufn_VarbinaryToVarcharHex(cast(substri ng(@VarbinaryValue,((@NumberOfBytes/2)+1),2000) as varbinary(2000))) IF (@NumberOfBytes = 0) RETURN '' -- Either 4 or less characters (8 hex digits) were input SET @LeftByte = CAST(@VarbinaryValue as Int) & 15 SET @LeftByte = CASE WHEN (@LeftByte < 10) THEN (48 + @LeftByte) ELSE (87 + @LeftByte) END SET @RightByte = (CAST(@VarbinaryValue as Int) / 16) & 15 SET @RightByte = CASE WHEN (@RightByte < 10) THEN (48 + @RightByte) ELSE (87 + @RightByte) END SET @VarbinaryValue = SUBSTRING(@VarbinaryValue, 1,(@NumberOfBytes-1)) RETURN CASE WHEN (@LeftByte < 10) THEN Payment.dbo.ufn_VarbinaryToVarcharHex(@VarbinaryVa lue) + char(@RightByte) + char(@LeftByte) ELSE Payment.dbo.ufn_VarbinaryToVarcharHex(@VarbinaryVa lue) + char(@RightByte) + char(@LeftByte) END END go GRANT EXECUTE ON [dbo].[ufn_VarbinaryToVarcharHex] TO [PUBLIC] GO
usp_ScriptDatabaseDiagrams
CREATE PROCEDURE dbo.usp_ScriptDatabaseDiagrams @DiagramName varchar (128) = null AS -- Variable Declarations ------------------------ Declare @id int Declare @objectid int Declare @property varchar(64) Declare @value varchar (255) Declare @uvalue varchar (255) Declare @lvaluePresent bit Declare @version int Declare @PointerToData varbinary (16) Declare @ImageRowByteCount int Declare @CharData varchar (8000) Declare @DiagramDataFetchStatus int Declare @CharDataFetchStatus int Declare @Offset int Declare @LastObjectid int Declare @NextObjectid int Declare @ReturnCode int -- Initializations ------------------ SET NOCOUNT ON SET TRANSACTION ISOLATION LEVEL REPEATABLE READ SET @ReturnCode = -1 SET @ImageRowByteCount = 40 SET @LastObjectid = -1 SET @NextObjectid = -1 -- Temp Table Creation for transforming Image Data into a text (hex) format --------------------------------------------------------------------------- CREATE TABLE #ImageData (KeyValue int NOT NULL IDENTITY (1, 1), DataField varbinary(8000) NULL) ON [PRIMARY] -- Check for an unexpected error -------------------------------- IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO CREATE TABLE #ImageData' PRINT '***' PRINT '' GOTO Procedure_Exit END ALTER TABLE #ImageData ADD CONSTRAINT PK_ImageData PRIMARY KEY CLUSTERED (KeyValue) ON [PRIMARY] -- Check for an unexpected error -------------------------------- IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO Index TABLE #ImageData' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Output Script Header Documentation ------------------------------------- PRINT '------------------------------------------------------------------------' PRINT '-- Database Diagram Reconstruction Script' PRINT '------------------------------------------------------------------------' PRINT '-- Created on: ' + Convert(varchar(23), GetDate(), 121) PRINT '-- From Database: ' + DB_NAME() PRINT '-- By User: ' + USER_NAME() PRINT '--' PRINT '-- This SQL Script was designed to reconstruct a set of database' PRINT '-- diagrams, by repopulating the system table dtproperties, in the' PRINT '-- current database, with values which existed at the time this' PRINT '-- script was created. Typically, this script would be created to' PRINT '-- backup a set of database diagrams, or to package up those diagrams' PRINT '-- for deployment to another database.' PRINT '--' PRINT '-- Minimally, all that needs to be done to recreate the target' PRINT '-- diagrams is to run this script. There are several options,' PRINT '-- however, which may be modified, to customize the diagrams tobe' PRINT '-- produced. Changing these options is as simple as modifyingthe' PRINT '-- initial values for a set of variables, which are definedimmediately' PRINT '-- following these comments. They are:' PRINT '--' PRINT '-- Variable Name Description' PRINT '-- ----------------------- ---------------------------------------------' PRINT '-- @TargetDatabase This varchar variable will establishthe' PRINT '-- target database, within which thediagrams' PRINT '-- will be reconstructed. This variableis' PRINT '-- initially set to database name fromwhich the' PRINT '-- script was built, but it may bemodified as' PRINT '-- required. A valid database namemust be' PRINT '-- specified.' PRINT '--' PRINT '-- @DropExistingDiagrams This bit variable is initially setset to a' PRINT '-- value of zero (0), which indicatesthat any' PRINT '-- existing diagrams in the targetdatabase are' PRINT '-- to be preserved. By setting thisvalue to' PRINT '-- one (1), any existing diagrams inthe target' PRINT '-- database will be dropped prior to' PRINT '-- reconstruction. Zero and One are theonly' PRINT '-- valid values for the variable.' PRINT '--' PRINT '-- @DiagramSuffix This varchar variable will be used to append' PRINT '-- to the original diagram names, asthey' PRINT '-- existed at the time they were scripted. This' PRINT '-- variable is initially set to take on the' PRINT '-- value of the current date/time, although it' PRINT '-- may be modified as required. An empty string' PRINT '-- value would effectively turn off the diagram' PRINT '-- suffix option.' PRINT '--' PRINT '------------------------------------------------------------------------' PRINT '' PRINT 'SET NOCOUNT ON' PRINT '' PRINT '-- User Settable Options' PRINT '------------------------' PRINT 'Declare @TargetDatabase varchar (128)' PRINT 'Declare @DropExistingDiagrams bit' PRINT 'Declare @DiagramSuffix varchar (50)' PRINT '' PRINT '-- Initialize User Settable Options' PRINT '-----------------------------------' PRINT 'SET @TargetDatabase = ''Payment''' PRINT 'SET @DropExistingDiagrams = 0' PRINT 'SET @DiagramSuffix = '' '' + Convert(varchar(23), GetDate(), 121)' PRINT '' PRINT '' PRINT '-------------------------------------------------------------------------' PRINT '-- END OF USER MODIFIABLE SECTION - MAKE NO CHANGES TO THE LOGIC BELOW --' PRINT '-------------------------------------------------------------------------' PRINT '' PRINT '' PRINT '-- Setting Target database and clearing dtproperties, if indicated' PRINT '------------------------------------------------------------------' PRINT 'Exec(''USE '' + @TargetDatabase)' PRINT 'IF (@DropExistingDiagrams = 1)' PRINT ' TRUNCATE TABLE dtproperties' PRINT '' PRINT '' PRINT '-- Creating Temp Table to persist specific variables ' PRINT '-- between Transact SQL batches (between GO statements)' PRINT '-------------------------------------------------------' PRINT 'IF EXISTS(SELECT 1' PRINT ' FROM tempdb..sysobjects' PRINT ' WHERE name like ''%#PersistedVariables%''' PRINT ' AND xtype = ''U'')' PRINT ' DROP TABLE #PersistedVariables' PRINT 'CREATE TABLE #PersistedVariables (VariableName varchar (50) NOT NULL,' PRINT ' VariableValue varchar (50) NOT NULL) ON [PRIMARY]' PRINT 'ALTER TABLE #PersistedVariables ADD CONSTRAINT' PRINT ' PK_PersistedVariables PRIMARY KEY CLUSTERED ' PRINT ' (VariableName) ON [PRIMARY]' PRINT '' PRINT '' PRINT '-- Persist @DiagramSuffix' PRINT '-------------------------' PRINT 'INSERT INTO #PersistedVariables VALUES (''DiagramSuffix'',' PRINT ' @DiagramSuffix)' PRINT 'GO' PRINT '' -- Cusror to be used to enumerate through each row of -- diagram data from the table dtproperties ----------------------------------------------------- Declare DiagramDataCursor Cursor FOR SELECT dtproperties.id, dtproperties.objectid, dtproperties.property, dtproperties.value, dtproperties.uvalue, CASE WHEN (dtproperties.lvalue is Null) THEN 0 ELSE 1 END, dtproperties.version FROM dtproperties INNER JOIN (SELECT objectid FROM dtproperties WHERE property = 'DtgSchemaNAME' AND value = IsNull(@DiagramName, value)) TargetObject ON dtproperties.objectid = TargetObject.objectid ORDER BY dtproperties.id, dtproperties.objectid -- Check for an unexpected error -------------------------------- IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO DECLARE CURSOR DiagramDataCursor' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Cusror to be used to enumerate through each row of -- varchar data from the temp table #ImageData ----------------------------------------------------- Declare CharDataCursor Cursor FOR SELECT '0x'+Payment.dbo.ufn_VarbinaryToVarcharHex(DataFie ld) FROM #ImageData ORDER BY KeyValue -- Check for an unexpected error -------------------------------- IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO DECLARE CURSOR CharDataCursor' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Open the DiagramDataCursor cursor ------------------------------------ OPEN DiagramDataCursor -- Check for an unexpected error -------------------------------- IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO OPEN CURSOR DiagramDataCursor' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Get the Row of Diagram data ------------------------------ FETCH NEXT FROM DiagramDataCursor INTO @id, @objectid, @property, @value, @uvalue, @lvaluePresent, @version -- Check for an unexpected error -------------------------------- IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO FETCH NEXT FROM CURSOR DiagramDataCursor' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Initialize the Fetch Status for the DiagramDataCursor cursor --------------------------------------------------------------- SET @DiagramDataFetchStatus = @@FETCH_STATUS -- Check for an unexpected error -------------------------------- IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO SET @DiagramDataFetchStatus' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Begin the processing each Row of Diagram data ------------------------------------------------ WHILE (@DiagramDataFetchStatus = 0) BEGIN -- Build an Insert statement for non-image data PRINT '' PRINT '-- Insert a new dtproperties row' PRINT '--------------------------------' IF (@LastObjectid <> @objectid) BEGIN -- Retrieve the persisted DiagramSuffix - If processing DtgSchemaNAME IF (@property = 'DtgSchemaNAME') BEGIN PRINT 'Declare @DiagramSuffix varchar (50)' PRINT 'SELECT @DiagramSuffix = Convert(varchar (50), VariableValue)' PRINT 'FROM #PersistedVariables' PRINT 'WHERE VariableName = ''DiagramSuffix''' END -- Build the Insert statement for a New Diagram - Apply and Persist the new Objectid PRINT 'INSERT INTO dtproperties (objectid,' PRINT ' property,' PRINT ' value,' PRINT ' uvalue,' PRINT ' lvalue,' PRINT ' version)' PRINT ' VALUES (0,' PRINT ' ''' + @property +''',' PRINT ' ' + CASE WHEN (@property = 'DtgSchemaNAME') THEN IsNull(('''' + @value + ''' + @DiagramSuffix,'), 'null,') ELSE IsNull(('''' + @value + ''','), 'null,') END PRINT ' ' + CASE WHEN (@property = 'DtgSchemaNAME') THEN IsNull(('''' + @uvalue + '''+ @DiagramSuffix,'), 'null,') ELSE IsNull(('''' + @uvalue + ''','), 'null,') END PRINT ' ' + CASE WHEN (@lvaluePresent = 1) THEN 'cast(''0'' as varbinary(10)),' ELSE 'null,' END PRINT ' ' + IsNull(Convert(varchar(15), @version), 'null') + ')' PRINT 'DELETE #PersistedVariables' PRINT 'WHERE VariableName = ''NextObjectid''' PRINT 'INSERT INTO #PersistedVariables VALUES (''NextObjectid'',' PRINT 'Convert(varchar(15), @@IDENTITY))' PRINT 'Declare @NextObjectid int' PRINT 'SELECT @NextObjectid = Convert(int, VariableValue)' PRINT 'FROM #PersistedVariables' PRINT 'WHERE VariableName = ''NextObjectid''' PRINT 'UPDATE dtproperties' PRINT ' SET Objectid = @NextObjectid' PRINT 'WHERE id = @NextObjectid' SET @LastObjectid = @objectid END ELSE BEGIN -- Retrieve the persisted DiagramSuffix - If processing DtgSchemaNAME IF (@property = 'DtgSchemaNAME') BEGIN PRINT 'Declare @DiagramSuffix varchar (50)' PRINT 'SELECT @DiagramSuffix = Convert(varchar(50), VariableValue)' PRINT 'FROM #PersistedVariables' PRINT 'WHERE VariableName = ''DiagramSuffix''' END -- Build the Insert statement for an in process Diagram - Retrieve the persisted Objectid PRINT 'Declare @NextObjectid int' PRINT 'SELECT @NextObjectid = Convert(int,VariableValue)' PRINT 'FROM #PersistedVariables' PRINT 'WHERE VariableName = ''NextObjectid''' PRINT 'INSERT INTO dtproperties (objectid,' PRINT ' property,' PRINT ' value,' PRINT ' uvalue,' PRINT ' lvalue,' PRINT ' version)' PRINT ' VALUES (@NextObjectid,' PRINT ' ''' + @property + ''',' PRINT ' ' + CASE WHEN(@property = 'DtgSchemaNAME') THEN IsNull(('''' + @value + ''' + @DiagramSuffix,'), 'null,') ELSE IsNull(('''' + @value + ''','), 'null,') END PRINT ' ' + CASE WHEN(@property = 'DtgSchemaNAME') THEN IsNull(('''' + @uvalue + '''+ @DiagramSuffix,'), 'null,') ELSE IsNull(('''' + @uvalue + ''','), 'null,') END PRINT ' ' + CASE WHEN(@lvaluePresent = 1) THEN 'cast(''0'' as varbinary(10)),' ELSE 'null,' END PRINT ' ' + IsNull(Convert(varchar(15), @version), 'null') + ')' END -- Each Insert deliniates a new Transact SQL batch PRINT 'GO' -- Check for a non-null lvalue (image data is present) IF (@lvaluePresent = 1) BEGIN -- Fill the temp table with Image Data of length @ImageRowByteCount INSERT INTO #ImageData (DataField) EXEC usp_dtpropertiesTextToRowset @id, @ImageRowByteCount -- Check for an unexpected error IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO INSERT INTO #ImageData' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Prepare to build the UPDATETEXT statement(s) for the image data SET @Offset = 0 -- Open the CharDataCursor cursor OPEN CharDataCursor -- Check for an unexpected error IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO OPEN CURSOR CharDataCursor' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Get the CharData Row FETCH NEXT FROM CharDataCursor INTO @CharData -- Check for an unexpected error IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO FETCH NEXT FROM CURSOR CharDataCursor' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Initialize the Fetch Status for the CharDataCursor cursor SET @CharDataFetchStatus = @@FETCH_STATUS -- Check for an unexpected error IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO SET @CharDataFetchStatus' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Begin the processing of each Row of Char data WHILE (@CharDataFetchStatus = 0) BEGIN -- Update a segment of image data PRINT '' PRINT '-- Update this dtproperties row with a new segment of Image data' PRINT 'Declare @PointerToData varbinary (16)' PRINT 'SELECT @PointerToData = TEXTPTR(lvalue) FROM dtproperties WHERE id = (SELECT MAX(id) FROM dtproperties)' PRINT 'UPDATETEXT dtproperties.lvalue @PointerToData ' + convert(varchar(15), @Offset) + ' null ' + @CharData -- Each UPDATETEXT deliniates a new Transact SQL batch PRINT 'GO' -- Calculate the Offset for the next segment of image data SET @Offset = @Offset + ((LEN(@CharData) - 2) / 2) -- Get the CharData Row FETCH NEXT FROM CharDataCursor INTO @CharData -- Check for an unexpected error IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO FETCH NEXT FROM CURSOR CharDataCursor' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Update the Fetch Status for the CharDataCursor cursor SET @CharDataFetchStatus = @@FETCH_STATUS -- Check for an unexpected error IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO SET @CharDataFetchStatus' PRINT '***' PRINT '' GOTO Procedure_Exit END END -- Cleanup CharDataCursor Cursor resources Close CharDataCursor -- Check for an unexpected error IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO CLOSE CURSOR CharDataCursor' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Flush the processed Image data TRUNCATE TABLE #ImageData -- Check for an unexpected error IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO TRUNCATE TABLE #ImageData' PRINT '***' PRINT '' GOTO Procedure_Exit END END -- Get the Row of Diagram data FETCH NEXT FROM DiagramDataCursor INTO @id, @objectid, @property, @value, @uvalue, @lvaluePresent, @version -- Check for an unexpected error IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO FETCH NEXT FROM CURSOR DiagramDataCursor' PRINT '***' PRINT '' GOTO Procedure_Exit END -- Update the Fetch Status for the DiagramDataCursor cursor SET @DiagramDataFetchStatus = @@FETCH_STATUS -- Check for an unexpected error IF (@@error != 0) BEGIN PRINT '' PRINT '***' PRINT '*** ERROR OCCURRED WHILE ATTEMPTING TO SET @DiagramDataFetchStatus' PRINT '***' PRINT '' GOTO Procedure_Exit END END PRINT '' PRINT '-- Cleanup the temp table #PersistedVariables' PRINT '---------------------------------------------' PRINT 'IF EXISTS(SELECT 1' PRINT ' FROM tempdb..sysobjects' PRINT ' WHERE name like ''%#PersistedVariables%''' PRINT ' AND xtype = ''U'')' PRINT ' DROP TABLE #PersistedVariables' PRINT 'GO' PRINT '' PRINT 'SET NOCOUNT OFF' PRINT 'GO' -- Processing Complete ---------------------- SET @ReturnCode = 0 Procedure_Exit: --------------- Close DiagramDataCursor DEALLOCATE DiagramDataCursor DEALLOCATE CharDataCursor DROP TABLE #ImageData SET NOCOUNT OFF RETURN @ReturnCode GO GRANT EXECUTE ON [dbo].[usp_ScriptDatabaseDiagrams] TO [Public] GO
dtpropertiesTextToRowset
CREATE PROCEDURE dbo.usp_dtpropertiesTextToRowset @id int, @RowsetCharLen int = 255 AS -- Variable Declarations ------------------------ Declare @PointerToData varbinary (16) Declare @TotalSize int Declare @LastRead int Declare @ReadSize int Declare @ReturnCode int -- Initializations ------------------ SET NOCOUNT ON SET TRANSACTION ISOLATION LEVEL REPEATABLE READ SET @ReturnCode = -1 -- Establish the Pointer to the Image data ------------------------------------------ SELECT @PointerToData = TEXTPTR(lvalue), @TotalSize = DATALENGTH(lvalue), @LastRead = 0, @ReadSize = CASE WHEN (@RowsetCharLen < DATALENGTH(lvalue)) THEN @RowsetCharLen ELSE DATALENGTH(lvalue) END FROM dtproperties WHERE id = @id -- Loop through the image data, returning rows of the desired length -------------------------------------------------------------------- IF (@PointerToData is not null) AND (@ReadSize > 0) WHILE (@LastRead < @TotalSize) BEGIN IF ((@ReadSize + @LastRead) > @TotalSize) SET @ReadSize = @TotalSize - @LastRead READTEXT dtproperties.lvalue @PointerToData @LastRead @ReadSize SET @LastRead = @LastRead + @ReadSize END -- Processing Complete ---------------------- SET @ReturnCode = 0 Procedure_Exit: --------------- SET NOCOUNT OFF RETURN @ReturnCode GO GRANT EXECUTE ON [dbo].[usp_dtpropertiesTextToRowset] TO [Public] GO
You can see original post by Clay Beatty
2. SQL 2005
UDP_SCRIPTDIAGRAM
CREATE PROCEDURE [dbo].[UDP_SCRIPTDIAGRAM] ( @name VARCHAR(128) ) AS BEGIN DECLARE @diagram_id INT DECLARE @index INT DECLARE @size INT DECLARE @chunk INT DECLARE @line VARCHAR(max) -- Set start index, and chunk 'constant' value SET @index = 1 -- SET @chunk = 32 -- values that work: 2, 6 -- values that fail: 15,16, 64 -- Get PK diagram_id using the diagram's name (which is what the user is familiar with) SELECT @diagram_id=diagram_id , @size = DATALENGTH(definition) FROM sysdiagrams WHERE [name] = @name IF @diagram_id IS NULL BEGIN PRINT '/**Diagram name [' + @name + '] could not be found. */' END ELSE -- Diagram exists BEGIN -- Now with the diagram_id, do all the work PRINT '/**' PRINT '' PRINT 'Restore diagram ''' + @name + '''' PRINT ' ' PRINT '' PRINT 'Generated by Tool_ScriptDiagram2005/Tool_VarbinaryToVarcharHex' PRINT 'Will attempt to create [sysdiagrams] table if it doesn''t already exist' PRINT ' ' PRINT '' + LEFT(CONVERT(VARCHAR(23), GETDATE(), 121), 16) + ' ' PRINT '*/' PRINT 'PRINT ''=== Tool_ScriptDiagram2005 restore diagram [' + @name + '] ===''' PRINT ' -- If the sysdiagrams table has not been created in this database, create it! IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''sysdiagrams'') BEGIN -- Create table script generated by Sql Server Management Studio -- _Assume_ this is roughly equivalent to what Sql Server/Management Studio -- creates the first time you add a diagram to a 2005 database CREATE TABLE [dbo].[sysdiagrams]( [name] [sysname] NOT NULL, [principal_id] [int] NOT NULL, [diagram_id] [int] IDENTITY(1,1) NOT NULL, [version] [int] NULL, [definition] [varbinary](max) NULL, PRIMARY KEY CLUSTERED ( [diagram_id] ASC )WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) , CONSTRAINT [UK_principal_name] UNIQUE NONCLUSTERED ( [principal_id] ASC, [name] ASC )WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ) EXEC sys.sp_addextendedproperty @name=N''microsoft_database_tools_support'', @value=1 , @level0type=N''SCHEMA'',@level0name=N''dbo'', @level1type=N''TABLE'',@level1name=N''sysdiagrams'' PRINT ''[sysdiagrams] table was created as it did not already exist'' END -- Target table will now exist, if it didn''t before' PRINT 'SET NOCOUNT ON -- Hide (1 row affected) messages' PRINT 'DECLARE @newid INT' PRINT 'DECLARE @DiagramSuffix varchar (50)' PRINT '' PRINT 'PRINT ''Suffix diagram name with date, to ensure uniqueness''' PRINT 'SET @DiagramSuffix = '' '' + LEFT(CONVERT(VARCHAR(23), GETDATE(), 121), 16)' PRINT '' PRINT 'PRINT ''Create row for new diagram''' -- Output the INSERT that _creates_ the diagram record, with a non-NULL [definition], -- important because .WRITE *cannot* be called against a NULL value (in the WHILE loop) -- so we insert 0x so that .WRITE has 'something' to append to... PRINT 'BEGIN TRY' PRINT ' PRINT ''Write diagram ' + @name + ' into new row (and get [diagram_id])''' SELECT @line = ' INSERT INTO sysdiagrams ([name], [principal_id], [version], [definition])' + ' VALUES (''' + [name] + '''+@DiagramSuffix, '+ CAST (principal_id AS VARCHAR(100))+', '+CAST (version AS VARCHAR(100))+', 0x)' FROM sysdiagrams WHERE diagram_id = @diagram_id PRINT @line PRINT ' SET @newid = SCOPE_IDENTITY()' PRINT 'END TRY' PRINT 'BEGIN CATCH' PRINT ' PRINT ''XxXxX '' + Error_Message() + '' XxXxX''' PRINT ' PRINT ''XxXxX END Tool_ScriptDiagram2005 - fix the error before running again XxXxX''' PRINT ' RETURN' PRINT 'END CATCH' PRINT '' PRINT 'PRINT ''Now add all the binary data...''' PRINT 'BEGIN TRY' WHILE @index < @size BEGIN -- Output as many UPDATE statements as required to append all the diagram binary -- data, represented as hexadecimal strings SELECT @line = ' UPDATE sysdiagrams SET [definition] .Write (' + ' 0x' + UPPER(dbo.Tool_VarbinaryToVarcharHex (SUBSTRING (definition, @index, @chunk))) + ', null, 0) WHERE diagram_id = @newid -- index:' + CAST(@index AS VARCHAR(100)) FROM sysdiagrams WHERE diagram_id = @diagram_id PRINT @line SET @index = @index + @chunk END PRINT '' PRINT ' PRINT ''=== Finished writing diagram id '' + CAST(@newid AS VARCHAR(100)) + '' ===''' PRINT ' PRINT ''=== Refresh your Databases-[DbName]-Database Diagrams to see the new diagram ===''' PRINT 'END TRY' PRINT 'BEGIN CATCH' PRINT ' -- If we got here, the [definition] updates didn''t complete, so delete the diagram row' PRINT ' -- (and hope it doesn''t fail!)' PRINT ' DELETE FROM sysdiagrams WHERE diagram_id = @newid' PRINT ' PRINT ''XxXxX '' + Error_Message() + '' XxXxX''' PRINT ' PRINT ''XxXxX END Tool_ScriptDiagram2005 - fix the error before running again XxXxX''' PRINT ' RETURN' PRINT 'END CATCH' END END
Tool_VarbinaryToVarcharHex
/**Based on ufn_VarbinaryToVarcharHex by Clay Beatty. Used by Tool_ScriptDiagram2005 Function has two 'parts': PART ONE: takes large VarbinaryValue chunks (greater than four bytes) and splits them into half, calling the function recursively with each half until the chunks are only four bytes long PART TWO: notices the VarbinaryValue is four bytes or less, and starts actually processing these four byte chunks. It does this by splitting the least-significant (rightmost) byte into two hexadecimal characters and recursively calling the function with the more significant bytes until none remain (four recursive calls in total). Craig Dunn Clay Beatty's original function was written for Sql Server 2000. Sql Server 2005 introduces the VARBINARY(max) datatype which this function now uses. References ---------- 1) MSDN: Using Large-Value Data Types http://msdn2.microsoft.com/en-us/library/ms178158.aspx 2) Clay's "original" Script, Save, Export SQL 2000 Database Diagrams http://www.thescripts.com/forum/thread81534.html or http://groups-beta.google.com/group/comp.databases.ms-sqlserver/browse_frm/thread/ca9a9229d06a56f9?dq=&hl=en&lr=&ie=UTF-8&oe=UTF-8&prev=/groups%3Fdq%3D%26num%3D25%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26group%3Dcomp.databases.ms-sqlserver%26start%3D25 binary data to be converted to HexadecimalHexadecimal representation of binary data, using chars [0-0a-f] */ CREATE FUNCTION [dbo].[Tool_VarbinaryToVarcharHex] ( @VarbinaryValue VARBINARY(max) ) RETURNS VARCHAR(max) AS BEGIN DECLARE @NumberOfBytes INT SET @NumberOfBytes = DATALENGTH(@VarbinaryValue) -- PART ONE -- IF (@NumberOfBytes > 4) BEGIN DECLARE @FirstHalfNumberOfBytes INT DECLARE @SecondHalfNumberOfBytes INT SET @FirstHalfNumberOfBytes = @NumberOfBytes/2 SET @SecondHalfNumberOfBytes = @NumberOfBytes - @FirstHalfNumberOfBytes -- Call this function recursively with the two parts of the input split in half RETURN dbo.Tool_VarbinaryToVarcharHex(CAST(SUBSTRING(@VarbinaryValue, 1 , @FirstHalfNumberOfBytes) AS VARBINARY(max))) + dbo.Tool_VarbinaryToVarcharHex(CAST(SUBSTRING(@VarbinaryValue, @FirstHalfNumberOfBytes+1 , @SecondHalfNumberOfBytes) AS VARBINARY(max))) END IF (@NumberOfBytes = 0) BEGIN RETURN '' -- No bytes found, therefore no 'hex string' is returned END -- PART TWO -- DECLARE @LowByte INT DECLARE @HighByte INT -- @NumberOfBytes <= 4 (four or less characters/8 hex digits were input) -- eg. 88887777 66665555 44443333 22221111 -- We'll process ONLY the right-most (least-significant) Byte, which consists -- of eight bits, or two hexadecimal values (eg. 22221111 --> XY) -- where XY are two hex digits [0-f] -- 1. Carve off the rightmost four bits/single hex digit (ie 1111) -- BINARY AND 15 will result in a number with maxvalue of 15 SET @LowByte = CAST(@VarbinaryValue AS INT) & 15 -- Now determine which ASCII char value SET @LowByte = CASE WHEN (@LowByte < 10) -- 9 or less, convert to digits [0-9] THEN (48 + @LowByte) -- 48 ASCII = 0 ... 57 ASCII = 9 ELSE (87 + @LowByte) -- else 10-15, convert to chars [a-f] END -- (87+10)97 ASCII = a ... (87+15_102 ASCII = f -- 2. Carve off the rightmost eight bits/single hex digit (ie 22221111) -- Divide by 16 does a shift-left (now processing 2222) SET @HighByte = CAST(@VarbinaryValue AS INT) & 255 SET @HighByte = (@HighByte / 16) -- Again determine which ASCII char value SET @HighByte = CASE WHEN (@HighByte < 10) -- 9 or less, convert to digits [0-9] THEN (48 + @HighByte) -- 48 ASCII = 0 ... 57 ASCII = 9 ELSE (87 + @HighByte) -- else 10-15, convert to chars [a-f] END -- (87+10)97 ASCII = a ... (87+15)102 ASCII = f -- 3. Trim the byte (two hex values) from the right (least significant) input Binary -- in preparation for further parsing SET @VarbinaryValue = SUBSTRING(@VarbinaryValue, 1, (@NumberOfBytes-1)) -- 4. Recursively call this method on the remaining Binary data, concatenating the two -- hexadecimal 'values' we just decoded as their ASCII character representation -- ie. we pass 88887777 66665555 44443333 back to this function, adding XY to the result string RETURN dbo.Tool_VarbinaryToVarcharHex(@VarbinaryValue) + CHAR(@HighByte) + CHAR(@LowByte) END
*******************************************************************************
How to use it? you just simply execute exec UDP_SCRIPTDIAGRAM 'Diagram Name'
*******************************************************************************
Comments
Post a Comment