Date: 28 Nov 2011
There are several well publicised methods of generating data insert scripts for SQL Server tables and with good reason - until SQL 2008, this feature was not available through any of the Microsoft SQL Server management toolset. SQL 2008 does provide this function, as does SQL 2008 R2 (although Microsoft decided to move its location giving the initial impression that it had disappeared)
However, these methods all script text using the standard unicode text string i.e. N'This is text'.
There will always be some user (or 3rd party software vendor) who will ruin your day by including control characters or other non-text characters in the text data. Fun, fun, fun.
This script adopts a new approach by converting all characters in a text column into one Hex string.
These will be processed by a standard insert statement - you just have to look as some of the SQL Server Replication stored procedures to find examples of this (one of the common SQL Injection attacks is even delivered using strings in this format in attempt to mask the malicious intent of the string)
The code is not particularly performant for larger data volumes, but then this kind of task is normally required when setting up or transferring lookup table data between servers/databases. For larger data volumes, I would recommend using BCP in native format mode.
**NOTE: This code could be adapted for SQL 2000 by replacing the VARCHAR(MAX) variables with VARCHAR(8000), but the verbose nature of a hex string (just over 4 * the size) will limit the size of the text strings that can be processed
DROP PROCEDURE dbo.usp_generate_inserts
CREATE PROCEDURE dbo.usp_generate_inserts
SET NOCOUNT ON
IF ISNULL(CHARINDEX('.', @Table), 0) = 0
PRINT 'Procedure dbo.usp_generate_inserts expects a table_name parameter in the form of schema_name.table_name';
-- initialize variables as otherwise the padding will fail (return nulls for nvarchar(max) types)
SET @Is_Identity = 0;
SET @Columns = '';
SET @Values = '';
SET @Script = '';
The following select makes an assumption that the identity column should be included in
the insert statements. Such inserts still work when coupled with identity_insert toggle,
which is typically used when there is a need to "plug the holes" in the identity values.
Please note the special handling of the text data type. The type should never be present
in SQL Server 2005 tables because it will not be supported in future versions, but there
are unfortunately plenty of tables with text columns out there, patiently waiting for
someone to upgrade them to varchar(max).
@Is_Identity = @Is_Identity | COLUMNPROPERTY(OBJECT_ID(@Table), column_name, 'IsIdentity'),
@Columns = @Columns + ', ' + '['+ column_name + ']',
@Values + ' + '', '' + isnull(master.dbo.fn_varbintohexstr(cast(' +
WHEN 'text' THEN 'cast([' + column_name + '] as varchar(max))'
WHEN 'ntext' THEN 'cast([' + column_name + '] as nvarchar(max))'
ELSE '[' + column_name + ']'
END + ' as varbinary(max))), ''null'')'
WHERE table_name = SUBSTRING(@Table, CHARINDEX('.', @Table) + 1, LEN(@Table))
AND data_type != 'timestamp'
ORDER BY ordinal_position;
SET @Script =
'select ''insert into ' + @Table + ' (' + SUBSTRING(@Columns, 3, LEN(@Columns)) +
') values ('' + ' + SUBSTRING(@Values, 11, LEN(@Values)) + ' + '');'' from ' + @Table + ';';
IF @Is_Identity = 1
PRINT ('set identity_insert ' + @Table + ' on');
generate insert statements. If the results to text option is set and the query results are
completely fit then the prints are a part of the batch, but if the results to grid is set
then the prints (identity insert related) can be gathered from the messages window.
EXEC sp_executesql @Script;
IF @Is_Identity = 1
PRINT ('set identity_insert ' + @Table + ' off');
SET NOCOUNT OFF