Last Updated On : 28-Sep-2026


Salesforce Certified Platform Developer II (SP25) Practice Test

Prepare with our free Salesforce Certified Platform Developer II (SP25) sample questions and pass with confidence. Our Salesforce-Platform-Developer-II practice test is designed to help you succeed on exam day.

161 Questions
Salesforce 2026

Which select statement should be inserted to retrieve Tasks ranging from 12 to 24 months old, including archived tasks, and excluding deleted ones?

Java
Date initialDate = System.Today().addMonths(-24);
Date endDate = System.Today().addMonths(-12);

A. [SELECT ... FROM Task WHERE What.Type = 'Account' AND isArchived=true AND CreatedDate => :initialDate ...]

B. [SELECT ... FROM Task WHERE What.Type = 'Account' AND CreatedDate => :initialDate ... ALL ROWS]

C. [SELECT ... FROM Task WHERE What.Type = 'Account' AND isDeleted=false AND CreatedDate => :initialDate ... ALL ROWS]

D. [SELECT ... FROM Task WHERE What.Type = 'Account' AND isArchived=true AND CreatedDate => :initialDate ... ALL ROWS]

C.   [SELECT ... FROM Task WHERE What.Type = 'Account' AND isDeleted=false AND CreatedDate => :initialDate ... ALL ROWS]

Explanation

This question tests how SOQL handles archived and deleted activity records. Archived Tasks and deleted Tasks are both skipped by a standard query, and the ALL ROWS keyword makes SOQL return both kinds.
The isDeleted field then filters the deleted records back out, leaving active and archived Tasks in the requested date range.

✅ C. [SELECT ... FROM Task WHERE What.Type = 'Account' AND isDeleted=false AND CreatedDate >= :initialDate ... ALL ROWS]
ALL ROWS makes the query return archived Tasks, which a standard query skips, and it also returns deleted records. Adding isDeleted=false then filters out the deleted ones. The combination therefore returns both active and archived Tasks while excluding anything in the Recycle Bin. Together with the CreatedDate filter against the initial date, it covers the requested 12 to 24 month window correctly.

❌ A. [SELECT ... FROM Task WHERE What.Type = 'Account' AND isArchived=true AND CreatedDate >= :initialDate ...]
This option filters on isArchived=true but omits ALL ROWS. Without ALL ROWS, the query does not return archived activities at all, so the result would be empty or incomplete. It also restricts results to archived Tasks only, which excludes the active Tasks that are still within the 12 to 24 month range.

❌ B. [SELECT ... FROM Task WHERE What.Type = 'Account' AND CreatedDate >= :initialDate ... ALL ROWS]
This option uses ALL ROWS, so archived Tasks are returned, but it has no isDeleted=false filter. ALL ROWS also returns records in the Recycle Bin, so deleted Tasks would appear in the results. The requirement explicitly says deleted Tasks must be excluded, which makes this option incorrect even though it retrieves archived records.

❌ D. [SELECT ... FROM Task WHERE What.Type = 'Account' AND isArchived=true AND CreatedDate >= :initialDate ... ALL ROWS]
This option adds ALL ROWS but filters on isArchived=true, so only archived Tasks are returned. Active Tasks in the 12 to 24 month range are left out, which does not meet the requirement to include both. It also lacks isDeleted=false, so deleted archived Tasks could still appear in the results.

Reference
🔗 SELECT Syntax (ALL ROWS) - SOQL SELECT Syntax, Salesforce Developers → confirms ALL ROWS returns archived and deleted records that standard queries skip.
🔗 Task - Object Reference, Salesforce Developers → confirms Task includes the IsArchived and IsDeleted fields used for filtering.

The Salesforce admin at Cloud Kicks created a custom object called Region__c to store all postal zip codes in the United States and the Cloud Kicks sales region the zip code belongs to.

Object Name: Region__c
Fields: Zip_Code__c (Text), Region_Name__c (Text)

Cloud Kicks wants a trigger on the Lead to populate the Region based on the Lead's zip code. Which code segment is the most efficient way to fulfill this request?

A. Java
Set< String > zips = new Set< String >();
for(Lead l : Trigger.new) {
if(l.PostalCode != Null) {
zips.add(l.PostalCode);
}
}
for(Lead l : Trigger.new) {
List< Region__c > regions = [SELECT Zip_Code__c, Region_Name__c FROM Region__c
WHERE Zip_Code__c IN :zips];
for(Region__c r : regions) {
if(l.PostalCode == r.Zip_Code__c) {

B. Region__c = r.Region_Name__c;
}
}
}

C. Java
Set< String > zips = new Set< String >();
for(Lead l : Trigger.new) {
if(l.PostalCode != Null) {
zips.add(l.PostalCode);
}
}
List< Region__c > regions = [SELECT Zip_Code__c, Region_Name__c FROM Region__c
WHERE Zip_Code__c IN :zips];
for(Lead l : Trigger.new) {
for(Region__c r : regions) {
if(l.PostalCode == r.Zip_Code__c) {

D. Region__c = r.Region_Name__c;
}
}
}

E. Java
for(Lead l : Trigger.new) {
Region__c reg = [SELECT Region_Name__c FROM Region__c WHERE Zip_Code__c =
:l.PostalCode];

F. Region__c = reg.Region_Name__c;
}

G. Java
Set< String > zips = new Set< String >();
for(Lead l : Trigger.new) {
if(l.PostalCode != Null) {
zips.add(l.PostalCode);
}
}
List< Region__c > regions = [SELECT Zip_Code__c, Region_Name__c FROM Region__c
WHERE Zip_Code__c IN :zips];
Map< String, String > zipMap = new Map< String, String >();
for(Region__c r : regions) {
zipMap.put(r.Zip_Code__c, r.Region_Name__c);
}
for(Lead l : Trigger.new) {
if(l.PostalCode != Null) {

H. Region__c = zipMap.get(l.PostalCode);
}
}

G.   Java
Set< String > zips = new Set< String >();
for(Lead l : Trigger.new) {
if(l.PostalCode != Null) {
zips.add(l.PostalCode);
}
}
List< Region__c > regions = [SELECT Zip_Code__c, Region_Name__c FROM Region__c
WHERE Zip_Code__c IN :zips];
Map< String, String > zipMap = new Map< String, String >();
for(Region__c r : regions) {
zipMap.put(r.Zip_Code__c, r.Region_Name__c);
}
for(Lead l : Trigger.new) {
if(l.PostalCode != Null) {
H.   Region__c = zipMap.get(l.PostalCode);
}
}

Explanation

The question tests Apex trigger bulkification and efficient record matching.
A trigger can process multiple Leads in one transaction, so SOQL queries should not be placed inside loops.
The postal codes should first be collected into a Set and queried in a single SOQL statement.
The returned Region__c records should then be stored in a Map for efficient postal-code lookup.
This avoids repeated database queries and unnecessary nested comparisons.
Therefore, the most efficient code segment is G–H.

Correct Option

🟢 G–H. Use a Set, one SOQL query, and a Map to populate Region__c.
This approach is fully bulkified. It collects all unique Lead postal codes in a Set, retrieves the matching Region__c records with one SOQL query, and stores them in a Map keyed by postal code. Each Lead can then obtain its region directly using zipMap.get(l.PostalCode). This avoids SOQL inside loops and avoids unnecessary nested loops, making the solution efficient and appropriate for bulk trigger execution.

Incorrect Options

❌ A–B. Query Region__c inside the Lead loop.
This option executes the SOQL query inside the second Trigger.new loop. If many Leads are processed, multiple queries are executed and Salesforce governor limits can be exceeded. Although the postal codes are collected efficiently, placing the query inside the loop makes this approach unsuitable for bulk processing.

❌ C–D. Query once, then use nested loops to match records.
This option correctly performs only one SOQL query, but it compares every Lead with every retrieved Region record through nested loops. That creates unnecessary processing as the number of records grows. A Map provides direct postal-code lookup and is more efficient than repeatedly comparing records.

❌ E–F. Query Region__c separately for each Lead.
This option places a SOQL query directly inside the Lead loop. Bulk processing can therefore execute many queries in one transaction, potentially exceeding the SOQL governor limit. It also repeats queries when multiple Leads have the same postal code, making it inefficient.

Reference
⇒ Apex Developer Guide – Bulk Apex Triggers — Confirms that triggers should be designed to handle multiple records and avoid inefficient database operations.

⇒ Apex Best Practices — Confirms that SOQL queries should be moved outside loops to avoid governor-limit problems.

As part of point-to-point integration, a developer must call an external web service which, due to high demand, takes a long time to provide a response. As part of the request, the developer must collect key inputs from the end user before making the callout. Which two elements should the developer use to implement these business requirements?

A. Batch Apex

B. Lightning web component

C. Screen Flow

D. Apex method that returns a Continuation object

B.   Lightning web component
D.   Apex method that returns a Continuation object

Explanation:

The scenario requires collecting user inputs interactively and then making a long-running external web service callout as part of point-to-point integration. Continuations enable asynchronous long-running callouts (up to 120 seconds) without blocking the UI thread or hitting synchronous request limits, while a Lightning Web Component provides the interactive UI to gather the required inputs before invoking the callout.

✅ Correct Option:

✅ B. Lightning web component
An LWC can render input fields to collect key user data and then imperatively (or via wire) call an Apex method. It fully supports Continuations, allowing the UI to remain responsive while the long-running callout executes and the callback returns the response.

✅ D. Apex method that returns a Continuation object
Define an @AuraEnabled(continuation=true) method that creates a Continuation instance, adds the HttpRequest, sets the callback method, and returns the Continuation object. This pattern handles the long-running external call asynchronously and processes the response in the designated callback.

❌ Incorrect options:

❌ A. Batch Apex
Batch Apex is designed for asynchronous bulk data processing across large record sets. It cannot interactively collect end-user inputs in real time and is not suitable for a user-driven, point-to-point callout scenario that requires immediate UI feedback.

❌ C. Screen Flow
A Screen Flow can collect user inputs, but it does not natively support the Continuation pattern for long-running callouts in the same non-blocking UI manner. Callouts from Flow (or Apex actions invoked by Flow) remain subject to synchronous transaction limits and do not provide the Continuation-based asynchronous handling required here.

🔧 Reference:
→ Work with a Continuation in an Apex Class (Lightning Web Components Developer Guide – Salesforce Developers)
Confirms how to implement an Apex method that returns a Continuation object and invoke it from Lightning Web Components for long-running callouts.

Universal Containers uses a custom Lightning page to provide a mechanism to perform a step-by-step wizard search for Accounts. One of the steps in the wizard is to allow the user to input text into a text field, ERP_Number__c, that is then used in a query to find matching Accounts.

Java
erpNumber = erpNumber + '%';
List accounts = [SELECT Id, Name FROM Account WHERE ERP_Number__c LIKE :erpNumber];

A developer receives the exception 'SOQL query not selective enough'. Which step should be taken to resolve the issue?

A. Move the SOQL query to within an asynchronous process.

B. Mark the ERP_Number__c field as required.

C. Mark the ERP_Number__c field as an external ID.

D. Change the query to use a SOSL statement instead of SOQL.

C.   Mark the ERP_Number__c field as an external ID.

Explanation

This question tests SOQL selectivity for a custom field used in a large-data-volume search. The query filters Accounts by a prefix pattern using LIKE :erpNumber, where the appended % wildcard performs a starts-with search. To make this query eligible for index-based optimization, the filtered custom field should be indexed.

✅ Correct Option:

✅ C. Mark the ERP_Number__c field as an external ID.
Setting ERP_Number__c as an External ID automatically creates an index on the field. Because the query uses a trailing wildcard, such as ABC%, Salesforce can use the index to locate Account values beginning with the entered ERP number, provided the filter is sufficiently selective. This reduces the records scanned and resolves the nonselective-query issue for the wizard search.

❌ Incorrect Options:

❌ A. Move the SOQL query to within an asynchronous process.
Asynchronous Apex changes when the query runs, not whether it is selective. The same nonselective SOQL query can still scan too many Account records and fail. Query optimization requires an appropriate indexed filter and a sufficiently small result set, not future, queueable, batch, or scheduled execution.

❌ B. Mark the ERP_Number__c field as required.
Making the field required prevents users from saving Accounts without an ERP number, but it does not add a database index. The query optimizer still has no indexed access path for this custom field. Required-field validation improves data completeness, not SOQL performance or filter selectivity.

❌ D. Change the query to use a SOSL statement instead of SOQL.
SOSL is intended for text searches across multiple objects or fields. This requirement filters a known field, ERP_Number__c, on the Account object using a prefix value. Indexing the SOQL filter field is the targeted solution; changing query languages does not address the field’s missing index.

🔧 Reference:
→ CustomField confirms that a custom field configured as an External ID is indexed.

→ Comparison Operators confirms that the LIKE operator supports % as a wildcard for partial string matching.

Which two queries are selective SOQL queries and can be used for a large data set of 200,000 Account records?

A. SELECT Id FROM Account WHERE Id IN (List of Account Ids)

B. SELECT Id FROM Account WHERE Name IN (List of Names) AND Customer_Number__c = 'ValueA'

C. SELECT Id FROM Account WHERE Name != ''

D. SELECT Id FROM Account WHERE Name LIKE '%Partner'

A.   SELECT Id FROM Account WHERE Id IN (List of Account Ids)
B.   SELECT Id FROM Account WHERE Name IN (List of Names) AND Customer_Number__c = 'ValueA'

Explanation

This question tests SOQL query selectivity principles when querying Large Data Volume (LDV) objects. It evaluates which query conditions leverage standard or custom indexes effectively to filter down large record sets below governor limits.

✅ A. SELECT Id FROM Account WHERE Id IN (List of Account Ids)
The Primary Key field (Id) is always indexed by default in Salesforce. Filtering by a list of specific Record IDs via the IN operator allows the Salesforce query optimizer to use the standard index directly, making the query highly selective regardless of overall dataset size.

✅ B. SELECT Id FROM Account WHERE Name IN (List of Names) AND Customer_Number__c = 'ValueA'
The standard Name field and unique or external ID custom fields (like Customer_Number__c) possess standard indexes. Using exact matching or specific lists against indexed fields enables the query optimizer to utilize index scans efficiently to evaluate selectively.

❌ C. SELECT Id FROM Account WHERE Name != ''
Using negative query operators such as != (NOT EQUAL TO) disables index usage because the query optimizer cannot narrow down rows using an index for non-matching values. This forces a full table scan, making the query non-selective on large datasets.

❌ D. SELECT Id FROM Account WHERE Name LIKE '%Partner'
Using a leading wildcard in a LIKE operator expression (e.g., '%Partner') prevents the query optimizer from utilizing the field index. The database engine cannot perform index lookups with leading wildcards, resulting in an expensive full table scan.

Reference
🔧 Make SOQL Queries Selective - Salesforce Developer Documentation → confirms that indexed fields with positive operators are selective, whereas negative operators and leading wildcards disable index lookups.

Salesforce-Platform-Developer-II Exam Questions - Home Previous
Page 3 out of 33 Pages