Is the LIKE operator case-sensitive with SQL Server? - sql

In the documentation about the LIKE operator, nothing is told about the case-sensitivity of it. Is it? How to enable/disable it?
I am querying varchar(n) columns, on an Microsoft SQL Server 2005 installation, if that matters.

It is not the operator that is case sensitive, it is the column itself.
When a SQL Server installation is performed a default collation is chosen to the instance. Unless explicitly mentioned otherwise (check the collate clause bellow) when a new database is created it inherits the collation from the instance and when a new column is created it inherits the collation from the database it belongs.
A collation like sql_latin1_general_cp1_ci_as dictates how the content of the column should be treated. CI stands for case insensitive and AS stands for accent sensitive.
A complete list of collations is available at https://msdn.microsoft.com/en-us/library/ms144250(v=sql.105).aspx
(a) To check a instance collation
select serverproperty('collation')
(b) To check a database collation
select databasepropertyex('databasename', 'collation') sqlcollation
(c) To create a database using a different collation
create database exampledatabase
collate sql_latin1_general_cp1_cs_as
(d) To create a column using a different collation
create table exampletable (
examplecolumn varchar(10) collate sql_latin1_general_cp1_ci_as null
)
(e) To modify a column collation
alter table exampletable
alter column examplecolumn varchar(10) collate sql_latin1_general_cp1_ci_as null
It is possible to change a instance and database collations but it does not affect previously created objects.
It is also possible to change a column collation on the fly for string comparison, but this is highly unrecommended in a production environment because it is extremely costly.
select
column1 collate sql_latin1_general_cp1_ci_as as column1
from table1

All this talk about collation seem a bit over-complicated. Why not just use something like:
IF UPPER(##VERSION) NOT LIKE '%AZURE%'
Then your check is case insensitive whatever the collation

If you want to achieve a case sensitive search without changing the collation of the column / database / server, you can always use the COLLATE clause, e.g.
USE tempdb;
GO
CREATE TABLE dbo.foo(bar VARCHAR(32) COLLATE Latin1_General_CS_AS);
GO
INSERT dbo.foo VALUES('John'),('john');
GO
SELECT bar FROM dbo.foo
WHERE bar LIKE 'j%';
-- 1 row
SELECT bar FROM dbo.foo
WHERE bar COLLATE Latin1_General_CI_AS LIKE 'j%';
-- 2 rows
GO
DROP TABLE dbo.foo;
Works the other way, too, if your column / database / server is case sensitive and you don't want a case sensitive search, e.g.
USE tempdb;
GO
CREATE TABLE dbo.foo(bar VARCHAR(32) COLLATE Latin1_General_CI_AS);
GO
INSERT dbo.foo VALUES('John'),('john');
GO
SELECT bar FROM dbo.foo
WHERE bar LIKE 'j%';
-- 2 rows
SELECT bar FROM dbo.foo
WHERE bar COLLATE Latin1_General_CS_AS LIKE 'j%';
-- 1 row
GO
DROP TABLE dbo.foo;

You have an option to define collation order at the time of defining your table. If you define a case-sensitive order, your LIKE operator will behave in a case-sensitive way; if you define a case-insensitive collation order, the LIKE operator will ignore character case as well:
CREATE TABLE Test (
CI_Str VARCHAR(15) COLLATE Latin1_General_CI_AS -- Case-insensitive
, CS_Str VARCHAR(15) COLLATE Latin1_General_CS_AS -- Case-sensitive
);
Here is a quick demo on sqlfiddle showing the results of collation order on searches with LIKE.

The like operator takes two strings. These strings have to have compatible collations, which is explained here.
In my opinion, things then get complicated. The following query returns an error saying that the collations are incompatible:
select *
from INFORMATION_SCHEMA.TABLES
where 'abc' COLLATE SQL_Latin1_General_CP1_CI_AS like 'ABC' COLLATE SQL_Latin1_General_CP1_CS_AS
On a random machine here, the default collation is SQL_Latin1_General_CP1_CI_AS. The following query is successful, but returns no rows:
select *
from INFORMATION_SCHEMA.TABLES
where 'abc' like 'ABC' COLLATE SQL_Latin1_General_CP1_CS_AS
The values "abc" and "ABC" do not match in a case-sensitve world.
In other words, there is a difference between having no collation and using the default collation. When one side has no collation, then it is "assigned" an explicit collation from the other side.
(The results are the same when the explicit collation is on the left.)

Try running,
SELECT SERVERPROPERTY('COLLATION')
Then find out if your collation is case sensitive or not.

You can change from the property of every item.

You can easy change collation in Microsoft SQL Server Management studio.
right click table -> design.
choose your column, scroll down i column properties to Collation.
Set your sort preference by check "Case Sensitive"

Related

How to determine if SQLite column created with COLLATE NOCASE

A column in a SQLite db must be COLLATE NOCASE. I assume there is no way to add that capability to an existing table, so I'm prepare to recreate the table with it. How can I determine if the existing column is COLLATE NOCASE in order to avoid recreating the table every time it is opened?
How can I determine if the existing column is COLLATE NOCASE
The query
SELECT sql FROM sqlite_master WHERE type='table' AND tbl_name='my_table'
will give you the CREATE TABLE statement for that table. You could inspect the DDL to determine if the column is already defined as COLLATE NOCASE.
You might not need to do that at all if it is sufficient to change the collations in the query. I mean you can just overwrite it in the query. It won't affect constraints or index, but depending on your use case, it might be good enough.
To be clear: the collate clause in the table definition is just a default for the queries. You can overwrite this in the queries.
e.g.
WHERE column = 'term' COLLATE NOCASE
or
ORDER BY column COLLATE NOCASE
However, not that SQLite's LIKE doesn't honor collate clause (use pragma case_sensitive_like instead).
The easiest and most general way is store a version number somewhere (in another table, or with PRAGMA user_version).
If you want to check the column itself, use a query with a comparison that is affected by the column's collation:
SELECT Col = upper(Col)
FROM (SELECT Col
FROM MyTable
WHERE 0 -- don't actually return any row from MyTable
UNION ALL
SELECT 'x' -- lowercase; same collation as Col
);

Firebird order by collation

I am with strange problem with Firebird 2.5.
My database has default charset = utf8.
I have a column p_nname in patienten table:
CREATE TABLE PATIENTEN (
P_NNAME VARCHAR(25) DEFAULT '' NOT NULL COLLATE UNICODE_CI,
I expect collation to work everywhere. I mean in WHERE and ORDER BY clauses.
What I have is working collation in WHERE. Two queries below give me similar result and it is good.
select * from patienten where p_nname='adler'
select * from patienten where p_nname='ADler'
Problem is ORDER BY clause does not work as I expect.
This SQL works as if the column has no UNICODE_CI collation.
select * from patienten order by p_nname
To get the needed result with good sorting I have to write so:
select * from patienten order by p_nname collate unicode_ci
Is there a way to omit COLLATE flag in ORDER BY clause?
Looks like a bug indeed, the documentation states:
The keyword COLLATE specifies the collation order for a string column
if you need a collation that is different from the normal one for this
column. The normal collation order will be either the default one for
the database character set or one that has been set explicitly in the
column's definition.
so it should work without specifing the collate clause in ORDER BY. I suggest you file a bug report.

SQL query to search for lowercase strings

I want a SQL query which can search for a certain word, but only in lowercase.
I am trying
select * from employees where name like LOWER('%smith%')however, this does not bring back any results.
However, when I do
select * from employees where name like '%smith%' it returns employees with name SMITH and smith....in my case i just want it to return where employee names are lower-cased.
Thanks in advance!
Your default collation is likely set to a case-insensitive option. Put simply this causes all character comparison to be performed as if the sides of the comparison are of the same case, regardless of whether this is true or not.
You may use a COLLATE statement following the column name in the WHERE clause:
select * from employees where name COLLATE Latin1_General_CS_AS like '%smith%'
However, if you have a significant need for case-sensitive comparison you may wish to change the default collation of your database as explicitly marking collation is very verbose, as you can see.
Normally, in order to query a table in a case sensitive way, you would designate the column (or the entire database) with a case sensitive collation.
For performance reasons, that will be the preferred approach if you will be regularly performing case sensitive queries against this column.
However, in a pinch, you can specify the query collation on the fly. This comes at the cost of a more expensive query plan, so regard it as a last resort.
For example:
SELECT * FROM Employees
WHERE EmployeeName COLLATE SQL_Latin1_General_CP1_CS_AS
LIKE '%smith%'
There are a variety of case sensitive collations, so you will typically want to choose the one that is closest to the standard case insensitive collation you are using.
You can check that by running these statements to check the configured collation:
--Server level
SELECT SERVERPROPERTY('COLLATION')
--Database level
SELECT DATABASEPROPERTYEX('DatabaseName', 'Collation')
--Column level
USE DatabaseName
GO
SELECT name, collation_name
FROM sys.columns
WHERE OBJECT_ID IN (SELECT OBJECT_ID
FROM sys.objects
WHERE type = 'U'
AND name = 'TableName')
AND name = 'ColumnName'
Most likely these will all return the same value. For example, SQL_Latin1_General_CP1_CI_AS, in which case the collation you would use for case sensitive queries would be SQL_Latin1_General_CP1_CS_AS.
Depending on the result you get, you will want to select the related case-sensitive collation from this list.
Use collation COLLATE Latin1_General_CP1_CS_AS to explicit Case Sensitive,
default collation when installing SQL Server is SQL_Latin1_General_CP1_CI_AS
select * from employees where name COLLATE Latin1_General_CS_AS like '%smith%'
Where
CS: Case Sensitive
AS: Accent sensitive
You can also use Binary_checksum(lower()) function as below.
select * from employees where
BINARY_CHECKSUM(EmployeeName) = BINARY_CHECKSUM(Lower(EmployeeName))
Please note: If the column Employeename has null values, it lists the nulls as well in your results.

How to change the collation of sqlite3 database to sort case insensitively?

I have a query for sqlite3 database which provides the sorted data. The data are sorted on the basis of a column which is a varchar column "Name". Now when I do the query
select * from tableNames Order by Name;
It provides the data like this.
Pen
Stapler
pencil
Means it is considering the case sensitive stuff. The way I want is as follows
Pen
pencil
Stapler
So what changes should I make in sqlite3 database for the necessary results?
Related How to set Sqlite3 to be case insensitive when string comparing?
To sort it Case insensitive you can use ORDER BY Name COLLATE NOCASE
The SQLite Datatypes documentation discusses user-defined collation sequences. Specifically you use COLLATE NOCASE to achieve your goal.
They give an example:
CREATE TABLE t1(
a, -- default collation type BINARY
b COLLATE BINARY, -- default collation type BINARY
c COLLATE REVERSE, -- default collation type REVERSE
d COLLATE NOCASE -- default collation type NOCASE
);
and note that:
-- Grouping is performed using the NOCASE collation sequence (i.e. values
-- 'abc' and 'ABC' are placed in the same group).
SELECT count(*) GROUP BY d FROM t1;
select * from tableNames Order by lower(Name);
Michael van der Westhuizen explains in his comment below why this is not a good way. I am leaving this answer up so as to preserve his comment and to serve as a warning to others who might have the same 'bright' idea I had ;-)
Use this statement in your SQLite database:
PRAGMA case_sensitive_like = false

SQL Server 2005 collation issue

I have two tables, and they are using different collations. It is not allowed to concatenate columns from tables with different collations, for example the following SQL is not allowed,
select table1column1 + table2column2 from ...
My question is, how to change the collation of a table without destroying the data of the table?
thanks in advance,
George
You can change columns collation on the fly if you need to.
E.g.
select table1column1 collate database default + table2column2 collate database default from ...
"Database default" could be whatever the collation you are wanting to use.
You can alter the collation of a column permanently with
ALTER TABLE ... ALTER COLUMN Table1Column1
varchar(50) COLLATE Latin1_General_CI_AS NOT NULL
GO