59

In SQLite it is possible to change the case sensitive behaviour of 'LIKE' by using the commands:

PRAGMA case_sensitive_like=ON;
PRAGMA case_sensitive_like=OFF;

However in my situation I would like to execute a query, part of which is case sensitive and part of which isn't. For example:

SELECT * FROM mytable
WHERE caseSensitiveField like 'test%'
AND caseInsensitiveField like 'g2%'

Is this possible?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Richard Williams
  • 2,044
  • 1
  • 24
  • 28

6 Answers6

50

You can use the UPPER keyword on your case insensitive field then upper-case your like statement. e.g.

SELECT * FROM mytable 
WHERE caseSensitiveField like 'test%' 
AND UPPER(caseInsensitiveField) like 'G2%'
Matt
  • 74,352
  • 26
  • 153
  • 180
rbedger
  • 1,177
  • 9
  • 20
  • 1
    @AlexanderMalakhov Works for Italian and German characters as well. Just make sure that the db and the data you imported in it are all in UTF-8 encoding, and it works. – Phantômaxx Jul 15 '14 at 08:22
  • 23
    @rbedger Note, you `don't need the Upper function`, since **Like** is case-insensitive by default. – Phantômaxx Jul 15 '14 at 08:24
  • 5
    @FrankN.Stein it's doable, but not out-of-the-box. From [official FAQ](http://sqlite.org/faq.html#q18): `The default configuration of SQLite only supports case-insensitive comparisons of ASCII characters.` – Alexander Malakhov Jul 15 '14 at 10:10
  • I did it so: Since I planned to use UTF-8 characters, I saved my tables as UTF-8 CSV files. Then generated my tables from the CSV files in SQLiteManager (FireFox plugin). Then changed something in the DB configuration (don't remember what and if it's really needed). Then added my indexes to the WHERE and the JOIN fields. And that was all. – Phantômaxx Jul 15 '14 at 10:19
  • 3
    By editing out the "UPPER()", you end up with the same code as what the OP posted in the question. If you want to change your answer completely do so, or if you want to delete your answer then say so; but the edit you made makes no sense. – Matt May 05 '16 at 18:57
  • @Rotwang How did you manage to do it? `select upper('ä')` gives `'ä';` in utf8 db for me. Official FAQ says sqlite doesn't associate upper and lower letters at all (except for ascii). – Antony Hatchkins Feb 14 '17 at 15:09
  • @AntonyHatchkins In my app, when I search for `'%ü%'`, I get (among the other results) `Überprüfen` (which was my error when I compiled the CSV files - it has to be lowercase) and `überlappen`. Is this what you are looking for? – Phantômaxx Feb 14 '17 at 15:31
  • @Rotwang in your example I hoped `like 'über%'` to match both words. – Antony Hatchkins Feb 15 '17 at 03:46
  • @AntonyHatchkins I just noticed it doesn NOT! OK, now I'm in troubles. Thank you for letting me notice a couple of mistakes in my app. – Phantômaxx Feb 15 '17 at 08:24
  • @Rotwang I see several workarounds: (a) they mention in the faq they have a callback for that, but there's no example how to do it and it might be difficult to provide the callback and/or it migit work too slow, (b) store lowercase version in separate column db and (c) switch to mysql or postgres. So far I'm happy with the latter one :) – Antony Hatchkins Feb 15 '17 at 09:57
5

Use plain comparisons, which are case sensitive by default (unless you have declared the column COLLATE NOCASE):

SELECT *
FROM mytable 
WHERE caseSensitiveField >= 'test'
  AND caseSensitiveField <  'tesu'
  AND caseInsensitiveField LIKE 'g2%'

This works only if the original LIKE is searching for a prefix, but allows using an index.

CL.
  • 173,858
  • 17
  • 217
  • 259
5

In SQLite you can use GLOB instead of LIKE for pattern search. For example:

SELECT * FROM mytable
WHERE caseSensitiveField GLOB 'test*'
AND caseInsensitiveField LIKE 'g2%'

With this approach you don't have to worry about PRAGMA.

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
Yoda066
  • 304
  • 6
  • 11
  • 2
    LIKE `'g2%'` will only work case-insensitive by default for ascii characters only within the pattern. The part matched by `%` does not matter as it stands for anything . However `'g2'` must be non-unicode chars for case-insenstive match. `'üb%'` will match `über` but not `Über` See https://www.sqlite.org/faq.html#q18 – dre-hh Feb 22 '21 at 11:18
3

I know this is an old question, but if you are coding in Java and have this problem this might be helpful. You can register a function that handles the like checking. I got the tip form this post: https://stackoverflow.com/a/29831950/1271573

The solution i dependent on sqlite jdbc: https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc

In my case I only needed to see if a certain string existed as part of another string (like '%mystring%'), so I created a Contains function, but it should be possible to extend this to do a more sql-like check using regex or something.

To use the function in SQL to see if MyCol contains "searchstring" you would do:

select * from mytable where Contains(MyCol, 'searchstring')

Here is my Contains function:

public class Contains extends Function {

    @Override
    protected void xFunc() throws SQLException {
        if (args() != 2) {
            throw new SQLException("Contains(t1,t2): Invalid argument count. Requires 2, but found " + args());
        }
        String testValue = value_text(0).toLowerCase();
        String isLike = value_text(1).toLowerCase();

        if (testValue.contains(isLike)) {
            result(1);
        } else {
            result(0);
        }
    }
}

To use this function you must first register it. When you are done with using it you can optionally destroy it. Here is how:

public static void registerContainsFunc(Connection con) throws SQLException   {
    Function.create(con, Contains.class.getSimpleName(), new Contains());
}
public static void destroyContainsFunc(Connection con) throws SQLException {
    Function.destroy(con, Contains.class.getSimpleName());
}
Community
  • 1
  • 1
Jarle Jacobsen
  • 111
  • 1
  • 3
  • Found a bug in my code. If the column you are using the Contains function on has null values allowed, you should check the value_text(n) for null before applying th toLowerCase function. – Jarle Jacobsen May 14 '17 at 12:00
0

I used a regular expression to do what I needed. I wanted to identify all the occurrences of the word "In" that was not all lower case.

select [COL] from [TABLE] where [COL] REGEXP '\bIn\b';

Example:

with x as (select 'in' Diff_Ins union select 'In' Diff_Ins)
select Diff_Ins from x where Diff_Ins REGEXP '\bIn\b';
David Buck
  • 3,752
  • 35
  • 31
  • 35
ByBarn
  • 1
  • 2
    A heads up to other readers, by default there is no REGEXP. "The REGEXP operator is a special syntax for the regexp() user function. No regexp() user function is defined by default and so use of the REGEXP operator will normally result in an error message." https://www.sqlite.org/lang_expr.html#regexp – Captain Man Sep 29 '20 at 19:05
0

As others mention, SQLite also offers the GLOB function which is case-sensitive.

Assume g2* is text entered by the user at the application-level. To simplify application-side grammar and make GLOB case-insensitive, the text needs to be normalised to a common case:

SELECT * FROM mytable WHERE LOWER(caseInsensitiveField) GLOB LOWER('g2*');

If UNICODE is required, carefully test LOWER and UPPER to confirm they operate as expected. GLOB is an extension function specific to SQLite. Building a general grammar engine supporting multiple database vendors is non-trivial.

AlainD
  • 5,413
  • 6
  • 45
  • 99