DAX содержит гибкие возможности фильтрации, и важными функциями являются ALL и REMOVEFILTERS. При использовании ALL и REMOVEFILTERS в качестве модификатора CALCULATE они ведут себя одинаково, т.к. в этом случае REMOVEFILTERS является псевдонимом ALL, однако ALL в FILTER возвращает «новую таблицу» и очищает влияние всех фильтров, что важно учитывать с точки зрения производительности и результатов.

Интересующимся особенностями ALL и сравнением ALL и REMOVEFILTERS  — добро пожаловать под кат :)

Рассмотрим следующие вопросы с примерами на тестовых данных:

  • случаи, когда ALL и REMOVEFILTERS эквивалентны

  • пример ALL внутри FILTER  с очисткой всех фильтров, что приводит к «созданию новой таблицы», а не просто к «снятию фильтра»

  • детали отмены фильтрации по группировочным полям и фильтрам FILTER в SUMMARIZECOLUMNS для ALL и REMOVEFILTERS

Рассмотрим все примеры на одном и том же наборе данных: схема с одной таблицей фактов sales и двумя справочниками product и customer.

Данные справочника клиентов customer:

customer_id

customer_name

customer_gender

1

Mike Smith

M

2

John Doe

M

3

Mary Brown

F

Данные справочника продуктов product:

product_id

product_name

product_brand

product_color

1

Black Pen

The First

Black

2

Red Pen

The Best

Red

3

Blue Pen

The First

Blue

4

White Pen

The Second

White

5

Green Pen

The First

Green

6

Silver Pen

The Second

Silver

Данные таблицы фактов sales:

order_number

customer_id

product_id

quantity

amount

orderdate

0001

1

3

1

3.15

01-01-2025

0002

1

2

2

4.24

01-01-2025

0003

2

1

3

3.45

02-01-2025

0004

1

2

1

2.12

02-01-2025

0005

3

1

1

1.15

03-01-2025

0006

1

3

2

6.30

03-01-2025

0007

2

4

2

6.32

01-01-2025

0008

1

5

2

4.28

01-01-2025

0009

1

6

1

1.19

02-01-2025

0010

3

5

1

2.14

02-01-2025

0011

2

6

1

1.19

03-01-2025

0012

1

4

2

6.32

03-01-2025

Рассмотрим простейшую меру — сумму продаж:

Total Amount = SUM ( sales[amount] )

Каждый раз создавать новую меру не будем, будем лишь изменять выражение Total Sales в SUMMARIZECOLUMNS.

1. Исходный запрос с фильтрами по группировочным полям и FILTER в SUMMARIZECOLUMNS

Рассмотрим исходный запрос с тремя фильтрами: фильтр за счет группировки по цвету продукта product[product_color], фильтр за счет группировки по полу customer[customer_gender] и фильтр по полу customer[customer_gender]=M через FILTER в SUMMARIZECOLUMNS, причем product влияет на расчет Total Sales за счет группировочного поля product[product_color], а customer влияет на Total Sales за счет группировочного поля customer[customer_gender] и фильтра FILTER по полу M. Для упрощения фильтрацию по цвету продукта рассматриваем через FILTER, т.е. без TREATAS и других возможностей DAX.

EVALUATE
SUMMARIZECOLUMNS (
    product[product_color],
    customer[customer_gender],
    FILTER ( customer, customer[customer_gender] = "M" ),
    "Total Sales", CALCULATE ( SUM ( sales[amount] ) )
)

Видим результаты выполнения запроса, это поможет для интерпретации следующих кейсов.

2. ALL и REMOVEFILTERS как модификаторы CALCULATE

Рассмотрим ALL и REMOVEFILTERS по таблице в роли модификаторов CALCULATE. Это известный случай и понятно, что в нем REMOVEFILTERS является псевдонимом ALL, но это позволяет продемонстрировать работу ALL и REMOVEFILTERS наглядно.

Рассмотрим случаи удаления фильтра через ALL и REMOVEFILTERS для таблиц customer и product, результаты запросов совпадают для ALL и REMOVEFILTERS.

Удаление фильтра по customer с использованием ALL:

EVALUATE
SUMMARIZECOLUMNS (
    product[product_color],
    customer[customer_gender],
    FILTER ( customer, customer[customer_gender] = "M" ),
    "Total Sales", CALCULATE ( SUM ( sales[amount] ), ALL ( customer ) )
)

Удаление фильтра по customer с использованием REMOVEFILTERS дает те же результаты:

EVALUATE
SUMMARIZECOLUMNS (
    product[product_color],
    customer[customer_gender],
    FILTER ( customer, customer[customer_gender] = "M" ),
    "Total Sales", CALCULATE ( SUM ( sales[amount] ), REMOVEFILTERS ( customer ) )
)

Удаление фильтра по product через ALL:

EVALUATE
SUMMARIZECOLUMNS (
    product[product_color],
    customer[customer_gender],
    FILTER ( customer, customer[customer_gender] = "M" ),
    "Total Sales", CALCULATE ( SUM ( sales[amount] ), ALL ( product ) )
)

Удаление фильтра по product через REMOVEFILTERS дает те же результаты:

EVALUATE
SUMMARIZECOLUMNS (
    product[product_color],
    customer[customer_gender],
    FILTER ( customer, customer[customer_gender] = "M" ),
    "Total Sales", CALCULATE ( SUM ( sales[amount] ), REMOVEFILTERS ( product ) )
)

Таким образом, видно, что при использовании ALL и REMOVEFILTERS по таблице в роли модификаторов CALCULATE они возвращают одинаковые результаты.

3. FILTER со вложенным ALL возвращает таблицу и отменяет все существующие фильтры

Вложенный ALL в FILTER, в отличие от REMOVEFILTERS, возвращает таблицу и снимает все существующие фильтры. Соответственно, REMOVEFILTERS может работать только как модификатор CALCULATE, не возвращая новую таблицу.

Рассмотрим удаление фильтра по customer через ALL(customer) в FILTER:

EVALUATE
SUMMARIZECOLUMNS (
    product[product_color],
    customer[customer_gender],
    FILTER ( customer, customer[customer_gender] = "M" ),
    "Total Sales",
        CALCULATE (
            SUM ( sales[amount] ),
            FILTER ( ALL ( customer ), customer[customer_gender] = "F" )
        )
)

Для расчета выражения Total Sales при ALL(customer) в FILTER выполняются следующие шаги:

  1. ALL(customer) создает «новую таблицу» без контекста, причем создаются связи таблиц на основе схемы данных, т.к. ALL умеет возвращать «новую таблицу»

  2. Снимаются все фильтры: фильтр по группировочной колонке product_color из таблицы product, фильтр по группировочной колонке customer[customer_gender] и фильтр по таблице customer и полу M

  3. FILTER для фильтрации по полу F работает по этой «новой таблице»

  4. «Новая таблица» из ALL после фильтрации по полу F «присоединяется обратно» по группировочным полям product, для customer — не присоединяется контекст фильтра SUMMARIZECOLUMNS по полям customer, т.к. мы его удалили через ALL(customer). С точки зрения контекста фильтра SUMMARIZECOLUMNS — берем все цвета из product[product_color] (т.к. фильтров по цвету в SUMMARIZECOLUMNS нет), но т.к. в выражении Total Sales есть фильтр по customer и считаем продажи по F, причем по F есть продажи только черных и зеленых продуктов, поэтому только для Black и Green будут записи, т.к. пустые результаты Total Sales не выводятся. Для каждого значения группировочного поля product[product_color] из контекста фильтра SUMMARIZECOLUMNS получаем разные значения продаж, причем считаем продажи по F, а выводим пол M. С учетом возможности вывода только ненулевых значений Total Sales получим только Black и Green продажи для пола F, но подписанные как M.

Рассмотрим удаление фильтра по product через ALL(product) в FILTER:

EVALUATE
SUMMARIZECOLUMNS (
    product[product_color],
    customer[customer_gender],
    FILTER ( customer, customer[customer_gender] = "M" ),
    "Total Sales",
        CALCULATE (
            SUM ( sales[amount] ),
            FILTER ( ALL ( product ), product[product_color] = "Green" )
        )
)

Для расчета выражения Total Sales при ALL(product) в FILTER выполняются следующие шаги:

  1. ALL(product) создает «новую таблицу» без контекста, причем создаются связи таблиц на основе схемы данных, т.к. ALL умеет возвращать «новую таблицу»

  2. Снимаются все фильтры: фильтр по группировочной колонке product_color из таблицы product, фильтр по группировочной колонке customer[customer_gender] и фильтр по таблице customer и полу M

  3. FILTER для фильтрации по цвету Green работает по этой «новой таблице»

  4. «Новая таблица» из ALL по фильтрации по цвету Green «присоединяется обратно» по группировочным полям customer, для product — не присоединяем контекст фильтра SUMMARIZECOLUMNS по полям product, т.к. мы его удалили через ALL(product). С точки зрения контекста фильтра SUMMARIZECOLUMNS — берем все цвета из product[product_color] (т.к. фильтров по цвету нет), но поскольку в выражении Total Sales фильтр по product сброшен через ALL(product), то для каждого значения группировочного поля product[product_color] из контекста фильтра получаем одно и то же значение Total Sales, равное 4.28, что соответствует продажам по цвету Green и полу M. Видно, что отображаемые в результатах цвета product_color разные, но Total Sales считается только по Green. Видно, что в этом запросе, в отличие от предыдущего, пол M соответствует результатам в Total Sales, т.е. действительно отображаются продажи по полу M.

Вывод

В качестве модификатора в CALCULATE поведение ALL и REMOVEFILTERS одинаково и REMOVEFILTERS является лишь псевдонимом для ALL. Однако ALL в FILTER приводит к отмене всех фильтров и созданию «новой таблицы». Если интерпретировать несколько образно, то ALL в FILTER создает «новую вселенную» в данных, и затем движок DAX объединяет результаты с контекстом фильтра SUMMARIZECOLUMNS.

Надеюсь, приведенные выводы могут быть интересны, успешных дашбордов :-)

Комментарии (0)