The previous lesson taught the SELECT-FROM-WHERE shape with a single equality filter. Real reporting needs more: ranges, multiple values, "contains this word", and "field is blank". This lesson is the toolkit that turns one equality test into a real filter.
SOQL supports the same comparison operators you would expect from any language, applied to the value of a field on the left side:
List<Account> big = [SELECT Id, Name FROM Account WHERE AnnualRevenue > 50000000]; List<Account> notCold = [SELECT Id, Name FROM Account WHERE Rating != 'Cold'];
The full set: =, !=, <, <=, >, >=. <> is also accepted as a synonym for !=. Strings compare alphabetically, numbers compare numerically, and dates compare chronologically. Pick the one that matches the business question: a payroll report wants >, a membership tier usually wants =.
Most useful filters ask for more than one thing at once. SOQL joins two conditions with AND (both must be true) or OR (either must be true):
Integer customerHot = [SELECT COUNT() FROM Account
WHERE Type = 'Customer' AND Rating = 'Hot'];
AND narrows the result. OR widens it. Parentheses control which side of an AND/OR pair is evaluated first, and you should always parenthesize mixed expressions to keep the intent obvious to the next reader.
When a field has to match any one of a small set of values, IN is cleaner than a long chain of OR:
List<Account> usCanada = [SELECT Id, Name FROM Account
WHERE BillingCountry IN ('USA', 'Canada')];
IN takes a comma-separated list of literals, or a bound Apex Set<String> or List<String> with the colon syntax: WHERE BillingCountry IN :countries. The list form is the right tool when the values come from data, not hardcoded literals.
Sometimes you do not know the full value, only a piece of it. LIKE is SOQL pattern matching, and two wildcards do the work:
% matches zero or more characters_ matches exactly one characterList<Account> tech = [SELECT Id, Name FROM Account WHERE Name LIKE '%Tech%'];
The pattern '%Tech%' matches anything that contains the substring Tech — TechCo, FinTech Solutions, Biotech Labs. The pattern 'Tech%' only matches strings that start with Tech. Anchoring on both sides is the difference between "contains" and "starts with".
A field that has never been set holds null, and you test for it with IS NULL or IS NOT NULL. The usual = does not work:
Integer missingFax = [SELECT COUNT() FROM Account WHERE Fax = null]; // wrong Integer noFax = [SELECT COUNT() FROM Account WHERE Fax IS NULL]; // right
WHERE Fax = null looks correct and always returns zero rows, because the comparison is never true. IS NULL is the only way to ask "is this field blank".
The most common slip is mixing = and IS — WHERE Fax = null is a silent no-match, not a syntax error. The test passes locally because there are no Accounts with null Fax, then fails on a real org.
A second slip is forgetting parentheses around an OR inside an AND. WHERE A = 1 AND B = 2 OR C = 3 is parsed as (A=1 AND B=2) OR C=3, which is rarely what was intended. Always write the parentheses explicitly.
A third slip is treating LIKE as case-sensitive when it is not. SOQL LIKE is case-INSENSITIVE by default, so '%tech%' matches TechCo. Use LIKE ... ESCAPE '\\' only when you need literal wildcards in the pattern.
Almost every real-world SOQL query is a WHERE clause. Reports, integrations, batch cleanup jobs, and triggers all combine several of these operators to ask a precise question of the database. Picking the right operator is the difference between a query that runs in milliseconds and one that pulls the whole table just to throw most of it away.