All streams
Search
Write a publication
Pull to refresh
1
0
Send message

Про DAX-часть с точки зрения BI-инженера, который особо не лезет вглубь :-)

Формулы Total Quantity = SUM(Sales[Quantity]) в DAX было бы вполне достаточно.

Прелесть DAX и, одновременно, сложность для разработчика, привыкшего к SQL-стилю, и состоит в том, что в таких случаях поля из dimensions в формуле не нужны, т.к. связи (relationships) обеспечат правильные срезы и агрегирование "автомагически".

Доп. плюс: если позднее добавятся новые dimensions (например, регион продаж с соотв. связью с Sales), код для Total Quantity обновлять не нужно - все должно работать как прежде.

SUMMARIZE с явным указанием полей для группирования в таком случае потребует обновления. Если представить, что таких dimensions в крупных системах десяток-другой-третий, то обслуживание такого кода будет большой проблемой.

Пример в Excel с Power Pivot
Пример в Excel с Power Pivot


P.S. Поправка: амперсанд (&) для условия "И" должен быть двойным (&&) - как и вертикальная черта (|) для условия "ИЛИ" (||).

IF(AND(‘Sales’[TotalSales] > 5000, OR(‘Sales’[Profit] > 1000, ‘Sales’[Cost] < 3000)), "Оптимально", "Неоптимально")

IF( ‘Sales’[TotalSales] > 5000 & ( Sales’[Profit] > 1000 || ‘Sales’[Cost] < 3000)
, "Оптимально"
, "Неоптимально"
)

https://learn.microsoft.com/en-us/dax/dax-operator-reference#logical-operators
:-)

Скорее всего, это просто требование безопасности. У многих западных облачных провайдеров вообще запрещено выносить диски из ЦОДов - их так же разрушают через шреддеры. Соответственно, никаких ремонтов-замен по гарантии вне ЦОДов.

Спасибо, принято.
Кстати, SQL тоже может быть попроще. Давненько я не писал SQL-запросы (работаю с другими типами БД), но если помню правильно, то условия в WHERE применяются раньше чем GROUP BY. Тогда первый пример может выглядеть так:

SELECT product.category AS "Категория",
client.name AS "Имя клиента",
SUM(sales.price) AS "Продажи товаров дешевле 1000"
FROM sales
INNER JOIN product ON sales.productkey = product.dimproduct_productkey
INNER JOIN client ON sales.customerkey = client.dimcustomer_customerkey
WHERE sales.price < 1000
GROUP BY product.category, client.name;

Преимущества DAX на этом примере:
- Если модель данных спроектирована правильно и сценарий использует созданные там связи (relationships), то во многих случаях в DAX JOIN-ы не нужны. Связи в табулярных моделях - "активные", т.е. работают как одно- или двунаправленные фильтры между связанными таблицами. При желании их можно (пере)определить прямо в коде (например, через функции USERELATIONSHIP, TREATAS, NATURAL*JOIN и пр)
- То же относится и к GROUP BY - как минимум, в типовых случаях DAX-движок понимает из контекста что нужно агрегировать
- В SQL трудно разделить меру (метрику) и контекст. Все поля и фильтры должны явным образом включаться в запрос, что увеличивает трудоемкость разработки запросов в разы (особенно с учетом обработки "крайних случаев" - пустых значений, больших списков значений в фильтрах, "Выбрать всё" и пр). Я пока не видел такой интеграции с UI (Power BI, Excel и т.п.), которая бы позволяла генерировать их автоматически так же просто и элегантно, как это делает c DAX PowerBI или Excel.

Пардон за длинный комментарий-добавление. О наболевшем :-)

Одно из ключевых преимуществ Power BI состоит в том, что код DAX в measures (метриках/вычислениях) автоматически "понимает" контекст из пользовательского интерфейса(фильтры-слайсеры, что в колонках /строчках сводных таблиц или на осях и категориях в графиках в визуализациях). При этом связи (relationships) между таблицами работают по умолчанию как фильтры, что тоже нужно учитывать.

Код с Evaluate - это обрамление вокруг метрик, которое используется при их отладке ну или в презентациях в целях демонстрации. При реальном использовании отчетов, Evaluate генерируется автоматически и пользователь (да и разработчик) его не видит (пока не захочет :-) )Т.е. реальный код DAX еще лаконичней чем в примерах.

Но! Мастерство разработчика DAX состоит как раз в написании кода метрик, которые будут работать в разных контекстах, т.е. в визуализациях с разным набором полей и на разных уровнях агрегации. Тогда модель получается элегантной и простой в использовании.

Например, более универсальная первая метрика могла бы выглядеть так:

Продажи товаров дешевле 1000 руб =
CALCULATE(SUM('Продажи'[Цена]), 'Продажи'[Цена]<1000)

И все. Если нужно посмотреть распределение по категориям/клиентам - добавляете в визуализацию (например, сводную таблицу) эти две категории и эту метрику (ну и, например, год-месяц в колонки) и получаете требуемый результат.
Нужно порезать по регионам - используете атрибут клиента "Регион" и все ту же метрику. И т.д. и т.п. Т.е. разработчик предвидит, что эта метрика будет использоваться в разных "разрезах", и избегает использования фиксированного набора категорий когда это возможно.

Кстати, рекомендуют сначала сделать базовую метрику
Сумма Продаж = SUM('Продажи'[Цена])

, а потом добавлять ее производные по мере надобности:

Продажи товаров дешевле 1000 руб =
CALCULATE([Сумма Продаж], 'Продажи'[Цена]<1000)

Продажи товаров дороже 2000 руб =
CALCULATE([Сумма Продаж], 'Продажи'[Цена] > 2000)

И т.п.

Подскажите, в Visiology это так же может быть реализовано? Или есть ограничения?

P.S.
- FILTER внутри CALCULATE в этом случае генерируется автоматически
- SUM лучше чем MAX отвечает на поставленный вопрос "Кто скупил дешевую колбасу?" :-)

Information

Rating
Does not participate
Registered
Activity