About This Blog

.net & SQL Samples, programming tips and tricks, performance tips, guidelines, and best practices
Showing posts with label MS SQL Server 2005. Show all posts
Showing posts with label MS SQL Server 2005. Show all posts

Sunday, 14 October 2012

SQL Server # TSQL to Convert STRING in PROPER format

Problem Statement

SQL Server has got in-built functions to convert the given string into LOWER() or UPPER() format but it does not provides any direct way to convert it to PROPER format. A string/text is said to be in a PROPER format if all the words in that string/text starts with a CAPITAL letter.

E.g. If a string is - “Hello, how are you?”,

String in Lower format = “hello, how are you?”

String in Upper format = “HELLO, HOW ARE YOU?”

and String in Proper format = “Hello, How Are You?”

 

Implementation

Ideally, SQL Server is not the right place to implement this kind of logic, as string operations are costlier in SQL from performance perspective. it should be either implemented in the Front-End language or the Reporting Tool as this more related to the formatting. However, if this is to be implemented in SQL, the more preferred way is to use SQL-CLR function. It does not mean that we can not achieve this with T-SQL.

Today, I will share a simple T-SQL function, which could be used to convert any given string in PROPER format. Below is the script -

CREATE FUNCTION [dbo].[PROPER]
(
  @StrToConvertToProper AS VARCHAR(MAX)
) 
RETURNS VARCHAR(MAX) 
AS
BEGIN
  --Trim the Text
  SET @StrToConvertToProper = LTRIM(RTRIM(@StrToConvertToProper))
 
  --Find the No. of Words in the Text
  DECLARE @WordCount AS INT
  SET @WordCount = LEN(@StrToConvertToProper) - LEN(REPLACE(@StrToConvertToProper,' ','')) + 1
 
  --Variable to track the space position
  DECLARE @LastSpacePosition AS INT = 0
 
  --Loop through all the words
  WHILE(@WordCount > 0)
    BEGIN
      --Set the Space Position
      SET @LastSpacePosition = CHARINDEX(' ',@StrToConvertToProper,@LastSpacePosition + 1)
      
      --Replace the Character
      SET @StrToConvertToProper = STUFF(@StrToConvertToProper,
                                        @LastSpacePosition + 1,
                                        1,
                                        UPPER(SUBSTRING(@StrToConvertToProper, @LastSpacePosition + 1, 1)))
      --Decrement the Loop counter                                      
      SET @WordCount = @WordCount - 1
    END
    
  RETURN @StrToConvertToProper
END  

When the above script is used as –



SELECT dbo.PROPER('hello, how are you?')


we get the following result - Hello, How Are You?


Conclusion


The given script could be used to convert any string in PROPER format using T-SQL. However, I would personally prefer converting the string at the Front-End or in the Reporting tool to display the string in this format.

Thursday, 12 January 2012

Fragmented Index – Rebuild or Reorganize ?

Introduction
In past, many times I have written on Fragmentation of Indexes and how to Defrag them. You can find some related articles at -
After this, many of my readers have queried me for-
  1. What is the basic difference between ReBuild & ReOrganizing an Index?
  2. When to use what?
So, today I will address these two specific queries and also show a handy TSQL which could be used to remove Index fragmentation.
ReBuilding Index means the Index will be ReBuild from scratch using the same definition of its creation. It is same as using DBCC DBREINDEX. Please note that for new development do no use DBCC DBREINDEX as its deprecated from SQL Server 2005 onwards. It is generally preferred to rebuild OFFLINE. However, rebuild could be done ONLINE by specifying appropriate options.
ReOrganizing Index means the data at the Index leaf will be re-organized and the fragments will be removed to the max possible extent. It is same as using DBCC INDEXDEFRAG. Please note that for new development do no use DBCC INDEXDEFRAG as its deprecated from SQL Server 2005 onwards. ReOrganizing an Index is an ONLINE process.
When to use what – As per Microsoft, the recommendations are as under -
If Avg. Fragmentation < 5%, no action is required
else if 5% < Avg. Fragmentation <= 30%, reorganization is required
else if Avg. Fragmentation > 30%, rebuild is required
So, based on the above recommendations, the below TSQL could be used to serve the purpose -
USE DBName
GO
 
DECLARE @tsql NVARCHAR(MAX)  
DECLARE @fillfactor INT
 
SET @fillfactor = 70 
 
DECLARE @FragmentedIndexs TABLE (IndexID INT,
                                 IndexName VARCHAR(100),
                                 ObjectName VARCHAR(100),
                                 AvgFragmentationInPercent DECIMAL(6,2),
                                 FragmentCount INT,
                                 AvgFragmentSizeInPage DECIMAL(6,2),
                                 IndexDepth INT)
 
--Insert the Details for Fragmented Indexes.
INSERT INTO @FragmentedIndexs
SELECT 
  PS.index_id,
  QUOTENAME(I.name) Name,
  QUOTENAME(DB_NAME()) +'.'+ QUOTENAME(OBJECT_SCHEMA_NAME(I.[object_id])) + '.' + QUOTENAME(OBJECT_NAME(I.[object_id])) ObjectName,
  PS.avg_fragmentation_in_percent,
  PS.fragment_count,
  PS.avg_fragment_size_in_pages,
  PS.index_depth
FROM 
  sys.dm_db_index_physical_stats (DB_ID(), NULL ,NULL, NULL, NULL) AS PS
INNER JOIN sys.indexes AS I 
  ON PS.[object_id]= I.[object_id]
  AND PS.index_id = I.index_id
WHERE
  PS.avg_fragmentation_in_percent > 5  
ORDER BY 
  PS.avg_fragmentation_in_percent DESC
 
--Select the details.
SELECT * FROM @FragmentedIndexs
 
--Prepare the Query to REORGANIZE the Indexes
SET @tsql = ''
 
SELECT @tsql = 
  STUFF(( SELECT DISTINCT 
           ';' + 'ALTER INDEX ' + FI.IndexName + ' ON ' + FI.ObjectName + ' REORGANIZE '
          FROM 
           @FragmentedIndexs FI
          WHERE
            FI.AvgFragmentationInPercent <= 30
          FOR XML PATH('')), 1,1,'')
  
SELECT @tsql
PRINT 'REORGANIZING START'
EXEC sp_executesql @tsql 
PRINT 'REORGANIZING END'
 
--Prepare the Query to REBUILD the Indexes
SET @tsql = ''
 
SELECT @tsql = 
  STUFF(( SELECT DISTINCT 
           ';' + 'ALTER INDEX ' + FI.IndexName + ' ON ' + FI.ObjectName + ' REBUILD WITH (FILLFACTOR = ' + CONVERT(VARCHAR(3),@fillfactor) + ') '
          FROM 
           @FragmentedIndexs FI
          WHERE
            FI.AvgFragmentationInPercent > 30
          FOR XML PATH('')), 1,1,'')
  
SELECT @tsql
PRINT 'REBUILD START'
EXEC sp_executesql @tsql
PRINT 'REBUILD END'

Conclusion

To keep the indexes in proper shape, a timely defragmentation is necessary. When to defragment has got no THUMB RULE, it depends on the environment. However, the above script could be scheduled as per ones need to make sure that the indexes gets defragmented when need.

Wednesday, 7 December 2011

How many times the T-SQL inside the CTE is executed?

Introduction

Common Table Expression (CTE) has become very popular these days. However, many users of CTE still have a myth that the t-sql written inside the CTE will be executed only once irrespective of the number of times it is referred in the subsequent CTEs or the related query.
However, this is not correct. It is a pure misconception. And let’s try to prove this with a simple example.

Proof
The Query
;WITH CTE1 AS (
SELECT
* 
FROM
dbo.Employees
),CTE2 AS (
SELECT
*
FROM
CTE1
)
SELECT
C1.EmployeeID,
C1.Name,
C2.EmployeeID,
C2.Name,
C3.EmployeeID,
C3.Name
FROM
CTE1 C1
INNER JOIN CTE2 C2
ON C2.EmployeeID = C1.EmployeeID
INNER JOIN CTE1 C3
ON C3.EmployeeID = C1.EmployeeID

Execution Plan

CTE

Please have a look at the execution plan. It clearly shows that even though the t-sql to fetch the data from the table is written only once inside CTE1, the Scan is done thrice. This is because CTE1 is referred thrice in the final query -
  1. Two times CTE1 is directly used.
  2. Once CTE1 is used indirectly via CTE2.
Conclusion
The CTE should be thought of a view that is defined for the current query only. At the time of execution, the query optimizer will replace all the direct/indirect use of CTE with the actual query in the same way as it does for Views.

Saturday, 1 October 2011

How to find out which Table is not having rows in SQL Server?

 

Introduction

Many times while tuning our production databases we might try to find out the list of tables not having even a single row of data. Today, I am going to show a simple script which could be used to get a list of tables having ZERO rows.

Script

USE DBName --Change this to the DB Name you want to script for.
GO
 
DECLARE @TableRowCount TABLE
( 
    TableName VARCHAR(255), 
    RowCnt INT 
) 
   
INSERT @TableRowCount 
  EXEC sp_msForEachTable 'SELECT PARSENAME(''?'', 1),COUNT(*) FROM ?' 
 
SELECT 
    * 
FROM 
  @TableRowCount 
WHERE
    RowCnt = 0     
ORDER BY 
  RowCnt 
 
    

Friday, 30 September 2011

How to find a string value in all the string columns of a table/view in SQL Server ?

 

Introduction

I am sure many times we all might have come across situations where we need to search/find a string value in all the string columns of a given table/view in SQL Server and return the matching rows from that table.

Unfortunately, we do not have any straight forward way to do this till date AFAIK. Hence, the below script can prove to be quite handy in this situation -

USE DBName --Replace with the DB in which the table resides
GO
 
--Declare variables and initialize them
DECLARE @TableSchema AS VARCHAR(50) = 'SchemaName' --Replace this with the name of Schema of the Table/View
DECLARE @TableName AS VARCHAR(50) = 'TableName' --Replace this with the name of the Table/View to search
DECLARE @SearchString AS VARCHAR(50) = 'SearchString' --Replace this with actual SearchString
 
DECLARE @Qry AS NVARCHAR(MAX)
DECLARE @Columns AS VARCHAR(MAX)
 
--Prepare the columns
SET @Columns = STUFF((
SELECT 
  '+' + CASE WHEN IS_NULLABLE = 'YES' THEN 'ISNULL(' + C.COLUMN_NAME + ','''')' ELSE C.COLUMN_NAME END
FROM 
  INFORMATION_SCHEMA.COLUMNS C
WHERE
  C.TABLE_SCHEMA = COALESCE(@TableSchema,C.TABLE_SCHEMA)
  AND C.TABLE_NAME = COALESCE(@TableName,C.TABLE_NAME)
  AND C.DATA_TYPE IN ('CHAR','NCHAR','NTEXT','NVARCHAR','TEXT','VARCHAR')
FOR XML PATH('')),1,1,'')
 
--Prepare the Query
SET @Qry = N' SELECT ' +
            '  * ' +
            ' FROM ' +
            @TableSchema + '.' + @TableName +
            ' WHERE  ' +
              @Columns + ' LIKE ''%' + @SearchString + '%'''  
 
--Execute the Query
EXEC SP_EXECUTESQL @Qry

Please note that the above script works only for the following column types - CHAR,NCHAR,NTEXT,NVARCHAR,TEXT,VARCHAR


Njoy searching….

Monday, 22 August 2011

T-SQL to find Fragmented Indexes


Fragmentation of Indexes is one of the reason for low performing queries resulting in a poor application performance.
Today, I will present a simple script which will help in identifying the level of fragmentation in a Database.
--Replace this with the name of the Database for which we want to find the fragmentation.
USE <DBName> 
GO
 
DECLARE @DBName AS VARCHAR(10) = 'DBName'
DECLARE @DBID AS INT = DB_ID(@DBName)
DECLARE @AllowedFragmentation AS INT = 70 --A acceptable value in Percent(%) for fragmentation.
DECLARE @Qry AS VARCHAR(MAX)
 
SELECT
--@DBID [DBID],
--@DBName DBName,
PS.OBJECT_ID ObjectID,
COALESCE(T.name,V.name) ObjectName,
PS.index_id,
I.name IndexName,
PS.page_count AS TotalPages,
(PS.page_count * 8)/1024.0 as TotalMB,
((PS.page_count * 8)/1024.0) * (PS.avg_fragmentation_in_percent/100) as ReclaimableMB,
PS.avg_fragmentation_in_percent AvgFragmentationPercent
FROM
sys.dm_db_index_physical_stats (@DBID, NULL, NULL, NULL, NULL) AS PS
INNER JOIN sys.indexes AS I
ON PS.OBJECT_ID = I.OBJECT_ID
AND PS.index_id = I.index_id  
LEFT JOIN sys.tables T
ON T.object_id = I.object_id
LEFT JOIN sys.views V
ON V.object_id = I.object_id
WHERE
PS.database_id = @DBID
AND PS.avg_fragmentation_in_percent > @AllowedFragmentation 
ORDER BY    
PS.avg_fragmentation_in_percent DESC 

Here, I have considered 70% fragmentation as an acceptable level of fragmentation.

Hope, this helps.