Technical Article

Trim Trailing Blanks in SQL Queries

,

If you like to copy-and-paste the text output from SQL SELECT statements, but don't like the wasted space of trailing blanks in wide varchar columns, you might find this script helpful. It will run your SQL SELECT statement and output the results so that the trailing blanks in varchar columns is neatly trimmed off.

Take a statement like this, run in the NorthWind database:

SELECT CustomerId, Address, City, Region, PostalCode FROM Customers WHERE Country = 'USA'

and run it like this:

EXEC spd_Tool_Reformat_Query_Results 'SELECT CustomerId, Address, City, Region, PostalCode FROM Customers WHERE Country = ''USA'''

/***************************************************************************************************
Written by:Jesse McLain
Purpose:Given a SQL SELECT statement, this spd will run it, saving the results in a temp
table, and query the temp table for the max size of the varchar columns. It will
then rerun the query, and limit the size of the output of those varchar columns 
to the max size it discovered. Typically this spd will be used to save metadata
in an ASCII text report.
Input Parameters:see below
Output Parameters:none
Called By:user
***************************************************************************************************/CREATE PROCEDURE [dbo].[spd_Tool_Reformat_Query_Results]
(
@sql varchar(8000),-- the SQL SELECT statement to generate the results
@print_sql char(1) = 'N'-- 'Y' if user wants to see SQL used to reformat results
)
AS


SET NOCOUNT ON
SET ANSI_WARNINGS OFF


IF @sql = 'help' OR @sql = '' OR @sql IS NULL OR LEFT(@sql, 6) <> 'SELECT'
BEGIN
PRINT 'PROCEDURE [dbo].[spd_Tool_Reformat_Query_Results] - parameters:'
PRINT '@sql varchar(8000)-- the SQL SELECT statement to generate the results'
PRINT '@print_sql char(1) = ''N''-- ''Y'' if user wants to see SQL used to reformat results'

RETURN
END


-- normalize incoming SQL statement; make sure that the only white space is space char:
SET @sql = REPLACE(@sql, CHAR(13), ' ')
SET @sql = REPLACE(@sql, CHAR(10), ' ')
SET @sql = REPLACE(@sql, CHAR(9), ' ')
WHILE CHARINDEX('  ', @sql) > 0 SET @sql = LTRIM(RTRIM(REPLACE(@sql, '  ', ' ')))-- replace double space with single


DECLARE @fnd smallint
DECLARE @fnd2 smallint
DECLARE @sql_target varchar(100)
SET @sql_target = ''
DECLARE @tmp varchar(8000)


-- we need to insert an "INTO" clause into the SQL:
SET @fnd = CHARINDEX(' INTO ', @sql)
IF @fnd > 0
BEGIN
-- if there already is one, then we replace it:
SET @tmp = SUBSTRING(@sql, @fnd + 6, DATALENGTH(@sql) - @fnd)
SET @fnd2 = CHARINDEX(' ', @tmp)
IF @fnd2 > 0
BEGIN
SET @sql_target = LEFT(@tmp, @fnd2 - 1)
SET @sql = REPLACE(@sql, ' INTO ' + @sql_target, ' INTO ##Tmp_Query_Results')
END
END
ELSE-- otherwise, the "INTO" clause goes before the "FROM" clause:
BEGIN
-- if there's not already an 'INTO' clause, then we'll find the 'FROM' clause and
-- insert our new 'INTO' just before it:
SET @fnd = CHARINDEX(' FROM ', @sql)
IF @fnd > 0
BEGIN
SET @sql = STUFF(@sql, @fnd, 0, ' INTO ##Tmp_Query_Results')
END
END


IF EXISTS(SELECT 1 FROM TempDb.dbo.Sysobjects WHERE Name = '##Tmp_Query_Results' AND Type = 'U') DROP TABLE ##Tmp_Query_Results
EXEC(@sql)

CREATE TABLE #Tmp_Col_Max_Size (Col_Max_Size int)

DECLARE @ColName varchar(200)
DECLARE @ColType varchar(20)
DECLARE @ColLength smallint
DECLARE @Col_Max_Size int

DECLARE Tmp_Table_Structure_Cursor CURSOR FOR
SELECT 
ColName = C.Name,
ColType = T.Name,
ColLength = C.Length
FROM TempDb.dbo.SysColumns C 
JOIN TempDb.dbo.SysObjects O ON O.Id = C.Id
JOIN TempDb.dbo.SysTypes T ON T.XType = C.XType
WHERE O.Name = '##Tmp_Query_Results'
AND T.Name <> 'sysname'
ORDER BY C.ColOrder

OPEN Tmp_Table_Structure_Cursor 

DECLARE @sql_refmt varchar(8000)
SET @sql_refmt = 'SELECT ' + CHAR(13) + CHAR(10) + CHAR(9)

FETCH NEXT FROM Tmp_Table_Structure_Cursor INTO @ColName , @ColType, @ColLength
WHILE @@FETCH_STATUS = 0
BEGIN
IF @ColType IN ('char', 'varchar', 'nchar', 'nvarchar')
BEGIN
TRUNCATE TABLE #Tmp_Col_Max_Size
IF @ColType IN ('nchar', 'nvarchar')
SET @sql = 'SELECT MAX(DATALENGTH(CONVERT(varchar(8000), ' + @ColName + '))) FROM ##Tmp_Query_Results'
ELSE
SET @sql = 'SELECT MAX(DATALENGTH(' + @ColName + ')) FROM ##Tmp_Query_Results'
INSERT INTO #Tmp_Col_Max_Size EXEC(@sql)
SELECT @Col_Max_Size = Col_Max_Size FROM #Tmp_Col_Max_Size

IF @Col_Max_Size IS NULL
SET @sql_refmt = @sql_refmt + @ColName + ' = LEFT(' + @ColName + ', 4), '
ELSE
SET @sql_refmt = @sql_refmt + @ColName + ' = LEFT(' + @ColName + ', ' + LTRIM(STR(@Col_Max_Size)) + '), '
END
ELSE
SET @sql_refmt = @sql_refmt + @ColName + ', '

SET @sql_refmt = @sql_refmt + CHAR(13) + CHAR(10) + CHAR(9)

FETCH NEXT FROM Tmp_Table_Structure_Cursor INTO @ColName , @ColType, @ColLength
END

CLOSE Tmp_Table_Structure_Cursor
DEALLOCATE Tmp_Table_Structure_Cursor


SET @sql_refmt = LEFT(@sql_refmt, LEN(@sql_refmt) - 5) + CHAR(13) + CHAR(10) + 'FROM ##Tmp_Query_Results'
IF @print_sql = 'Y'
PRINT REPLACE(@sql_refmt, '##Tmp_Query_Results', '???')
PRINT ''
EXEC(@sql_refmt)


DROP TABLE ##Tmp_Query_Results
DROP TABLE #Tmp_Col_Max_Size

Rate

2.33 (3)

You rated this post out of 5. Change rating

Share

Share

Rate

2.33 (3)

You rated this post out of 5. Change rating