Searching data from a column is a very common requirement – but with unique variants in each application. Recently, I came across one such requirement:
Underlying database, table and columns use a case in-sensitive (CI) collation
Application must be able to switch between a case sensitive v/s a case insensitive comparison
The ability to switch between a case sensitive and case insensitive comparison is the challenge because it needs to be done on a database that inherently does not discriminate between the two.
In this post, I will present one method of implementing this requirement. If you have any others that you would like to share, please feel free to do so in the comments area.
Temporarily using Case Sensitive Collations
The most common implementation pattern to realize the case sensitive search requirement is to temporarily use a collation that is case sensitive as shown below.
To begin with, let us create a test table and insert some fictional test data.
USE AdventureWorks2012; GO --Step 01: Create test data IF OBJECT_ID('dbo.Product','U') IS NOT NULL DROP TABLE dbo.Product; GO CREATE TABLE dbo.Product (ProductId INT NOT NULL IDENTITY(1,1), ProductName VARCHAR(100) NOT NULL, VendorName VARCHAR(100) ); GO --Add some test data INSERT INTO dbo.Product (ProductName, VendorName) VALUES ('Cycles','Contosso'), ('cBike', 'AdventureWorks'), ('SomeOtherProduct','SomeOtherVendor'); GO
Next, let us fetch the collation of the database where our test table resides. You may also want to use the system stored procedure (sp_help) to study the collation of the table columns (which by default would be same as that of the database in which the table resides). On my server, the collation was – [SQL_Latin1_General_CP1_CI_AS] which is case in-sensitive (notice the CI in the collation name).
--Step 02: Check the database collation USE AdventureWorks2012; GO SELECT DATABASEPROPERTYEX(N'AdventureWorks2012', N'Collation'); GO --For AdvenutreWorks2012 --SQL_Latin1_General_CP1_CI_AS --Check the collation of the table columns sp_help [dbo.Product]; GO
Now, attempt to query the table for all products whose names begin with the letter ‘c’ (small case). To do so, we need to temporarily COLLATE the column – dbo.Product.ProductName to a case sensitive collation (in my case, this is SQL_Latin1_General_CP1_CS_AS).
USE AdventureWorks2012; GO SELECT ProductId, ProductName, VendorName FROM dbo.Product WHERE ProductName COLLATE SQL_Latin1_General_CP1_CS_AS LIKE 'c%'; GO
As can be seen from the image below, desired results are obtained. However, if one has the actual execution plan opened up, an interesting observation can be made if we look at the properties of the SELECT operation.
We can observe that SQL Server internally uses the CONVERT function with a style of 0. Per Books On Line (see references below), this indicates a binary to character conversion. This conversion is performed for all records in the table, which in-turn affects performance.
Because we have the overhead of applying a conversion on all rows of a particular table, this method should be used only when the column cannot be modified to permanently use a case sensitive collation and a business need exists to provide both case sensitive & insensitive search.
- The COLLATE Keyword: https://msdn.microsoft.com/en-us/library/ms184391.aspx
- Refer Binary Styles in CAST and CONVERT: https://msdn.microsoft.com/en-us/library/ms187928.aspx
- System Stored Procedure sp_help: https://msdn.microsoft.com/en-us/library/ms187335.aspx
Until we meet next time,
Be courteous. Drive responsibly.