Salesforce SOQL: Salesforce Object Query Language

Every application needs a way to ask its database a question: "Give me all customers in Mumbai with revenue above ₹1 crore." In Salesforce, that question is written in SOQL — Salesforce Object Query Language. SOQL is how Apex code retrieves records from the Salesforce database. Every developer and advanced administrator needs to understand it thoroughly.

What Is SOQL?

SOQL is a query language that looks similar to SQL (Structured Query Language) used in traditional databases. The main difference is that SOQL is designed specifically for Salesforce's object model — so instead of querying tables, you query Salesforce objects. SOQL can only retrieve data — it cannot insert, update, or delete records. For those operations, you use DML statements.

The Library Search Analogy

  QUESTION: "Find me all science books published after 2010
             that are currently available, sorted by title."

  SOQL EQUIVALENT:
  SELECT Title, Author, Year
  FROM Book__c
  WHERE Category = 'Science'
  AND Year > 2010
  AND IsAvailable__c = true
  ORDER BY Title ASC

Basic SOQL Syntax

Every SOQL query follows this structure:

SELECT field1, field2, field3
FROM ObjectAPIName
WHERE condition
ORDER BY fieldName ASC|DESC
LIMIT numberOfRecords

A Real SOQL Example

SELECT Id, Name, Industry, AnnualRevenue, Phone
FROM Account
WHERE Industry = 'Technology'
AND AnnualRevenue > 10000000
ORDER BY AnnualRevenue DESC
LIMIT 10

This query returns the top 10 Technology accounts with annual revenue above ₹1 crore, sorted from highest to lowest revenue. Each clause plays a specific role:

  • SELECT — lists which fields to return
  • FROM — names the object to query
  • WHERE — filters which records to include
  • ORDER BY — sorts the results
  • LIMIT — caps the number of results returned

Using SOQL in Apex

In Apex, you embed SOQL queries inside square brackets. The result is stored in a List or a single record variable.

// Return multiple records into a List
List<Account> techAccounts = [
    SELECT Id, Name, AnnualRevenue
    FROM Account
    WHERE Industry = 'Technology'
    AND AnnualRevenue > 10000000
    ORDER BY AnnualRevenue DESC
    LIMIT 10
];

// Loop through results
for (Account acc : techAccounts) {
    System.debug('Account: ' + acc.Name + ' | Revenue: ' + acc.AnnualRevenue);
}

// Return a single record
Account topAccount = [
    SELECT Id, Name, AnnualRevenue
    FROM Account
    ORDER BY AnnualRevenue DESC
    LIMIT 1
];
System.debug('Top Account: ' + topAccount.Name);

WHERE Clause Operators

OperatorMeaningExample
=EqualsIndustry = 'Healthcare'
!=Not equal toStatus != 'Closed'
>Greater thanAmount > 500000
<Less thanNumberOfEmployees < 50
>=Greater than or equal toCloseDate >= TODAY()
LIKEPattern match (% is wildcard)Name LIKE 'Tata%'
INMatches any value in a listIndustry IN ('IT', 'Finance')
NOT INDoes not match any value in a listStageName NOT IN ('Closed Won', 'Closed Lost')
INCLUDESMulti-select picklist contains valueSkills__c INCLUDES ('Java')

Date Functions in SOQL

SOQL provides built-in date literals that make filtering by relative dates very easy:

-- Opportunities closing this month
SELECT Id, Name, CloseDate FROM Opportunity
WHERE CloseDate = THIS_MONTH

-- Cases created in the last 7 days
SELECT Id, Subject FROM Case
WHERE CreatedDate = LAST_N_DAYS:7

-- Accounts modified this year
SELECT Id, Name FROM Account
WHERE LastModifiedDate = THIS_YEAR

Date literals available include: TODAY, YESTERDAY, THIS_WEEK, LAST_WEEK, THIS_MONTH, LAST_MONTH, THIS_QUARTER, THIS_YEAR, LAST_N_DAYS:n, NEXT_N_DAYS:n, and more.

Relationship Queries

Because Salesforce objects are related, SOQL lets you query across those relationships in two directions.

Child to Parent (Dot Notation)

Access a parent record's fields from a child query using the relationship name and a dot:

SELECT Id, Name, Account.Name, Account.Industry
FROM Contact
WHERE Account.Industry = 'Finance'

This retrieves Contact records and also shows the Account name and industry for each Contact's parent Account.

Parent to Child (Subquery)

Retrieve a parent record and include its related child records in the same query:

SELECT Id, Name,
       (SELECT Id, Subject, Status FROM Cases)
FROM Account
WHERE Name = 'Infosys'

This returns the Infosys Account and, nested inside it, all Cases related to that Account. In Apex, you access the child records through the relationship name: account.Cases.

Aggregate Functions

SOQL supports aggregate functions for summarizing data — similar to Excel formulas like SUM and COUNT:

-- Count all open Opportunities
SELECT COUNT() FROM Opportunity WHERE IsClosed = false

-- Total value of open Opportunities by Stage
SELECT StageName, SUM(Amount) totalAmount, COUNT(Id) dealCount
FROM Opportunity
WHERE IsClosed = false
GROUP BY StageName
ORDER BY totalAmount DESC

Available aggregate functions: COUNT(), COUNT(fieldName), SUM(), AVG(), MIN(), MAX(). When you use aggregate functions with GROUP BY, results return as AggregateResult objects in Apex.

SOQL Governor Limits

Salesforce enforces limits on SOQL to protect shared server resources:

  • 100 SOQL queries per synchronous transaction
  • 200 SOQL queries per asynchronous transaction (batch, future, queueable)
  • 50,000 records maximum returned by a single query

The most critical rule: never put a SOQL query inside a loop. If you loop through 200 records and run a SOQL inside the loop, Salesforce executes 200 queries — blowing past the 100-query limit and throwing an error.

// BAD - SOQL inside loop (will fail at scale)
for (Account acc : accounts) {
    List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :acc.Id];
}

// GOOD - One SOQL outside loop
List<Contact> allContacts = [SELECT Id, AccountId FROM Contact
                              WHERE AccountId IN :accountIds];

Key Points

  • SOQL retrieves records from the Salesforce database — it reads data only, not modifies it.
  • Every query uses SELECT (fields), FROM (object), WHERE (filter), ORDER BY (sort), and LIMIT (cap).
  • Relationship queries let you traverse parent-to-child and child-to-parent connections in one query.
  • Aggregate functions like COUNT(), SUM(), and AVG() summarize data using GROUP BY.
  • Never put SOQL queries inside loops — collect IDs first and use a single IN query outside the loop.

Leave a Comment

Your email address will not be published. Required fields are marked *