ChatGPT解决这个技术问题 Extra ChatGPT

How to make "case-insensitive" query in Postgresql?

Is there any way to write case-insensitive queries in PostgreSQL, E.g. I want that following 3 queries return same result.

SELECT id FROM groups where name='administrator'

SELECT id FROM groups where name='ADMINISTRATOR'

SELECT id FROM groups where name='Administrator'
if citext comes with your Postgres installation, try citext type. It's case-insensitive text
For newcomers to this question, this link to official postgres documentation contains all the answers given here, as well as a few other options.
Sir reassign accepted answer to the one made by @Arun please. It is much less complicated and do not pull bunch of troubles after apply.

C
Chandu

Use LOWER function to convert the strings to lower case before comparing.

Try this:

SELECT id 
  FROM groups
 WHERE LOWER(name)=LOWER('Administrator')

It's important to note that using LOWER (or any function) on the predicate columns--in this case "name"--will cause any indexes to no longer be seekable. If this is a large or frequently queried table, that could cause trouble. Case-insensitive collation, citext, or a function-based index will improve performance.
Or just create an index like this: CREATE INDEX idx_groups_name ON groups lower(name);
Also specify varchar_pattern_ops if you want the index to work with LIKE 'xxx%' query, i.e. CREATE INDEX ix_groups_name ON groups (lower(name) varchar_pattern_ops).
Using the ILIKE operator (as shown in other answers below) is a simpler approach, even though this is the most voted answer.
Going through the comments here, a lot of suggestions here suggests ILIKE, It will work, but with slow response. To obtain fast access to tables based on the results of computations, I suggest anyone just checking this should go with the accepted answer. See more details here and here
M
Matthew Lock

using ILIKE instead of LIKE

SELECT id FROM groups WHERE name ILIKE 'Administrator'

Note that ILIKE is not supported by Hibernate when used in Spring Boot.
@AnT it works with org.hibernate.dialect.PostgreSQL94Dialect and Spring Boot 2.0.6.RELEASE. But IntelliJ complains about it.
Is ilike going to be much slower? Especially when the field is indexed?
M
Mike Sherrill 'Cat Recall'

The most common approach is to either lowercase or uppercase the search string and the data. But there are two problems with that.

It works in English, but not in all languages. (Maybe not even in most languages.) Not every lowercase letter has a corresponding uppercase letter; not every uppercase letter has a corresponding lowercase letter. Using functions like lower() and upper() will give you a sequential scan. It can't use indexes. On my test system, using lower() takes about 2000 times longer than a query that can use an index. (Test data has a little over 100k rows.)

There are at least three less frequently used solutions that might be more effective.

Use the citext module, which mostly mimics the behavior of a case-insensitive data type. Having loaded that module, you can create a case-insensitive index by CREATE INDEX ON groups (name::citext);. (But see below.) Use a case-insensitive collation. This is set when you initialize a database. Using a case-insensitive collation means you can accept just about any format from client code, and you'll still return useful results. (It also means you can't do case-sensitive queries. Duh.) Create a functional index. Create a lowercase index by using CREATE INDEX ON groups (LOWER(name));. Having done that, you can take advantage of the index with queries like SELECT id FROM groups WHERE LOWER(name) = LOWER('ADMINISTRATOR');, or SELECT id FROM groups WHERE LOWER(name) = 'administrator'; You have to remember to use LOWER(), though.

The citext module doesn't provide a true case-insensitive data type. Instead, it behaves as if each string were lowercased. That is, it behaves as if you had called lower() on each string, as in number 3 above. The advantage is that programmers don't have to remember to lowercase strings. But you need to read the sections "String Comparison Behavior" and "Limitations" in the docs before you decide to use citext.


About #1: It shouldn't be a problem, since it would be two different strings (think of it like doing col = 'a' and col = 'b'). About #2: As you said, you can create an index on an expression, so it's not really a problem. But I agree with you that changing the collation is most likely the best solution.
Can someone tell me what case-insensitive collations are PostgreSQL built-in collations ? I see this as an option but can't find anything about a case-insensitive collation for Postgres on the net ?
@AnupShah: No, I'm not saying that. I'm not running PostgreSQL on Windows. The 9.4 docs say this: "On all platforms, the collations named default, C, and POSIX are available. Additional collations may be available depending on operating system support." You can see which collations PostgreSQL thinks are available with select * from pg_collation;.
@Matthieu: This is best introduction (and caution) to the subject that I know about: Edge Cases to Keep in Mind. Part 1 – Text.
M
Matthieu

You can use ILIKE. i.e.

SELECT id FROM groups where name ILIKE 'administrator'

Its correct and working fine for me, I am using MAC OS X(Mountain Lion).
This will work, but with slow response. To obtain fast access to tables based on the results of computations, I suggest to use the lower function. See more details
@AfolabiOlaoluwaAkinwumi fundamentally this comes down to whether you're searching for results opposed to filtering known values. In the latter case, a single uniform case should be persisted at the data level allowing the equality operator to work. [Personal recommendation is upper pascal case for type code values]
b
biegleux

You can also read up on the ILIKE keyword. It can be quite useful at times, albeit it does not conform to the SQL standard. See here for more information: http://www.postgresql.org/docs/9.2/static/functions-matching.html


Something to watch out for here is malicious user input. If you run a query like email ILIKE 'user-input-email-here', make sure to escape the user input. Otherwise people can enter characters like % that match anything.
@MattDeLeon Hi. Well said. But I just want to ask you, if I use ILIKE and prepared statements will this protect me from sql injection?
"The key word ILIKE can be used instead of LIKE to make the match case-insensitive according to the active locale. This is not in the SQL standard but is a PostgreSQL extension." Works like a charm in 9.3
ILIKE is slower than lower(column_name) like %expression%.
@PatrykImosa: Can you please elaborate or show an example of ILIKE being slower?
J
James Brown

You could also use POSIX regular expressions, like

SELECT id FROM groups where name ~* 'administrator'

SELECT 'asd' ~* 'AsD' returns t


I had the same problem, I needed case insensitive searches on my PostgreSQL database. I thought about transforming the user input string into a regular expression. Now, using ~* instead of = or LIKE worked perfectly! I didn't need to create new indexes, columns or whatever. Sure, regex search is slower than straight byte comparison, but I don't think the impact on performance would be so much greater than having to handle two sets of data (one lower or uppercased just for searching, then having to retrieve the corresponding original data from the other set). Besides, this is cleaner!
Fine, but how to do with regexp_matches() for example ?
According to postgres docs: The operator ~~ is equivalent to LIKE, and ~~* corresponds to ILIKE. There are also !~~ and !~~* operators that represent NOT LIKE and NOT ILIKE, respectively. All of these operators are PostgreSQL-specific.
I faced a issue when brackets are included in the text, its not working. like: "code (LC)"
faced issues with special characters.
E
EstevaoLuis

Using ~* can improve greatly on performance, with functionality of INSTR.

SELECT id FROM groups WHERE name ~* 'adm'

return rows with name that contains OR equals to 'adm'.


Hey, Robin, welcome to SO. James Brown's answer already proposed this solution. Additionally, your proposed answer does not leverage regex in any way.
~* is not precisely case-insensitive match. It is regex pattern matching. In your example if db contains ADM then where name ~* 'Adm' or where name ~* 'Ad' would yield results. Use ILIKE instead
s
samzna

ILIKE work in this case:

SELECT id 
  FROM groups
 WHERE name ILIKE 'Administrator'

M
MUGABA

use ILIKE

select id from groups where name ILIKE 'adminstration';

If your coming the expressjs background and name is a variable use

select id from groups where name ILIKE $1;

J
James Hudnall

For a case-insensitive parameterized query, you can use the following syntax:

 "select * from article where upper(content) LIKE upper('%' || $1 || '%')"

D
DEV Tiago França
-- Install 'Case Ignore Test Extension'
create extension citext;

-- Make a request
select 'Thomas'::citext in ('thomas', 'tiago');

select name from users where name::citext in ('thomas', 'tiago');

A
Anand Tripathi
select id from groups where name in ('administrator', 'ADMINISTRATOR', 'Administrator')

Please add some explanation to your answer such that others can learn from it