Search a value in your database in SQL Server

Here is a script to identify a value in your database. The script will identify the presence of the search value from all tables and generate select queries from the respective tables which you can execute and confirm.

	DECLARE @STRINGTOLOOKFOR VARCHAR(500)
		,@TABLENAME SYSNAME
		,@FULLTABLENAME SYSNAME
        --<-- Give the value to search------->
	SELECT @STRINGTOLOOKFOR = '7F0B0DD5-22BC-421B-9416-3A7C24146A98'  
        --<-- Give the value to search------->

	DECLARE @COLUMNNAME NVARCHAR(128),
		@DATETYPE NVARCHAR(128),
		@ROW SMALLINT,
		@ROWCOUNT INT,
		@SQL NVARCHAR(1000)
		
	DECLARE STRING_FIND_CURSOR CURSOR FAST_FORWARD FOR 
		
	SELECT TABLE_NAME, TABLE_SCHEMA+'.'+TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
	WHERE TABLE_TYPE ='BASE TABLE' 
	
	OPEN STRING_FIND_CURSOR
	
	FETCH NEXT FROM STRING_FIND_CURSOR 
	INTO @TABLENAME, @FULLTABLENAME
	
	SET @STRINGTOLOOKFOR = @STRINGTOLOOKFOR 
	
	WHILE @@FETCH_STATUS = 0
	BEGIN
		SET @ROW = 1
	
		SELECT @ROWCOUNT = MAX([ORDINAL_POSITION])
		FROM [INFORMATION_SCHEMA].[COLUMNS]
		WHERE [TABLE_NAME] = @TABLENAME 
		GROUP BY [ORDINAL_POSITION]
	
		WHILE @ROW  <= @ROWCOUNT
                BEGIN 
		SELECT @COLUMNNAME =  QUOTENAME(COLUMN_NAME) ,
			@DATETYPE = [DATA_TYPE]
		FROM [INFORMATION_SCHEMA].[COLUMNS]
		WHERE [TABLE_NAME] = @TABLENAME 
			AND [ORDINAL_POSITION] = @ROW
		ORDER BY [ORDINAL_POSITION]
	
		SET @ROW = @ROW + 1  
			
		SET @SQL = NULL
	
		IF @DATETYPE IN ( N'CHAR', N'VARCHAR', N'TEXT')
			SET @SQL = 'SELECT * FROM ' + @FULLTABLENAME + ' WHERE PATINDEX(''%' + @STRINGTOLOOKFOR + '%'', ' + @COLUMNNAME + ') > 0'
			IF @DATETYPE IN (N'UNIQUEIDENTIFIER') AND @STRINGTOLOOKFOR LIKE '[A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][-][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][-][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][-][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][-][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9][A-F,0-9]'
				SET @SQL = 'SELECT * FROM ' + @FULLTABLENAME + ' WHERE' + @COLUMNNAME + ' = ''' + @STRINGTOLOOKFOR + ''''
			IF @DATETYPE IN (N'NCHAR', N'NVARCHAR', N'NTEXT')
				SET @SQL = 'SELECT * FROM ' + @FULLTABLENAME + ' WHERE PATINDEX(''%' + @STRINGTOLOOKFOR + '%'', CAST(' + @COLUMNNAME + ' AS TEXT)) > 0'
			
			IF @DATETYPE IN (N'SQL_VARIANT',N'SMALLINT',N'INT',N'BIGINT',N'TINYINT')
				SET @SQL = 'SELECT * FROM ' + @FULLTABLENAME + ' WHERE CONVERT(VARCHAR(8000),' + @COLUMNNAME + ') LIKE ''%'+ @STRINGTOLOOKFOR + '%'''
			
			IF @SQL IS NOT NULL
			BEGIN
				SET @SQL = 'IF EXISTS(' + @SQL + ') PRINT ''SELECT '+@COLUMNNAME+' FROM ' + @FULLTABLENAME + ' WHERE ' + @COLUMNNAME + ' LIKE ''''%'+@STRINGTOLOOKFOR+'%'''''''
				EXEC (@SQL)
			END
		END
	
		FETCH NEXT FROM STRING_FIND_CURSOR 
		INTO @TABLENAME, @FULLTABLENAME

	END
	
	CLOSE STRING_FIND_CURSOR
	DEALLOCATE STRING_FIND_CURSOR
	
	

How to build comma separated string in SQL Server

Building a comma separated string is a very frequent&common requirement for SQL Server developers. Developers find different ways to achieve this like CLR/XML PATH/Co-related queries etc. With this post, we are going to see two options that are widely used XML PATH & string_AGG and a quick look at its performance comparison.

— Using STUFF & XML PATH

This is the most widely used method to build the comma separated string. In my personal experience, I observed many performance issues related to this method for a large set of data.


Drop Table if exists BuildCommaSeparatedString
Create Table BuildCommaSeparatedString(SessionID int, CourseID varchar(100))

Insert into BuildCommaSeparatedString Values 
(1,'English'),(1,'Maths'),(1,'Accountancy'),(2,'History'),(2,'Biology')

SELECT  SessionID,STUFF((SELECT  ',' + CourseID FROM BuildCommaSeparatedString EE
            WHERE  EE.SessionID=E.SessionID
            ORDER BY CourseID -- To order the Courses in order 
        FOR XML PATH('')), 1, 1, '') AS 'CommaseparatedString'
FROM BuildCommaSeparatedString E
GROUP BY E.SessionID


Sample Execution results — Using string_AGG in SQL Server 2017

With SQL Server 2017 release, there is a better way to do this using string_agg built-in function. The STRING_AGG() is an aggregate function that concatenates rows of strings into a single string, separated by a specified separator.

STRING_AGG ( input_string, separator ) [ order_clause ]

input_string - is the column name of any type that can convert to a comma separated string
separator - is the separator caharacter like , or ; etc
[ order_clause ] - specifies the sort order of concatenated results using WITHIN GROUP clause

WITHIN GROUP ( ORDER BY expression [ ASC | DESC ] )
Please note that, The STRING_AGG() ignores NULL and it does not add the separator for NULL when performing concatenation.

Drop Table if exists BuildCommaSeparatedString
Create Table BuildCommaSeparatedString(SessionID int, CourseID varchar(100))

Insert into BuildCommaSeparatedString Values 
(1,'English'),(1,'Maths'),(1,'Accountancy'),(2,'History'),(2,'Biology')

Select SessionID, STRING_AGG(CourseID,',') From BuildCommaSeparatedString Group by SessionID

--To build the comma separated string in an order way
Select SessionID, STRING_AGG(CourseID,',') within group (Order by CourseID asc) 
From BuildCommaSeparatedString Group by SessionID

Sample Execution results A quick look on Performance benefit

The below snapshot clearly indicates that the performance benefit of string_AGG built-in function over XML PATH approach.

Conclusion

If you are in SQL Server 2017 – use built-in function string_AGG instead of any other method. I have seen this outperform many times than a custom built code. If you do not agree or have any different experience, please share the specific case with an example for the benefits of readers. Thanks in advance!

How to remove special characters like TAB, Carriage Return, and Line Feed characters from string in SQL Server

Today, we are going to see a scenario where we need to remove special characters from a string in SQL Server. Let us discuss on few methods to achieve this “extended” trim functionality.

1. Option: Using REPLACE

REPLACE function can be effectively used to replace the special characters.

Script:

DECLARE @BaddataString NVARCHAR(max);
SET @BaddataString = 'my '+
			CHAR(10)+CHAR(10)+CHAR(10) +
			 'text   ' + 
			CHAR(9)+CHAR(10)+CHAR(13)+CHAR(32) + 
			 '     ' +
			CHAR(10)+CHAR(10)+CHAR(10);

SELECT 
           @BaddataString,
           LEN(@BaddataString)
           , REPLACE(REPLACE(REPLACE(RTRIM(@BaddataString),CHAR(9), ''),CHAR(10),''),CHAR(13),'') ,
           LEN(REPLACE(REPLACE(REPLACE(RTRIM(@BaddataString),CHAR(9), ''),CHAR(10),''),CHAR(13),''))


Here is the output of the below code:

2. Option: Using CDATA Another effective option to use CDATA method.

Script


/*
The below function replaces special characters like invisible TAB, Carriage Return, and Line Feed characters.
*/
CREATE FUNCTION dbo.FN_RemoveBadCharacter(@input VARCHAR(MAX))
   RETURNS VARCHAR(MAX)
AS
BEGIN 
   RETURN (SELECT CAST('' AS XML).value('(/r/text())[1] cast as xs:token?','VARCHAR(MAX)'));
END
GO
DECLARE @BaddataString NVARCHAR(max);
SET @BaddataString = 'my '+
						CHAR(10)+CHAR(10)+CHAR(10) +
					 'text   ' + 
						CHAR(9)+CHAR(10)+CHAR(13)+CHAR(32) + 
					 '     ' +
						CHAR(10)+CHAR(10)+CHAR(10);

SELECT		@BaddataString, 
		LEN(@BaddataString)
			, dbo.FN_RemoveBadCharacter(@BaddataString),
		LEN(dbo.FN_RemoveBadCharacter(@BaddataString))

Here is the output of the below code:

3. Option: Using CLR to define a function to remove

There are certain things its best to do at application code rather than T-SQL. SQL Server may not be the best place to formatting string, date etc. There will be lots of available resources just away from a google search.

Hope, you enjoy this post, please share your thoughts as always!

Windows Power Shell Script to Find Full File Path Length for all files in Directory

In some cases, we may need to identify the maximum length of full file path in a directory such that we can reduce the file name to avoid file length/security policy issues.

PS Script:-

$pathToScan = "C:\temp\File_Length"  
$outputFilePath = "C:\temp\File_Length\output.txt" 
$writeOnConsole = $true   

$outputDir = Split-Path $outputFilePath -Parent
if (!(Test-Path $outputDir)) { New-Item $outputDir -ItemType Directory }

if ($writeOnConsole) {Write-Host "*************************************"}
if ($writeOnConsole) {Write-Host "  List of files with file Length :-  "}
if ($writeOnConsole) {Write-Host "*************************************"}
$stream = New-Object System.IO.StreamWriter($outputFilePath, $false)
Get-ChildItem -Path $pathToScan -Recurse -Force | Sort-Object {($_.FullName.Length)} -Descending | ForEach-Object {
    $Path = $_.FullName
    $len = $_.FullName.Length
    $strg = "$len : $Path"
    
    if ($writeOnConsole) { Write-Host $strg }

    $stream.WriteLine($strg)
}
$stream.Close()

Output:-

Hope this would be helpful, thanks for reading !!

For more Powershell related blogs: refer here.

 

Curious case of varchar to uniqueidentifier in SQL Server

Converting a datatype to another datatype is a very common requirement in real world and we usually do it with CAST or CONVERT (eg. int to char or varchar etc).

There are two types of conversions – implicit and explicit.

Explicit conversions are the conversions done by developers using SQL server functions like cast/convert etc and Implicit conversions are mainly managed by SQL Server internally. If you want to see these types of conversions, you can check for IMPLICIT_CONVERT in the execution plan generated by SQL Server.

Today, we are going to see a curious case of an implicit conversion – varchar to uniquidentifier.

SQL Server does a implicit conversion from varchar to uniqueidentifier by default as below:

Declare @varchar nvarchar(MAX), @uniqueidentifier uniqueidentifier
Set @varchar ='f124656c-136b-4beb-ab3a-b348053f898a,7f0b0dd5-22bc-421b-9416-3a7c24146a98'

Set @uniqueidentifier = @varchar
Select @uniqueidentifier

Now, if you look at the results, you can see the first 36 character is being converted implicitly. Since its a trivial, the operator may not be able to see in your execution plan.

The word of caution

Sometimes, if we are assigning more values/characters in the varchar variable, it would ONLY pick the first 36 characters and ignoring the rest characters by default. This default character of the conversion may end up with a wrong results, however, there would not be any sign of error! So beware of this characteristic while you writing a code.

Windows Power Shell script to Purge/Cleanup Backup & Transaction files

At times, we need to purge backup files (.bak, *.trn) which are older than some x days from the server on the regular basis, such that Disk Space and SQL Data backups will be maintained consistently within the server.

Power Shell Script:-

The below power shell script will purge the backup files (which are older than 5 days) from server, this script identifies the older files based on the last modified date time.

Based on your requirement, you can change the date range and schedule this script for Server Maintenance.

Get-ChildItem -Path "C:\Backups" -Recurse -ErrorAction SilentlyContinue -include *.bak, *.trn | 
Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-5) -and $_.PSIsContainer -eq $False} | 
Remove-Item

How to get list of filenames in a folder – Command Shell Script

There may be some situation where you want to find the list of all filenames whose patterns are like “*.txt”, “File*.csv”, “*.html”.., etc. In such scenario you can use the below command shell scripts to get the desired results which you are looking for.

1) To get the list of all filenames and folder names present in a folder “C:\testdata\”

cd "C:\testdata\"
dir /b /s

Output:-

2) To get all the filenames of pattern “*.txt” or “*.html” from folder “C:\testdata\”

dir /b /s "*.txt"
dir /b /s "*.html"

Output:-

3) To get all the filenames of pattern “*.txt” from folder “C:\testdata\” and store the corresponding results in the text document

dir /b /s "*.txt" > output.txt
dir /b /s "*.txt" > "c:\testdata\test\outputs.txt"

Output:-