Why is this query MySQL query running case-sensitive?

Asked
Active3 hr before
Viewed126 times

6 Answers

runningquery
90%

MySQL queries are not case-sensitive by default. Following is a simple query that is looking for 'value'. However it will return 'VALUE', 'value', 'VaLuE', etc…,Whilst the listed answer is correct, may I suggest that if your column is to hold case sensitive strings you read the documentation and alter your table definition accordingly.,The good news is that if you need to make a case-sensitive query, it is very easy to do using the BINARY operator, which forces a byte by byte comparison:,How can I make it return only Sellers with Location 'San Jose' instead of 'san jose' or something else?

MySQL queries are not case-sensitive by default. Following is a simple query that is looking for 'value'. However it will return 'VALUE', 'value', 'VaLuE', etc…

SELECT * FROM `table`
WHERE `column` = 'value'

The good news is that if you need to make a case-sensitive query, it is very easy to do using the BINARY operator, which forces a byte by byte comparison:

SELECT * FROM `table`
WHERE BINARY `column` = 'value'
load more v
88%

Partition, subpartition, column, index, stored routine, event, and resource group names are not case-sensitive on any platform, nor are column aliases. , However, names of logfile groups are case-sensitive. This differs from standard SQL. , By default, table aliases are case-sensitive on Unix, but not so on Windows or macOS. The following statement would not work on Unix, because it refers to the alias both as a and as A: , Although database, table, and trigger names are not case-sensitive on some platforms, you should not refer to one of these using different cases within the same statement. The following statement would not work because it refers to a table both as my_table and as MY_TABLE:

Although database, table, and trigger names are not case-sensitive on some platforms, you should not refer to one of these using different cases within the same statement. The following statement would not work because it refers to a table both as my_table and as MY_TABLE:

mysql > SELECT * FROM my_table WHERE MY_TABLE.col = 1;
load more v
72%

MySQL queries are not case-sensitive by default. It is possible that you have created case sensitive tables when importing data. Check if you have utf8_unicode_cs collation, that makes it case-sensitive. Reimport your data then using utf8_general_ci.,MySQL docs: Identifier Case Sensitivity ,Your collations changed when re-importing data.,2) Restart the database so that all database table names are now created in lower-case.

1) Edit the MySQL configuration file (i.e. /etc/my.cnf), and add the following line in [mysqld] heading.

lower_case_table_names = 1
load more v
65%

Another way for case-insensitive matching is to use a different “collation”. The default collations used by SQL Server and MySQL do not distinguish between upper and lower case letters—they are case-insensitive by default.,Case-Insensitive Search Using UPPER or LOWER,Ignoring the case in a where clause is very simple. You can, for example, convert both sides of the comparison to all caps notation:,FunctionsCase-Insensitive Search Using UPPER or LOWERUser-Defined FunctionsOver-Indexing

Ignoring the case in a where clause is very simple. You can, for example, convert both sides of the comparison to all caps notation:

SELECT first_name, last_name, phone_number
FROM employees
WHERE UPPER(last_name) = UPPER('winand')
Explain Plan
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
ID | Operation | Rows | Cost
1 | RETURN | | 690
2 | TBSCAN EMPLOYEES | 400 of 10000(4.00 % ) | 690

Predicate Information
2 - SARG(UPPER(Q1.LAST_NAME) = 'WINAND')
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
Id | Operation | Name | Rows | Cost |
   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
   |
   0 | SELECT STATEMENT | | 10 | 477 |
   |
   * 1 | TABLE ACCESS FULL | EMPLOYEES | 10 | 477 |
   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

Predicate Information(identified by operation id):
   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
   1 - filter(UPPER("LAST_NAME") = 'WINAND')
                     QUERY PLAN
                     -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
                     Seq Scan on employees
                        (cost = 0.00. .1722 .00 rows = 50 width = 17)
                     Filter: (upper((last_name)::text) = 'WINAND'::text)

This is a trap we all might fall into. We recognize the relation between LAST_NAME and UPPER(LAST_NAME) instantly and expect the database to “see” it as well. In reality the optimizer’s view is more like this:

SELECT first_name, last_name, phone_number
FROM employees
WHERE BLACKBOX(...) = 'WINAND'

To support that query, we need an index that covers the actual search term. That means we do not need an index on LAST_NAME but on UPPER(LAST_NAME):

CREATE INDEX emp_up_name
ON employees(UPPER(last_name))
Explain Plan
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
ID | Operation | Rows | Cost
1 | RETURN | | 13
2 | FETCH EMPLOYEES | 1 of 1(100.00 % ) | 13
3 | IXSCAN EMP_UP_NAME | 1 of 10000(.01 % ) | 6

Predicate Information
3 - START(UPPER(Q1.LAST_NAME) = 'WINAND')
STOP(UPPER(Q1.LAST_NAME) = 'WINAND')
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
Id | Operation | Name | Rows | Cost |
   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
   |
   0 | SELECT STATEMENT | | 100 | 41 |
   |
   1 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 100 | 41 |
   |
   * 2 | INDEX RANGE SCAN | EMP_UP_NAME | 40 | 1 |
   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

Predicate Information(identified by operation id):
   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
   2 - access(UPPER("LAST_NAME") = 'WINAND')
                       QUERY PLAN
                       -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
                       Bitmap Heap Scan on employees
                          (cost = 4.65. .178 .65 rows = 50 width = 17)
                       Recheck Cond: (upper((last_name)::text) = 'WINAND'::text) -
                          > Bitmap Index Scan on emp_up_name(cost = 0.00. .4 .64 rows = 50 width = 0)
                       Index Cond: (upper((last_name)::text) = 'WINAND'::text)
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
Id | Operation | Name | Rows | Cost |
   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
   |
   0 | SELECT STATEMENT | | 1 | 3 |
   |
   1 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 1 | 3 |
   |
   * 2 | INDEX RANGE SCAN | EMP_UP_NAME | 1 | 1 |
   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

Predicate Information(identified by operation id):
   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
   2 - access(UPPER("LAST_NAME") = 'WINAND')
                      QUERY PLAN
                      -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
                      Index Scan using emp_up_name on employees
                         (cost = 0.00. .8 .28 rows = 1 width = 17)
                      Index Cond: (upper((last_name)::text) = 'WINAND'::text)

Since MySQL 5.7 you can index a generated columns as follows:

ALTER TABLE employees
ADD COLUMN last_name_up VARCHAR(255) AS(UPPER(last_name));
CREATE INDEX emp_up_name ON employees(last_name_up);
ALTER TABLE employees ADD last_name_up AS UPPER(last_name)
CREATE INDEX emp_up_name ON employees(last_name_up)
load more v
75%

--Use BINARY to make LIKE sensitive
SELECT 'abc'
LIKE BINARY 'ABC';
--0
load more v
40%

To check if a specific SQL Server database is case sensitive, run this query: SELECT collation_name FROM sys.databases WHERE name = 'your_database_name' Again, this will output something like: SQL_Latin1_General_CP1_CI_AS,Another command for checking the case-sensitivity and other properties of the database server is:,To check if a server is case sensitive, run this query: SELECT SERVERPROPERTY('COLLATION') A common result is: SQL_Latin1_General_CP1_CI_AS The CI indicates that the server is case insensitive., How to Check Case-Sensitivity in SQL Server (this article)

SELECT SERVERPROPERTY('COLLATION')
SQL_Latin1_General_CP1_CI_AS
load more v

Other "running-query" queries related to "Why is this query MySQL query running case-sensitive?"