Advanced Technical Guide · Part 1 of 2

Advanced Set Analysis

Operators, modifiers, dollar-sign expansion, and the P() and E() functions: the foundation separating intermediate developers from senior ones.

Set Analysis is not filtering. It is set algebra.
6Set operators
3Modifier types
P() E()Advanced functions
$( )Dynamic expansion
scroll to explore

1. Complete Anatomy of a Set Analysis Expression

Before advancing to complex patterns, you need to master the exact anatomy. Every part of a Set Analysis expression has a specific role - and confusing them is the source of 90% of bugs.

Full structure

Sum( { set_identifier  < set_modifier > }  expression )
      ^                ^               ^
      |                |               |
  Set identifier   Set modifier   Aggregation
                                   expression
    

Set Identifiers

1
{ 1 } - Full set (all records)Completely ignores user selections. Calculates across 100% of the data regardless of what has been filtered.
$
{ $ } - Current set (active selection)Equivalent to the expression without Set Analysis. Represents exactly what the user has selected. The starting point for modifiers.
_
{ $_1 } - Previous selectionThe set representing the selection immediately before the current one. Useful for interactive "before and after" comparisons.
BM
{ BM01 } - Bookmark as setA saved bookmark can be used as a set identifier. Lets you express "sales in the state saved as BM01".
// Practical examples of identifiers
// Total sales - ignores any Region, Product, Year selection
Sum({1} Amount)

// Sales in current selection - identical to Sum(Amount) without Set Analysis
Sum({$} Amount)

// Sales under the previous selection
Sum({$_1} Amount)

// Sales under bookmark "BM01" state (e.g., Top 10 Customers)
Sum({BM01} Amount)

Critical distinction: {1} ignores ALL selections, including selections on the expression's own field. {$} respects the current selection. Picking the wrong identifier is the most silent and dangerous mistake in Set Analysis.

2. Set Operators

Set operators allow you to combine, subtract, intersect, and modify data sets with precision. They are the foundation of set algebra in Qlik - and what makes Set Analysis genuinely powerful.

Available operators
+Union - includes all elements from both sets
-Difference - elements in the first set that are not in the second
*Intersection - only elements present in both sets
/Symmetric difference - elements in one OR the other, but not both
+
Union Operator

Combines two sets: the result contains all elements from both. Equivalent to logical OR when applied to different subsets of the same field.


// Sales of Electronics OR Furniture (regardless of current selection)
Sum({<Category={'Electronics'}> + <Category={'Furniture'}>} Amount)

// More concise equivalent for the same field:
Sum({<Category={'Electronics', 'Furniture'}>} Amount)

// More powerful union: sets from different fields
// Current selection + November records from any year
Sum({$ + <Month={'November'}>} Amount)

// Real-world case: customers in the current selection OR VIP customers
Count({$ + <CustomerSegment={'VIP'}>} DISTINCT CustomerID)
-
Difference Operator

Returns the first set minus elements also in the second. Essential for exclusion analysis: "everything except X".


// All records EXCEPT returns
Sum({1 - <Status={'Return'}>} Amount)

// Current selection EXCEPT 'Product X'
Sum({$ - <Product={'Product X'}>} Amount)

// Real-world case: net revenue = gross minus cancellations and returns
Sum({1 - <TransactionType={'Cancellation', 'Return'}>} GrossAmount)

// All customers who did NOT buy last month
// (used for churn analysis)
Count({
  <CustomerID=P({1}<Month={$(=Month(Today()))}> CustomerID)>
  -
  <CustomerID=P({1}<Month={$(=Month(AddMonths(Today(),-1)))}> CustomerID)>
} DISTINCT CustomerID)
*
Intersection Operator

Returns only elements present in both sets simultaneously. Equivalent to logical AND between distinct sets.


// Customers who bought Electronics AND are in the current selection
Count({
  <CustomerID=P({1}<Category={'Electronics'}> CustomerID)>
  *
  $
} DISTINCT CustomerID)

// Real-world case: average ticket for customers who purchased
// BOTH in Q1 AND Q4 (seasonally recurring customers)
Avg({
  <CustomerID=P({1}<Quarter={'Q1'}> CustomerID)>
  *
  <CustomerID=P({1}<Quarter={'Q4'}> CustomerID)>
} OrderValue)

// The * operator is the right tool for cohort analysis:
// "what is the LTV of customers who met both conditions"
/
Symmetric Difference - The Forgotten Operator

Returns elements that are in one set OR the other, but not both. Useful for comparison analyses where you want to highlight what is exclusive to each set.


// Products sold in 2023 OR in 2024, but not in both
// (products that entered or left the portfolio)
Count({
  <ProductID=P({1}<Year={2023}> ProductID)>
  /
  <ProductID=P({1}<Year={2024}> ProductID)>
} DISTINCT ProductID)

// Interpretation:
// Set A: products with sales in 2023
// Set B: products with sales in 2024
// A / B = new products (only in 2024) + discontinued products (only in 2023)

3. Advanced Modifiers

Modifiers alter the active selection for a specific field within the set. They are expressed between < > and determine exactly which values of each dimension participate in the calculation.

Types of Modifiers

Direct assignment - literal values

// Defines exactly which values
// the field must have in the set

Sum({<Year={2024}>} Amount)

Sum({<Region={'South', 'West'}>} Amount)

Sum({<Status={'Active'}>,
     Year={2024}>} Amount)

// Overrides the current field selection
// and uses the specified values
Exclusion modifier - removes field

// Removes the selection from a specific field
// while keeping other field selections intact

// Ignore Year selection, keep the rest
Sum({<Year=>} Amount)

// Ignore both Month AND Quarter, keep others
Sum({<Month=, Quarter=>} Amount)

// Practical for "full-year total" within
// a context filtered by week

Modifier with Expression-Derived Value

The most powerful modifier type: the set of values is determined by an expression evaluated at render time. Combines Set Analysis with dynamic logic.


// Current year derived from expression - dynamic, never needs updating
Sum({<Year={$(=Year(Today()))}>} Amount)

// Previous month calculated dynamically
Sum({<Month={$(=Month(AddMonths(Today(), -1)))},
     Year={$(=Year(AddMonths(Today(), -1)))}>} Amount)

// Top N values of the Product field (defined by variable vN)
// $(vN) expands to the variable value at calculation time
Sum({<ProductID=Top(Rank(Sum(Amount)), 1, $(vN))>} Amount)

// Dynamic period: from year start to today
Sum({<Date={">=$(=YearStart(Today()))<=$(=Today())"}>} Amount)

The difference between Year={2024} and Year={$(=Year(Today()))} seems small but is critical in production. The second always calculates the correct year, without needing to update the expression at each year boundary.

Modifiers with Partial Matching - Wildcards


// Products whose name starts with "Pro"
Sum({<Product={"Pro*"}>} Amount)

// Customers whose email is from the @company.com domain
Count({<Email={"*@company.com"}>} DISTINCT CustomerID)

// Records with code containing "US" in any position
Sum({<CountryCode={"*US*"}>} Amount)

// Combining wildcard with expression:
// Products that start with the user-selected letter
// (vLetter is a variable set by an input box)
Sum({<Product={"$(vLetter)*"}>} Amount)

4. Dollar-Sign Expansion in Set Analysis

Dollar-sign expansion $( ) is the mechanism that makes Set Analysis truly dynamic. It resolves the content of the expansion before Set Analysis is evaluated - allowing variables, expressions, and even other Set Analysis expressions to define the set parameters.

1
$(variable) - variable expansionSubstitutes the token with the current value of the variable. Happens before Set Analysis evaluation.
2
$(=expression) - expression expansionEvaluates the expression and uses the result as part of the Set Analysis. Enables dynamic calculations in set parameters.
3
$(#variable) - numeric expansionReturns the numeric value without regional formatting. Critical when thousand/decimal separators vary across locales.

Dollar-Sign Expansion Patterns

// Pattern 1: variable as dynamic filter
// Script: SET vCurrentYear = Year(Today());
// In expression:
Sum({<Year={$(vCurrentYear)}>} Amount)
// Expands to: Sum({<Year={2025}>} Amount)
// Auto-updates on every reload - no expression changes needed

// Pattern 2: dynamic expression as parameter
// Period: from first day of month to today
Sum({<Date={">=$(=MonthStart(Today()))<=$(=Today())"}>} Amount)

// Pattern 3: variable containing a full Set Analysis expression
// Script: SET vVIPFilter = '{<CustomerSegment={''VIP''}>}';
// In expression:
Sum($(vVIPFilter) Amount)
// Expands to: Sum({<CustomerSegment={'VIP'}>} Amount)
// Reuse the filter across multiple charts without repetition
// Pattern 4: numeric expansion to avoid locale issues
// Variable: LET vTarget = 150000.50;
// Problem: in locales with comma as decimal separator,
// $(vTarget) may expand to "150.000,50" - invalid in Set Analysis

// Wrong (may break in different locales):
Sum({<Amount={>$(vTarget)}>} Orders)

// Correct - $(#vTarget) always returns the number without formatting:
Sum({<Amount={>$(#vTarget)}>} Orders)
// Always expands to: Sum({<Amount={>150000.5}>} Orders)

Rule of thumb: whenever a modifier value comes from a numeric variable, use $(#variable) instead of $(variable). Prevents silent bugs in environments with regional settings different from the development environment.

5. P() and E() - Element Functions

The P() (Possible Values) and E() (Excluded Values) functions are the most sophisticated tools in Set Analysis. They allow you to use the set of possible or excluded values from one field as the parameter for another field - creating high-precision cross-field filters.

P() - Possible Values

// P(field) returns the set of POSSIBLE
// (non-excluded) values of a field
// in the current or a defined set

// Customers possible in the current selection
P(CustomerID)

// Products possible in set {1} filtered by Category
P({1}<Category={'Electronics'}> ProductID)

// Use: filter ANOTHER field by the possible values
Sum({<CustomerID=P({1}<Region={'West'}> CustomerID)>} Amount)
// "Sales of customers who are from the West region"
E() - Excluded Values

// E(field) returns the set of EXCLUDED
// (grayed out in Qlik) values of a field
// in the current selection

// Customers excluded by the current selection
E(CustomerID)

// Use: calculate over what was excluded
// (impact analysis - "what was left out")
Sum({<CustomerID=E(CustomerID)>} Amount)
// "Sales of customers who were excluded
//  by the current selection" - impact analysis

P() in Practice - Cohort Filtering

The most powerful use of P() is cross-field filtering. Instead of listing explicit values, you instruct Qlik to "use the values of field X that satisfy condition Y as the filter for field Z".


// Case 1: sales generated by customers who purchased a specific product
// Without P(): impossible without a JOIN in script
// With P(): elegant and direct

Sum({
  <CustomerID = P({1}<ProductID={'PROD-LAPTOP-001'}> CustomerID)>
} Amount)
// Step by step:
// 1. P({1}<ProductID={'PROD-LAPTOP-001'}> CustomerID)
//    returns all CustomerIDs who bought PROD-LAPTOP-001
// 2. <CustomerID = [that set of IDs]>
//    filters the data to those customers
// 3. Sum(Amount) over that filtered data

// Case 2: cross-sell analysis
// How much do Electronics buyers also spend in other categories?
Sum({
  <CustomerID = P({1}<Category={'Electronics'}> CustomerID),
   Category = {'Appliances'}>
} Amount)
// "Sales in the Appliances category
//  made by customers who also bought Electronics"

// Case 3: hierarchy - sales of managers whose reports hit their target
Sum({
  <ManagerID = P({1}<QuotaPercent={>100}> ManagerID)>
} BonusAmount)

Combining P() with Set Operators


// Cohort intersection: customers who purchased in BOTH periods
// (high-retention customers - bought in Q1 AND Q3)
Count({
  <CustomerID =
    P({1}<Quarter={'Q1'}> CustomerID)
    *
    P({1}<Quarter={'Q3'}> CustomerID)
  >
} DISTINCT CustomerID)

// Cohort difference: new customers in the current period
// (bought now, but did NOT buy in the previous period)
Sum({
  <CustomerID =
    P({1}<Year={$(=Year(Today()))}> CustomerID)
    -
    P({1}<Year={$(=Year(Today())-1)}> CustomerID)
  >
} Amount)
// "Revenue generated by first-time buyers this year"

P() and E() are evaluated in the context of the set that wraps them. P({1} Field) and P({$} Field) produce completely different results: the first ignores the selection, the second respects it. Always be explicit about which context you want.

Review Checklist - Set Analysis Part 1

SetAnalysis QlikSense BI QlikDeveloper DataAnalytics BusinessIntelligence QlikView DashboardDesign DataModeling