LIKE filters on part of a text field: names that contain a word, codes that start with a prefix, or text that sits between two known words. The part people get stuck on is the negative form. SOQL has no NOT LIKE operator, so you negate the whole condition instead:
List<Account> accounts = [
SELECT Id, Name FROM Account
WHERE (NOT Name LIKE '%test%')
];
Everything below was run against a live org. The errors quoted are the ones Salesforce returned.
NOT LIKE: the syntax that works
Put NOT before the field and wrap the condition in parentheses.
// Works
WHERE (NOT Name LIKE '%test%')
// Parse error: SOQL has no NOT LIKE operator
WHERE Name NOT LIKE '%test%'
The parentheses matter as soon as you combine conditions. WHERE (NOT Name LIKE '%test%') AND Type = 'Customer' is unambiguous. Without the parentheses you are relying on operator precedence, and the query is harder to read.
To exclude several patterns, negate each one or negate a list bind (covered below):
WHERE (NOT Name LIKE '%test%') AND (NOT Name LIKE '%demo%')
NOT LIKE keeps blank values
A negated LIKE returns rows where the field is null. In the test org, 6 of 8 accounts had no website, and (NOT Website LIKE '%zzqq%') returned all 8. SQL would have dropped the blanks. If you only want rows that have a value, add AND Website != null. SOQL does not accept IS NOT NULL.
The two wildcards
| Pattern | Matches |
|---|---|
'Acme%' |
starts with Acme |
'%Acme' |
ends with Acme |
'%Acme%' |
contains Acme anywhere |
'Acme%Ltd' |
starts with Acme and ends with Ltd |
'J_n' |
Jan, Jen, Jon (exactly one character in the middle) |
'Acme' |
exactly Acme, ignoring case |
LIKE ignores case. '%a%' and '%A%' returned the same 7 accounts in the test org. There is no case-sensitive option, so filter in Apex when case matters.
Matching text between two words
Put % between the words, and on both ends if they can sit anywhere in the field:
List<Account> accounts = [
SELECT Id, Name, Industry FROM Account
WHERE Industry LIKE '%Technology%Services%'
];
That matches "Technology Services", "Technology and Services" and "Technology, Consulting Services". It does not match "Services in Technology", because the order of the words matters.
Use _ when exactly one character must sit between them. '%Street_Avenue%' matches "Street Avenue" but not "Street Avenue" with two spaces.
Binding Apex variables
A bind variable is used as the full pattern, so add the wildcards in Apex first:
String keyword = '%' + searchTerm + '%';
List<Account> accounts = [
SELECT Id, Name FROM Account WHERE Name LIKE :keyword
];
// Negated
List<Account> others = [
SELECT Id, Name FROM Account WHERE (NOT Name LIKE :keyword)
];
Binding :searchTerm without the % gives you an exact match, which is the usual reason a search box "finds nothing".
Binding a list of patterns
You can bind a List<String>, and SOQL returns records that match any pattern in it:
List<String> patterns = new List<String>{ '%Acme%', 'Global%', '%Ltd' };
List<Account> accounts = [
SELECT Id, Name FROM Account WHERE Name LIKE :patterns
];
This works the same as an OR of three LIKE conditions and keeps the query readable when the list comes from configuration.
Escaping % and _
A % or _ typed by a user acts as a wildcard. To match it literally, escape it with a backslash in the SOQL text:
SELECT Id FROM Product2 WHERE Name LIKE '50\% off'
When you build that query as an Apex string, the backslash needs escaping too, so it reaches SOQL intact:
String soql = 'SELECT Id FROM Product2 WHERE Name LIKE \'50\\% off\'';
List<Product2> products = Database.query(soql);
For dynamic SOQL built from user input, also run the input through String.escapeSingleQuotes() so a stray quote cannot change the query.
Which field types accept LIKE
| Field type | LIKE works? | What happens instead |
|---|---|---|
| Text, Text Area (255) | Yes | |
| Email, Phone, URL | Yes | |
| Picklist (single-select) | Yes | Industry LIKE 'Tech%' works |
| ID | No | invalid operator on id field |
| Number, Currency, Date | No | like operator only valid on string field |
| Multi-select picklist | No | invalid operator on multipicklist field. Use INCLUDES |
| Long Text Area, Rich Text | No | the field can not be filtered in query call. Use SOSL |
For a multi-select picklist, see SOQL CONTAINS vs LIKE vs INCLUDES.
Performance
An index can only help when the pattern is anchored at the start. 'Acme%' can use an index on Name. '%Acme%' cannot, so on an object with hundreds of thousands of rows the optimizer has to scan, and in a trigger that can end in a non-selective query error.
- Anchor the pattern at the start when the business rule allows it.
- Add a selective filter, such as a date range or an owner, alongside the
LIKE. - For free-text search across fields or objects, use SOSL
FIND, which runs on Salesforce's search index.
Common mistakes
- Writing
Name NOT LIKE. Use(NOT Name LIKE ...). - Binding a variable without wildcards and getting an exact match.
- Expecting
NOT LIKEto drop blank values. It keeps them. AddAND field != null. - Using
LIKEon an ID, a number or a multi-select picklist. - Starting every pattern with
%on a large object.
Leave a Comment