Skip to content

Compare two queries

Configure a Check that compares the result of one SOQL query with the result of a second SOQL query. Use it for two counts, two single values, or two lists.

Reference

  • This page defines the required SOQL, compatible result settings and operators, access behavior, limits, and outcomes.
  • For every field’s size, default, help text, and examples, use the Check field reference.

This evaluation type requires working knowledge of SOQL. Both queries are stored on the same Check record in Setup: Source Query is the left side and Comparison Query is the right side. If you cannot safely write and test both queries, use a Formula Check or ask a Salesforce developer.

Setup fieldAPI nameRequirement
Evaluation TypeEvaluationType__cCompare two queries: COMPARE_TWO_QUERIES
Source QuerySourceQuery__cRequired left-side SOQL template
Source Query FieldSourceQueryField__cSelected field or aggregate alias; blank for bare COUNT()
Comparison QueryComparisonQuery__cRequired right-side SOQL template
Comparison Query FieldComparisonQueryField__cSelected field or aggregate alias; blank for bare COUNT()
How To Read Query ResultsQueryResultHandling__cOne row or aggregate or Compare as lists
Comparison OperatorComparisonOperator__cOperator compatible with the selected mode

Expected Value Comes From is not used. The Comparison Query always supplies the Expected value.

Choose One row or aggregate (ONE_RESULT) to compare Number, Text, Date, Date/Time, or Checkbox values. Common examples are two bare COUNT() queries or two aggregate queries with aliases.

  • Leave both query-field settings blank for bare COUNT().
  • For an aliased aggregate, enter each alias in its corresponding Query Field.
  • For a selected field, each query must produce the single value expected by the comparison.
  • Use equality, ordering, contains, or empty-value operators supported by Comparison Operator.

For example, compare the total number of Opportunity Contact Roles with the number marked Primary:

SELECT COUNT()
FROM OpportunityContactRole
WHERE OpportunityId = {!record.Id}
SELECT COUNT()
FROM OpportunityContactRole
WHERE OpportunityId = {!record.Id} AND IsPrimary = TRUE

Choose Compare as lists: COMPARE_AS_LISTS and one of these operators:

Setup labelAPI valuePass condition
Lists overlapLISTS_OVERLAPAt least one normalized value occurs in both lists
Lists contain allLISTS_CONTAIN_ALLThe Comparison/Expected list contains every value in the Source/Found list; it may contain additional values
Lists match exactlyLISTS_MATCH_EXACTLYBoth lists contain the same values the same number of times

List matching ignores letter case. For example, Chicago and CHICAGO match. Single-value Contains remains case-sensitive. Select the list column with each Query Field and configure the result to use when either query finds no records.

Setup fieldAPI nameBehavior
If Query Finds No RecordsNoRowsResult__cDetermines the outcome when a required list/query side has no records
If Field Value Is EmptyEmptyValueHandling__cIgnores, preserves as blank, or forces no match for empty selected values
Max Query Rows (1-2000)MaxQueryRows__cApplies to returned rows; defaults to 200, maximum 2000

Both queries execute in the same evaluation transaction. Keep their selected fields and row counts as small as the comparison requires.

Each side is capped independently. Record Health Check probes one row beyond Max Query Rows for the Source Query and again for the Comparison Query; either side exceeding the cap returns UNABLE_TO_EVALUATE / ROW_LIMIT_EXCEEDED before comparison. The detail names the configured cap, not the true row count.

A bare COUNT() query always returns one aggregate row, even when the count is zero. If Query Finds No Records therefore applies to a query that returns zero rows, not to a COUNT() value of zero.

  • Both templates support current-record merge tokens such as {!record.Id} and parent paths. Add a quoted fallback attribute when an optional lookup can be blank (for example {!record.ParentId fallback="001000000000000AAA"}).
  • Use API names in SOQL and aliases in the matching Query Field setting.
  • Queries run using the current user’s effective record, object, and field access.
  • Access, invalid-query, alias, value-conversion, and incompatible result problems return UNABLE_TO_EVALUATE when Record Health Check can safely return a result.
  • Unexpected Apex failures return ERROR; Salesforce governor limits can still stop the current Apex transaction.

Test unequal/equal values, each ordering boundary, one empty side, both empty sides, blank selected values, duplicate list values, case differences, the configured row limit, and access denied to each query source. Also test every applicability and prerequisite path.

Use stable status and reasonCode values for automation. Found represents the resolved Source Query value; Expected represents the resolved Comparison Query value.

The Apex response does not contain a separate Compare-two-queries version number. Its global Apex types are the compile-time contract supplied by the installed package. Flow responses currently report contract 2.0, and Platform Events report their separate contract 1.0. A future field can be added without changing existing fields; removing or renaming a field, Status, operator, or Reason Code requires a new contract version. No Compare-two-queries field is currently deprecated.