Podstawy MDX. Podstawy MDX. Podstawy MDX. Struktura kostki [BiznesG]



Podobne dokumenty
przygotował: Podstawy języka MDX Tworzenie zbiorów

Integracja i Eksploracja Danych

MDX ZAWARTOŚĆ O MDX. Wyk onał: Zatwi erdził: KSPBC_Szkolenie_ doc. Spra wdził: Strona 1 z 15

Systemy OLAP I. Krzysztof Dembczyński. Instytut Informatyki Zakład Inteligentnych Systemów Wspomagania Decyzji Politechnika Poznańska

OnLine Analytical Processing (OLAP) Kostki OLAP i zapytania MDX

Krzysztof Dembczyński. Inteligentne Systemy Wspomagania Decyzji Studia magisterskie, semestr I Semestr letni 2007/08

Analityczny język zapytań MDX: zaawansowane

Funkcjonalność języka MDX w implementacji HYPERION

Nauczycielem wszystkiego jest praktyka Juliusz Cezar. Nauka to wiara w ignorancję ekspertów Richard Feynman

Analityczny język zapytań MDX: podstawy

Autor: Joanna Karwowska

Przestrzenne bazy danych Podstawy języka SQL

SQL (ang. Structured Query Language)

Podstawowe zapytania SELECT (na jednej tabeli)

Teoretyczne podstawy informatyki

Kostki OLAP i język MDX

ORACLE. System Zarządzania Bazą Danych Oracle. Oracle Advanced SQL

Microsoft Excel 2013: Budowanie modeli danych przy użyciu PowerPivot

Systemy OLAP I. Krzysztof Dembczyński. Instytut Informatyki Zakład Inteligentnych Systemów Wspomagania Decyzji Politechnika Poznańska

Wykład 6. SQL praca z tabelami 3

Wykład 7 Implementacja języka SQL w systemach baz danych Oracle sortowanie, funkcje agregujące i podzapytania.

opisuje nazwy kolumn, wyrażenia arytmetyczne, funkcje nazwy tabel lub widoków warunek (wybieranie wierszy)

- język zapytań służący do zapisywania wyrażeń relacji, modyfikacji relacji, tworzenia relacji

Język SQL. Rozdział 5. Połączenia i operatory zbiorowe

Wprowadzenie do języka SQL

Laboratorium nr 8. Temat: Podstawy języka zapytań SQL (część 2)

Relacyjne bazy danych. Podstawy SQL

Bazy danych Access KWERENDY

Język SQL. Rozdział 2. Proste zapytania

Wprowadzenie do hurtowni danych

Systemy GIS Tworzenie zapytań w bazach danych

Wstęp 5 Rozdział 1. Podstawy relacyjnych baz danych 9

TP1 - TABELE PRZESTAWNE od A do Z

SQL - Structured Query Language. strukturalny język zapytań

SQL praca z tabelami 4. Wykład 7

Bazy danych. Plan wykładu. Zależności funkcyjne. Wykład 2: Relacyjny model danych - zależności funkcyjne. Podstawy SQL.

Podstawy języka SQL cz. 2

OLAP i hurtownie danych c.d.

Autor: Joanna Karwowska

Ćwiczenie zapytań języka bazy danych PostgreSQL

Język SQL. Rozdział 4. Funkcje grupowe Funkcje grupowe, podział relacji na grupy, klauzule GROUP BY i HAVING.

System imed24 Instrukcja Moduł Analizy i raporty

Podzapytania. Rozdział 5. Podzapytania. Podzapytania wyznaczające wiele krotek (1) Podzapytania wyznaczające jedną krotkę

Relacyjne bazy danych. Podstawy SQL

MS Excel 2007 Kurs zaawansowany Obsługa baz danych. prowadzi: Dr inż. Tomasz Bartuś. Kraków:

Informatyka sem. III studia inżynierskie Transport 2018/19 LAB 2. Lab Backup bazy danych. Tworzenie kopii (backup) bazy danych

Autor: Joanna Karwowska

Podzapytania. Rozdział 5. Podzapytania. Podzapytania wyznaczające wiele krotek (1) Podzapytania wyznaczające jedną krotkę

Bazy danych SQL Server 2005

Konstruowanie Baz Danych SQL UNION, INTERSECT, EXCEPT

Excel 2016 PL w biurze i nie tylko / Sergiusz Flanczewski. Gliwice, cop Spis treści

Podzapytania. Rozdział 5. Podzapytania. Podzapytania wyznaczające wiele krotek (1) Podzapytania wyznaczające jedną krotkę

SQL do zaawansowanych analiz danych część 1.

Technologie baz danych

Agregacja i Grupowanie Danych. Funkcje Agregacji. Opcje GROUP BY oraz HAVING

Wykład 5. SQL praca z tabelami 2

Formularze i raporty w MS Access

Język SQL Złączenia. Laboratorium. Akademia Morska w Gdyni

MJUP_Instrukcja obsługi aplikacji. wspomagającej

Plan. Wyświetlanie n początkowych wartości (TOP n) Użycie funkcji agregujących. Grupowanie danych - klauzula GROUP BY

Laboratorium nr 5. Temat: Funkcje agregujące, klauzule GROUP BY, HAVING

koledzy, Jan, Nowak, ul. Niecała 8/23, , Wrocław, , ,

Modele danych - wykład V. Zagadnienia. 1. Wprowadzenie 2. MOLAP modele danych 3. ROLAP modele danych 4. Podsumowanie 5. Zadanie fajne WPROWADZENIE

Program szkoleniowy. 16 h dydaktycznych (12 h zegarowych) NAZWA SZCZEGÓŁY CZAS. Skróty do przeglądania arkusza. Skróty dostępu do narzędzi

Bazy danych 8. Podzapytania i grupowanie. P. F. Góra

Wybór wszystkich danych: SELECT * FROM employee Wybór określonych kolumn lub wyrażeń: SELECT first_name, last_name, salary FROM employee

Laboratorium Bazy danych SQL 2

INFORMATYKA GEODEZYJNO- KARTOGRAFICZNA Relacyjny model danych. Relacyjny model danych Struktury danych Operacje Oganiczenia integralnościowe

Konstruowanie Baz Danych DQL agregacja danych

Tablice. Jones Stygar na tropie zmiennych

Autor: dr inż. Katarzyna Rudnik

Hurtownie danych. Projektowanie hurtowni: modele wielowymiarowe. Modelowanie punktowe. Operacje OLAP na kostkach.

Ćwiczenie 3 funkcje agregujące

Wprowadzenie do SQL TEMAT 3 - Zadania dodatkowe

ORACLE. System Zarządzania Bazą Danych Oracle. Oracle Advanced SQL

Spis treści. Część I Wprowadzenie do pakietu oprogramowania Analysis Services

140, , ,000 80, ROK

Analityczny język zapytań MDX: wstęp

etrader Pekao Podręcznik użytkownika Portfel inwestycyjny

Część I Istota analizy biznesowej a Analysis Services

Języki programowania wysokiego poziomu. PHP cz.4. Bazy danych

Przykład powyżej pokazuje, że w zapytaniu można umieszczać funkcje zarówno zdefiniowane w ramach środowiska, jak również własne.

Bazy danych wykład trzeci. Konrad Zdanowski

Kwerenda. parametryczna, z polem wyliczeniowym, krzyżowa

SQL Server Analysis Services Procedury składowane. Grzegorz Stolecki

WSCHÓD I ZACHÓD SŁOŃCA SUNRISE / SUNSET

Hurtownie danych. Przetwarzanie zapytań. ZAPYTANIA NA ZAPLECZU

1: 2: 3: 4: 5: 6: 7: 8: 9: 10:

Wprowadzenie do Hurtowni Danych. Mariusz Rafało

Język DML. Instrukcje DML w różnych implementacjach SQL są bardzo podobne. Podstawowymi instrukcjami DML są: SELECT INSERT UPDATE DELETE

WSCHÓD I ZACHÓD SŁOŃCA SUNRISE / SUNSET

Symfonia Produkcja. Kreator raportów. Wersja 2013

WSCHÓD I ZACHÓD SŁOŃCA SUNRISE / SUNSET

Modele danych - wykład V

Podstawy języka T-SQL : Microsoft SQL Server 2016 i Azure SQL Database / Itzik Ben-Gan. Warszawa, Spis treści

Język SQL. Rozdział 6. Podzapytania Podzapytania proste i skorelowane, podzapytania w klauzuli SELECT i FROM, operatory ANY, ALL i EXISTS.

SQL do zaawansowanych analiz danych część 2.

Podstawy języka SQL. SQL Structured Query Languagestrukturalny

Zaokrąglanie liczb Adresowanie względne i bezwzględne Automatyczne podejmowanie decyzji Porządkowanie tabeli danych

Struktura drzewa w MySQL. Michał Tyszczenko

Transkrypt:

Podstawowe zapytanie MDX ma strukturę podobną do zapytań SQL. Najprostsza postać zwraca dwuwymiarową kostkę: opis osi ON COLUMNS, opis osi ON ROWS FROM nazwa_kostki [WHERE opis_plastra] Najprostsza postać opisu osi lub wyboru członów używa MEMBERS jako wymaganego wymiaru, łącznie ze wymiarem Measures: Measures.MEMBERS ON COLUMNS, [Nazwa kategorii].members ON ROWS Opis osi może być traktowany jako wybór członu dla osi. Jeżeli wymagany jest pojedynczy wymiar, przy użyciu takiego zapisu musi być zwrócone COLUMNS. Dla większej ilości wymaganych wymiarów nazwami osi byłyby PAGES (strony), CHAPTERS (rozdziały) oraz SECTIONS (sekcje). Jeśli chcemy użyć bardziej uniwersalnych określeń osi, możemy użyć konwencji: AXIS(index), gdzie index jest zakresem rozpoczynającym się od zera. W Management Studio dopuszczalne tylko dwie osie. Jeżeli chcemy wyliczyć elementy wymiaru, mogą one być zwrócone jako pojedyncza oś (lista ograniczona {...} rozdzielona, : Measures.MEMBERS ON COLUMNS, {[Nazwa kategorii].[clocks], [Nazwa kategorii].[sampler] } ON ROWS Struktura kostki [BiznesG] 1

Parents Descendants ANCESTOR(Time.[2000].[Q1], Time.[Year]) Time.[2000].[Q1].Parent.Parent Time.[2000].Parent All Time.[2001].Parent All Time.[2000].[Q1].Parent 2000 2001 Descendants( Time.[2000], Quarter) 2000 2001 Q1 Q2 Q3 Q4 Q1 Q2 Q3 Q4 Q1 Q2 Q3 Q4 Q1 Q2 Q3 Q4 Jan Feb Mar Oct Nov Dec Jan Feb Mar Oct Nov Dec Descendants( Time.[2000], Month) Children Descendants All All Time.[2000].FirstChild Time.[2000].Children 2000 2001 2000 2001 Q1 Q2 Q3 Q4 Q1 Q2 Q3 Q4 Q1 Q2 Q3 Q4 Q1 Q2 Q3 Q4 Jan Feb Mar Oct Nov Dec Jan Feb Mar Oct Nov Dec Descendants(Time.[2000].[Jan], Month) 2

Aby uzyskać miary dla członów składających się na te kategorie, zapytalibyśmy ich dzieci (CHILDREN): Measures.MEMBERS ON COLUMNS, {[KategoriaProduktuH].[Nazwa kategorii].[clocks].children, [KategoriaProduktuH].[Nazwa kategorii].[sampler].children } ON ROWS Miary obliczane nie są dołączane, gdy pobierane są człony wymiarów. Ich uwzględnienie musi być jawnie narzucone, przez użycie funkcji ADDCALCULATEDMEMBERS:. ADDCALCULATEDMEMBERS(Measures.MEMBERS) ON COLUMNS, {[KategoriaProduktuH].[Nazwa kategorii].[clocks], DESCENDANTS( [KategoriaProduktuH].[Nazwa kategorii].[clocks],[nazwa Towaru])}ON ROWS Funkcja MEMBERS zwraca elementy wskazanego wymiaru lub poziomu wymiarów. Funkcja CHILDREN zwraca dzieci dla określonego członu wymiaru. Obie funkcje są używane przy formułowaniu wyrażeń, ale nie zapewniają możliwości rozwijania do niższych poziomów hierarchii. Przy użyciu funkcji DESCENDANTS możliwe się staje zapytanie kostki o informacje na poziomie nazwa towaru dla wybranej kategorii Measures.MEMBERS ON COLUMNS, { [KategoriaProduktuH].[Nazwa kategorii].[clocks], DESCENDANTS( [KategoriaProduktuH].[Nazwa kategorii].[clocks], [Nazwa Towaru]) }ON ROWS Wybór miar do wyświetlenia {MEASURES.wartosc, MEASURES.zysk} ON COLUMNS, { [KategoriaProduktuH].[Nazwa kategorii].[clocks], DESCENDANTS( [KategoriaProduktuH].[Nazwa kategorii].[clocks], [Nazwa Towaru]) }ON ROWS DESCENDANTS(człon, poziom [, flagi]) Wartość flagi może wynosić: SELF (domyślna wartość), BEFORE, AFTER lub BEFORE_AND_AFTER 3

Zastosowanie krotki na wymiarach w celu wyświetlenia hierarchii ADDCALCULATEDMEMBERS(Measures.MEMBERS) ON COLUMNS, {CROSSJOIN( [KategoriaTowaruG].[Nazwa kategorii].members, [KategoriaProduktuH].[Nazwa Towaru].members)}ON ROWS Każda pozycja z jednego wymiaru z każdą z drugiego CROSSJOIN nie może być zastosowany do dwa razy występującego tego samego wymiaru Zastosowanie krotki na wymiarach w celu wyświetlenia hierarchii ADDCALCULATEDMEMBERS(Measures.MEMBERS) ON COLUMNS, { NONEMPTY (CROSSJOIN( FILTER ( [KategoriaTowaruG].[Nazwa kategorii].members, [KategoriaTowaruG].[Nazwa kategorii]<>[kategoriatowarug].[nazwa kategorii].[all] ), [KategoriaProduktuH].[Nazwa Towaru].members)) }ON ROWS Wyeliminowanie elementu ALL reprezentującego wszystkie obiekty poziomu nadrzędnego osiągamy przez zastosowanie funkcji FILTER Zastosowanie krotki na wymiarach w celu wyświetlenia hierarchii ADDCALCULATEDMEMBERS(Measures.MEMBERS) ON COLUMNS, { NONEMPTY (CROSSJOIN( [KategoriaTowaruG].[Nazwa kategorii].members, [KategoriaProduktuH].[Nazwa Towaru].members)) }ON ROWS Nie zastosowanie krotki powoduje spłaszczenie wyświetlania Measures.MEMBERS ON COLUMNS, { [KategoriaProduktuH].[Nazwa kategorii].members, [KategoriaProduktuH].[Nazwa Towaru].members}ON ROWS W celu wyeliminowania niepowiązanych rekordów zastosować możemy operator NONEMPTY Nazwy towarów dla kategorii CLOCKS 4

Specyfikację plastra definiuje się przez klauzulę WHERE [Nazwa Kategorii].MEMBERS ON COLUMNS, [LokalizacjaKlientaH].[Województwo].MEMBERS ON ROWS WHERE ([Measures].[wartosc]) [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS ON COLUMNS, [LokalizacjaKlientaH].[Województwo].MEMBERS ON ROWS WHERE ([Measures].[wartosc], [Towar G].[Nazwa Kategorii].[CLOCKS]) Definiowanie plastra z wykorzystaniem dwóch wymiarów zawierających ten sam poziom Mało eleganckie ze względu na wartości NULL Bardziej szczegółową definicję plastra można osiągnąć przez zdefiniowanie konkretnej wartości wymiaru [Nazwa Kategorii].MEMBERS ON COLUMNS, [LokalizacjaKlientaH].[Województwo].MEMBERS ON ROWS WHERE ([Measures].[wartosc], [Data Faktury].[Rok].[2003]) Nie można do definiowania plastra użyć wymiaru poprzednio wykorzystanego do definiowania kolumn lub wierszy NONEMPTY([KategoriaTowaruG].[Nazwa Kategorii].MEMBERS) ON COLUMNS, [LokalizacjaKlientaH].[Województwo].MEMBERS ON ROWS WHERE ([Measures].[wartosc], [Towar G].[Nazwa Kategorii].[CLOCKS]) Definiowanie plastra z wykorzystaniem dwóch wymiarów zawierających ten sam poziom Pominięcie wartości NULL przy użyciu NONEMPTY 5

[KategoriaTowaruG].[Nazwa Kategorii].[CLOCKS] ON COLUMNS, [LokalizacjaKlientaH].[Województwo].MEMBERS ON ROWS WHERE ([Measures].[wartosc]) Definiowanie plastra z wykorzystaniem jawnego wskazania na wartość w kolumnie Możliwe jest wyznaczenie członów wyliczanych Ad hoc przy zastosowaniu klauzuli oraz miary wyliczanej MEMBER Measures.ZyskProcentowy AS '([Measures].[zysk]) / [Measures].[WartoscZakupu]', FORMAT_STRING = '#.00%' [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS ON COLUMNS, [LokalizacjaKlientaH].[Województwo].MEMBERS ON ROWS WHERE Measures.ZyskProcentowy Możliwe jest wyznaczenie członów wyliczanych Ad hoc przy zastosowaniu klauzuli MEMBER Measures.ZyskProcentowy AS '([Measures].[Wartosc] - [Measures].[WartoscZakupu]) / [Measures].[WartoscZakupu]', FORMAT_STRING = '#.00%' [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS ON COLUMNS, [LokalizacjaKlientaH].[Województwo].MEMBERS ON ROWS WHERE Measures.ZyskProcentowy Możliwe jest wyznaczenie członów wyliczanych Ad hoc przy zastosowaniu klauzuli MEMBER Measures.ZyskProcentowy AS ([Measures].[Wartosc] - [Measures].[WartoscZakupu]) / [Measures].[WartoscZakupu], FORMAT_STRING = '0.000%' ZyskProcentowy ON COLUMNS, [LokalizacjaKlientaH].[Województwo].MEMBERS ON ROWS 6

Możliwe jest wyznaczenie członów wyliczanych Ad hoc przy zastosowaniu klauzuli i odczytanie ich przez ADDCALCULATEDMEMBERS MEMBER Measures.ZyskProcentowy AS '([Measures].[zysk]) / [Measures].[WartoscZakupu]', FORMAT_STRING = '#.00%' ADDCALCULATEDMEMBERS(MEASURES.MEMBERS) ON COLUMNS, [LokalizacjaKlientaH].[Województwo].MEMBERS ON ROWS MEMBER Measures.ZyskProcentowy AS '([Measures].[zysk]) /[Measures].[WartoscZakupu]', FORMAT_STRING = '#.##%' MEMBER [Data Faktury].[Miesiac].PierwszaPolowa AS '[Miesiac].[1]+[Miesiac].[2]+[Miesiac].[3]+[Miesiac].[4]+[Miesiac].[5]+[Miesiac].[6]' MEMBER [Data Faktury].[Miesiac].DrugaPolowa AS '[Miesiac].[7]+[Miesiac].[8]+[Miesiac].[9]+[Miesiac].[10]+[Miesiac].[11] +[Miesiac].[12]' {PierwszaPolowa, DrugaPolowa, [Data Faktury].Miesiac.MEMBERS} ON COLUMNS, [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS on ROWS WHERE Measures.ZyskProcentowy MEMBER Measures.ZyskProcentowy AS '([Measures].[zysk]) /[Measures].[WartoscZakupu]', FORMAT_STRING = '#.##%' MEMBER [Data Faktury].[Miesiac].PierwszaPolowa AS '[Miesiac].[1]+[Miesiac].[2]+[Miesiac].[3]+[Miesiac].[4]+[Miesiac].[5]+[Miesiac].[6]' MEMBER [Data Faktury].[Miesiac].DrugaPolowa AS '[Miesiac].[7]+[Miesiac].[8]+[Miesiac].[9]+[Miesiac].[10]+ [Miesiac].[11]+[Miesiac].[12]' {PierwszaPolowa, DrugaPolowa} ON columns, [KategoriaTowaruG].[Nazwa Kategorii].members on rows WHERE Measures.ZyskProcentowy Używając obliczanych członów możemy łatwo zdefiniować nowy wymiar CZASU służący do przedstawienia roku z rozbiciem na połowy : MEMBER Measures.ZyskProcentowy AS '([Measures].[zysk]) /[Measures].[WartoscZakupu]', FORMAT_STRING = '#.##%, SOLVE_ORDER=1 MEMBER [Data Faktury].[Miesiac].PierwszaPolowa AS '[Miesiac].[1]+[Miesiac].[2]+[Miesiac].[3]+[Miesiac].[4]+[Miesiac].[5]+[Miesiac].[6]' MEMBER [Data Faktury].[Miesiac].DrugaPolowa AS '[Miesiac].[7]+[Miesiac].[8]+[Miesiac].[9]+[Miesiac].[10]+[Miesiac].[11] +[Miesiac].[12]' {PierwszaPolowa, DrugaPolowa, [Data Faktury].Miesiac.MEMBERS} ON COLUMNS, [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS on ROWS WHERE Measures.ZyskProcentowy Wymuszenie kolejność obliczania miar wyliczanych za pomocą SOLVE_ORDER=? 7

MEMBER Measures.ZyskProcentowy AS '([Measures].[zysk]) /[Measures].[WartoscZakupu]', FORMAT_STRING = '#.##%', SOLVE_ORDER=1 MEMBER [Data Faktury].[Kwartal].PierwszaPolowa AS '[Kwartal].[1]+[Kwartal].[2]' MEMBER [Data Faktury].[Kwartal].DrugaPolowa AS '[Kwartal].[3]+[Kwartal].[4]' {PierwszaPolowa, DrugaPolowa,[Data Faktury].Kwartal.MEMBERS} ON COLUMNS, [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS ON ROWS WHERE Measures.ZyskProcentowy 1. How did Sales this period compare with Sales in the previous period? Q2 Qtr Apr May Jun Mon Sales 200 65 45 90 Delta (DELTA) = 80 15-20 45 (Time.CurrentMember, Measures.Sales) - Podobna realizacja ale dla wprowadzonej hierarchii Kwartal (Time.CurrentMember.PrevMember, Measures.Sales) Porównanie z poprzednim okresem Year Qtr Mon Sales 2000 790 Q1 120 Jan 30 Feb 40 Mar 50 Q2 200 Apr 65 May 45 Jun 90 Q3 185 Jul 55 Aug 60 Sep 70 Q4 285 Oct 80 Nov 100 Dec 105 Porównanie z równoległym okresem poprzedniego roku Year Qtr Mon Sales 2000 790 Q1 120 Jan 30 Feb 40 Mar 50 Q4 285 Oct 80 Nov 100 Dec 105 2001 850 Q1 170 Jan 50 Feb 55 Mar 65 Q4 275 Oct 90 Nov 100 Dec 85 8

Porównanie z równoległym okresem poprzedniego roku Year Qtr Mon Sales Delta 2000 790 Q1 120 Jan 30 Feb 40 Mar 50 2001 850 Q1 170 Jan 50 20 Feb 55 Mar 65 (DELTA)= (Time.CurrentMember, Measures.Sales)- Źle (Time.CurrentMember.Lag(12), (ParallelPeriod(Year,1,Time.CurrentMember), Measures.Sales) Measures.Sales) 3. What have Sales been since the beginning of the year? Year Qtr Mon Sales YTD 2000 790 Q1 120 120 Jan 30 30 Feb 40 70 Mar 50 120 Time.Jan,Measures.Sales + Sum(YTD(Time.CurrentMember), Time.Feb,Measures.Sales + Źle Sales) Time.Mar,Measures.Sales Wyznaczanie sumy bieżącej od początku roku Year Qtr Mon Sales 2000 790 Q1 120 Jan 30 Feb 40 Mar 50 Q2 200 Apr 65 May 45 Jun 90 Q3 185 Jul 55 Aug 60 Sep 70 Q4 285 Oct 80 Nov 100 Dec 105 3. What have Sales been since the beginning of the year? Year Qtr Mon Sales 2000 790 Q1 120 Jan 30 Feb 40 Mar 50 Time.Jan,Measures.Sales + Time.Feb,Measures.Sales + Time.Mar,Measures.Sales Sum(YTD(Time.CurrentMember), Sales) = YTD 120 30 70 120 9

możemy wyświetlić zysk dla każdej kategorii towaru w każdym pierwszym kwartale (pierwszy potomek hierarchii) każdego roku: SET [Kwartal1] AS GENERATE([Data Faktury].[DataFakturyH].[Rok].MEMBERS, {[Data Faktury].[DataFakturyH].CURRENTMEMBER.FIRSTCHILD}) [Kwartal1] ON COLUMNS, [Towar G].[Nazwa Kategorii].MEMBERS ON ROWS WHERE ([Measures].[Zysk]) możemy wyświetlić zysk dla każdej kategorii towaru w każdym pierwszym kwartale (pierwszy potomek hierarchii - numeracja od 0) każdego roku: SET [Kwartal1] AS GENERATE([Data Faktury].[DataFakturyH].[Rok].MEMBERS, {[Data Faktury].[DataFakturyH].CURRENTMEMBER.children(0)}) [Kwartal1] ON COLUMNS, [Towar G].[Nazwa Kategorii].MEMBERS ON ROWS WHERE ([Measures].[Zysk]) możemy wyświetlić zysk dla każdej kategorii towaru w każdym ostatnim kwartale (Ostatni potomek hierarchii o ile istnieje) każdego roku: SET [Kwartal1] AS GENERATE([Data Faktury].[DataFakturyH].[Rok].MEMBERS, {[Data Faktury].[DataFakturyH].CURRENTMEMBER.LASTCHILD}) [Kwartal1] ON COLUMNS, [Towar G].[Nazwa Kategorii].MEMBERS ON ROWS WHERE ([Measures].[Zysk]) możemy wyświetlić zysk dla każdej kategorii towaru w każdym pierwszym kwartale (czwarty potomek hierarchii - numeracja od 0) każdego roku: SET [Kwartal1] AS GENERATE([Data Faktury].[DataFakturyH].[Rok].MEMBERS, {[Data Faktury].[DataFakturyH].CURRENTMEMBER.children(3)}) [Kwartal1] ON COLUMNS, [Towar G].[Nazwa Kategorii].MEMBERS ON ROWS WHERE ([Measures].[Zysk]) Gdy niezdefiniowano dla któregoś roku nie jest wyświetlany 10

Wyznaczmy sprzedaż danej marki produktu jako udział procentowy w sprzedaży jego kategorii czyli atrybutu, w odniesieniu do jego rodzica. Wyrażenie tworzące taki miarę obliczaną może zostać uzyskane przy użyciu właściwości CURRENTMEMBER oraz PARENT. MEMBER MEASURES.ZyskKategorii AS ([KategoriaProduktuH].CURRENTMEMBER.PARENt, [Measures].[Zysk]) MEMBER MEASURES.ZyskProcentowy AS ([KategoriaProduktuH].CURRENTMEMBER, [Measures].[Zysk])/ ([KategoriaProduktuH].CURRENTMEMBER.PARENT, [Measures].[Zysk]), FORMAT_STRING = '0.00%' {Measures.ZyskKategorii, [Measures].[Zysk], MEASURES.ZyskProcentowy} ON COLUMNS, [KategoriaProduktuH].[Nazwa Towaru] ON ROWS Wielokrotne użycie funkcji PARENT może być zastąpione przez obliczenie odpowiednich przodków członu CURRENTMEMBER przez funkcje ANCESTOR, zwracającą przodka na odpowiednim poziomie dla podanego członu. Konieczne jest użycie nazwy hierarchii: MEMBER MEASURES.ZyskKategorii AS (ANCESTOR([KategoriaProduktuH].CURRENTMEMBER, [KategoriaProduktuH].[Nazwa Kategorii]), [Measures].[Zysk]) MEMBER MEASURES.ZyskProcentowy AS ([KategoriaProduktuH].currentmember, [Measures].[Zysk])/ (ANCESTOR([KategoriaProduktuH].CURRENTMEMBER, [KategoriaProduktuH].[Nazwa Kategorii]), [Measures].[Zysk]), FORMAT_STRING = '0.00%' {MEASURES.ZyskKategorii,[Measures].[Zysk], MEASURES.ZyskProcentowy} ON COLUMNS, [KategoriaProduktuH].[nazwa towaru] ON ROWS PARENT może być używane wielokrotnie. W naszym przypadku przeniesie nas już na poziom ALL MEMBER MEASURES.ZyskKategorii AS ([KategoriaProduktuH].CURRENTMEMBER.PARENT. PARENT, [Measures].[Zysk]) MEMBER MEASURES.ZyskProcentowy AS ([KategoriaProduktuH].CURRENTMEMBER, [Measures].[Zysk])/ ([KategoriaProduktuH].CURRENTMEMBER.PARENT.PARENT, [Measures].[Zysk]), FORMAT_STRING = '0.00%' {Measures.ZyskKategorii, [Measures].[Zysk], MEASURES.ZyskProcentowy} ON COLUMNS, [KategoriaProduktuH].[Nazwa Towaru] ON ROWS użycie nazwanych zbiorów i funkcji EXCEPT (odnajduje różnice pomiędzy dwoma zbiorami) umożliwia skonstruowanie wyrażenia, które pokaże procentową sprzedaż dla każdej grupy towarów w porównaniu do całości pomniejszonej o sprzedaż zegarów SET [OproczZegarow] AS EXCEPT([KategoriaProduktuH].[Nazwa Kategorii].MEMBERS, [Towar G].[KategoriaProduktuH].[Nazwa Kategorii].[Clocks]) MEMBER Measures.ProcentSprzedazy AS ([KategoriaProduktuH].CURRENTMEMBER, [Measures].[Zysk]) / SUM([OproczZegarow], [Measures].[Zysk]), FORMAT_STRING = '#.00%' {[Measures].[Zysk], Measures.ProcentSprzedazy} ON COLUMNS, [OproczZegarow] ON ROWS 11

Formatowanie warunkowe SET Towary as [KategoriaProduktuH].[Nazwa Kategorii].MEMBERS MEMBER Measures.zakup AS [Measures].[Wartosc], FORMAT_STRING = IIF(zakup>800,'#.00','{#.00)'), fore_color = IIF(zakup>800,RGB(255,0,0), RGB(255,255,0)), back_color = IIF(zakup>800,RGB(0,255,255), RGB(0,155,0)), FONT_FLAGS = IIF(zakup>800,MDFF_BOLD or MDFF_UNDERLINE,MDFF_ITALIC or MDFF_STRIKEOUT), FONT_NAME = IIF(zakup>800,ARIAL,Times), FONT_SIZE = IIF(zakup>800,16,10) Towary ON COLUMNS, [LokalizacjaKlientaH].[Województwo].MEMBERS ON ROWS Nie wszystko działa?!! WHERE Measures.Zakup CELL PROPERTIES VALUE, FORMATTED_VALUE, CELL_ORDINAL, FORMAT_STRING, FORE_COLOR, BACK_COLOR, FONT_FLAGS, FONT_NAME, FONT_SIZE To samo ale z zastosowaniem DESCENDANTS GENERATE([DataFakturyH].[Rok].MEMBERS, {[DataFakturyH].CURRENTMEMBER, DESCENDANTS([DataFakturyH].CURRENTMEMBER, [Data Faktury].[DataFakturyH].[Kwartal])}) ON COLUMNS, [KategoriaProduktuH].[Nazwa Kategorii].members ON ROWS WHERE ([Measures].[Zysk]) Rozpatrzmy zapytanie mające zwracać na osi kolumn informacje o sprzedaży w każdym roku oraz odpowiadające im szczegóły kwartalne. GENERATE([DataFakturyH].[Rok].MEMBERS, {[DataFakturyH].CURRENTMEMBER, [DataFakturyH].CURRENTMEMBER.CHILDREN}) ON COLUMNS, [KategoriaProduktuH].[Nazwa Kategorii].members ON ROWS WHERE ([Measures].[Zysk]) To samo ale z rozbiciem na miesiące GENERATE([DataFakturyH].[Rok].MEMBERS, {[DataFakturyH].CURRENTMEMBER, DESCENDANTS([DataFakturyH].CURRENTMEMBER, [Data Faktury].[DataFakturyH].[Miesiac])}) ON COLUMNS, [KategoriaProduktuH].[Nazwa Kategorii].members ON ROWS WHERE ([Measures].[Zysk]) 12

Pokazanie wzrostu w okresie czasu umożliwia funkcja PREVMEMBER. Jeżeli mielibyśmy wyświetlić zysk ze sprzedaży i przyrostową zmianę od poprzedniego członu czasu na poziomie kolejnych miesięcy MEMBER Measures.[wzrost Zysku] AS ([Measures].[Zysk]) - ([Measures].[Zysk],[DataFakturyH].PREVMEMBER), FORMAT_STRING = '###,###.00 ZŁ' {[Measures].[Zysk], Measures.[wzrost Zysku]} ON COLUMNS, {DESCENDANTS([DataFakturyH], [DataFakturyH].[miesiac])} ON ROWS Możemy również użyć funkcji LEAD, która zwraca człon oddalony w wymiarze o określoną liczbę pozycji od wskazanego członu. MEMBER Measures.[wzrost Zysku] AS ([Measures].[Zysk]) - ([Measures].[Zysk],[DataFakturyH]. LEAD)(-2)), FORMAT_STRING = '###,###.00 ZŁ' {[Measures].[Zysk], Measures.[wzrost Zysku]} ON COLUMNS, {DESCENDANTS([DataFakturyH], [DataFakturyH].[miesiac])} ON ROWS Użycie NEXTMEMBER w tym wyrażeniu pokazałoby sprzedaż dla każdego miesiąca zestawioną ze sprzedażami z poprzednich miesięcy. MEMBER Measures.[wzrost Zysku] AS ([Measures].[Zysk]) - ([Measures].[Zysk],[DataFakturyH]. NEXTMEMBER), FORMAT_STRING = '###,###.00 ZŁ' {[Measures].[Zysk], Measures.[wzrost Zysku]} ON COLUMNS, {DESCENDANTS([DataFakturyH], [DataFakturyH].[miesiac])} ON ROWS PARALLELPERIOD pozwala na łatwe porównanie wzrostu ze wzrostem z tego samego przedziału czasu w poprzednim kwartale: MEMBER Measures.[wzrost Zysku] AS ([Measures].[Zysk]) - (Measures.[Zysk], PARALLELPERIOD([DataFakturyH].[Kwartal])), FORMAT_STRING = '###,###.00 ZŁ' {[Measures].[Zysk], Measures.[wzrost Zysku]} ON COLUMNS, {DESCENDANTS([DataFakturyH], [DataFakturyH].[miesiac])} ON ROWS Pojawiają się błędy gdy nie zdefiniowno równoległego miesiąca. Miesiące w obrębie kwartału są wykrywane jako kolejne wystąpienia na liście, niezgodnie z kalendarzem 13

Można sprawdzić o ile wzrosła sprzedaż po pierwszym miesiącu sezonu. Używając kwartału do przedstawienia sezonu, można mierzyć różnicę w sprzedaży jednostek dla każdego miesiąca, porównując z miesiącem otwierającym kwartał: MEMBER Measures.[wzrost Zysku] AS ([Measures].[Zysk]) - (Measures.[Zysk], OPENINGPERIOD([DataFakturyH].Miesiac, [DataFakturyH].CURRENTMEMBER.PARENT)), FORMAT_STRING = '###,###.00 ZŁ' {[Measures].[Zysk], Measures.[wzrost Zysku]} ON COLUMNS, {DESCENDANTS([DataFakturyH], [DataFakturyH].[miesiac])} ON ROWS W postaci skróconej można zastosować funkcję YTD() MEMBER Measures.Zysk_YTD AS SUM(YTD(), [Measures].[Zysk]), FORMAT_STRING = '#.00' {[KategoriaTowaruG].[Nazwa Kategorii].MEMBERS} ON Columns, {DESCENDANTS([DataFakturyH], [DataFakturyH].Miesiac)} ON rows WHERE (Measures.Zysk_YTD) OPENINGPERIOD(poziom, człon) CLOSINGINGPERIOD(poziom, człon) Oprócz YTD() istnieją QTD(), MTD() i WTD(). Przy użyciu funkcji SUM i PERIODSTODATE można zdefiniować obliczany człon, który wyświetli informację year-to-date.. Miarą jest suma bieżąca na poziomie roku: PERIODSTODATE([Time].[Year], [Time].CURRENTMEMBER) MEMBER Measures.Zysk_YTD AS SUM(PERIODSTODATE([DataFakturyH].[Rok],[DataFakturyH].CURRENTMEMBER), [Measures].[Zysk]), FORMAT_STRING = '#.00' {[KategoriaTowaruG].[Nazwa Kategorii].MEMBERS} ON Columns, {DESCENDANTS([DataFakturyH], [DataFakturyH].miesiac)} ON rows WHERE (Measures.Zysk_YTD) Przy użyciu funkcji SUM i PERIODSTODATE można zdefiniować obliczany człon, który wyświetli informację Quarter-to-date.. Miarą jest suma bieżąca na poziomie Kwartału: MEMBER Measures.Zysk_QTD AS SUM(PERIODSTODATE([DataFakturyH].[Kwartal],[DataFakturyH].CURRENTMEMB ER), [Measures].[Zysk]), FORMAT_STRING = '#.00' {[KategoriaTowaruG].[Nazwa Kategorii].MEMBERS} ON Columns, {DESCENDANTS([DataFakturyH], [DataFakturyH].miesiac)} ON rows WHERE (Measures.Zysk_QTD) 14

To samo przy użyciu funkcji QTD: MEMBER Measures.Zysk_QTD AS SUM(QTD(), [Measures].[Zysk]), FORMAT_STRING = '#.00' {[KategoriaTowaruG].[Nazwa Kategorii].MEMBERS} ON Columns, [DataFakturyH].miesiac ON rows WHERE (Measures.Zysk_QTD) Usuwanie pustych członów z osi możemy osiągnąć przez zastosowanie klauzuli NON EMPTY, [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS ON COLUMNS, NON EMPTY{CROSSJOIN( [Klienci G].[Województwo].MEMBERS, [Data Faktury].[Kwartal].MEMBERS)} ON ROWS WHERE ([Measures].[Zysk]) Przy takiej definicji krotki zapytanie bieżące i z poprzedniej strony zwracają to samo W wielu przypadkach kombinacja członów z różnych wymiarów jest zamknięta w nawiasach. Kombinacja taka znana jest jako krotka (tuplet) i jest wykorzystywana do wyświetlenia wielu wymiarów na jednej osi. [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS ON COLUMNS, {CROSSJOIN( [Klienci G].[Województwo].MEMBERS, [Data Faktury].[Kwartal].MEMBERS)} ON ROWS WHERE ([Measures].[Zysk]) Do filtrowania bardziej szczegółowego, MDX udostępnia funkcję FILTER. Zwraca ona zbiór, który jest wynikiem filtrowania na podstawie określonego warunku. FILTER (zbiór, warunek_wyszukiwania) [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS ON COLUMNS, FILTER({[LokalizacjaKlientaH].[Miasto].MEMBERS}, ([Measures].[Zysk], [DataFakturyH].[All])>500) ON ROWS WHERE ([Measures].[Zysk]) 15

Do filtrowania bardziej szczegółowego, MDX udostępnia funkcję FILTER. Zwraca ona zbiór, który jest wynikiem filtrowania na podstawie określonego warunku. FILTER (zbiór, warunek_wyszukiwania) [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS ON COLUMNS, FILTER({[LokalizacjaKlientaH].[Miasto].MEMBERS}, ([Measures].[Zysk], [DataFakturyH].[All])>500) ON ROWS WHERE ([Measures].[Zysk], [DataFakturyH].[Rok].[2003]) Zysk których z produktów spada poniżej średniej dla województwa????? MEMBER [Measures].[ZyskProcentowy] AS ([Measures].[Wartosc]-[Measures].[WartoscZakupu]) / ([Measures].[WartoscZakupu]), FORMAT_STRING = '#.00%' NON EMPTY {[KategoriaTowaruG].[Nazwa Kategorii].MEMBERS} ON COLUMNS, FILTER({[LokalizacjaKlientaH].[Miasto].MEMBERS}, ([Measures].[ZyskProcentowy], [DataFakturyH].[All]) < ([Measures].[ZyskProcentowy], [DataFakturyH].[All], ANCESTOR([LokalizacjaKlientaH].CURRENTMEMBER, [LokalizacjaKlientaH].[Województwo]))) ON ROWS WHERE ([Measures].[ZyskProcentowy], [DataFakturyH].[All]) Filtr dla zysku we wszystkich latach większego niż 500 ale wyświetlono zysk z roku 2003 Jest sens stosowanie NON EMPTY wyeliminowano PABIANICE [KategoriaTowaruG].[Nazwa Kategorii].MEMBERS ON COLUMNS, NON EMPTY(FILTER({[LokalizacjaKlientaH].[Miasto].MEMBERS}, ([Measures].[Zysk], [DataFakturyH].[All])>500)) ON ROWS WHERE ([Measures].[Zysk], [DataFakturyH].[Rok].[2003]) Rozpatrzmy proste zapytanie o miary dla lokalizacji klientów (miasta): [Measures].MEMBERS ON COLUMNS, [LokalizacjaKlientaH].[Miasto].MEMBERS ON ROWS Filtr dla zysku we wszystkich latach większego niż 500 ale wyświetlono zysk z roku 2003 16

Pierwszym wyświetlonym miastem jest Bydgoszcz etc... Naturalna kolejność nie jest zbyt widoczna ponieważ nie znamy członu z poziomu rodzica. Jeśli bylibyśmy zainteresowani miastami wylistowanymi między Kutno a Czersk musielibyśmy napisać: [Measures].MEMBERS ON COLUMNS, [LokalizacjaKlientaH].[Miasto].[KUTNO]:[CZERSK] ON ROWS Sortowanie wyników ORDER(zbiór, wyrażenie [, ASC DESC BASC BDESC]) Brak prefiksu B wskazuje, że hierarchiczny porządek nie może zostać rozbity. [Measures].MEMBERS ON COLUMNS, ORDER([LokalizacjaKlientaH].[Miasto].[KUTNO]:[CZERSK], [LokalizacjaKlientaH].CURRENTMEMBER.NAME, ASC) ON ROWS Sortowanie wyników ORDER(zbiór, wyrażenie [, ASC DESC BASC BDESC]) Prefiks B wskazuje, że hierarchiczny porządek może zostać rozbity. [Measures].MEMBERS ON COLUMNS, ORDER([LokalizacjaKlientaH].[Miasto].[KUTNO]:[CZERSK], [LokalizacjaKlientaH].CURRENTMEMBER.NAME, BASC) ON ROWS Dość często bieżące sortowanie jest oparte o aktualną miarę. Zapytamy o informacje sprzedaży w miastach, uporządkowaną według efektywności sprzedaży: [Measures].MEMBERS ON COLUMNS, ORDER([LokalizacjaKlientaH].[Miasto].MEMBERS, [Measures].[Wartosc], DESC) ON ROWS W przykładzie tym sortowanie odbyło się po właściwości Name. Zwraca on nazwę poziomu, wymiaru, członu, lub hierarchii. Istnieje podobna właściwość UniqueName zwracająca odpowiednią unikalną nazwę. 17

Dość często bieżące sortowanie jest oparte o aktualną miarę. Zapytamy o informacje sprzedaży w miastach, uporządkowaną według efektywności sprzedaży: [Measures].MEMBERS ON COLUMNS, ORDER([LokalizacjaKlientaH].[Miasto].MEMBERS, [Measures].[Wartosc], BDESC) ON ROWS TOPCOUNT zwraca ze zbioru n najlepszych na podstawie podanego wyrażenia wyników. TOPCOUNT(zbiór, n, wyrażenie_numeryczne) Poprzednie wyrażenie możemy zatem przepisać: [Measures].MEMBERS ON COLUMNS, TOPCOUNT([LokalizacjaKlientaH].[Miasto].MEMBERS, 10, [Measures].[Wartosc]) ON ROWS Bez rozbicia wynikającego z hierarchii HEAD funkcja zwracająca pierwszych n członów z podanego zbioru. Podobnie TAIL zwraca n ostatnich członów z podanego zbioru. Ograniczmy zakres wyświetlanych miast do 10 najbardziej wydajnych: [Measures].MEMBERS ON COLUMNS, HEAD(ORDER([LokalizacjaKlientaH].[Miasto].MEMBERS, [Measures].[Wartosc], BDESC), 10) ON ROWS Zapytanie MDX, które wyświetla górne 10 miast, w oparciu o ilość transakcji sprzedaży, oraz jak dużo sprzedały łącznie pozostałe miasta. Takie wyrażenie pokaże także inne zastosowanie funkcji SUM, nawiązujące do nazwanych zbiorów i obliczanych członów: SET TopTens AS TOPCOUNT([LokalizacjaKlientaH].[Miasto].MEMBERS, 10, [Measures].[Ilosc]) MEMBER [LokalizacjaKlientaH].[Inne Miasta] AS ([LokalizacjaKlientaH].[All], Measures.CURRENTMEMBER) - SUM(TopTens, Measures.CURRENTMEMBER) [Measures].MEMBERS ON COLUMNS, {TopTens, [Inne Miasta]} ON ROWS Istnieje również TOPPERCENT, TOPSUM Oczywiście istnieje seria funkcji BOTTOM 18

Wyświetlanie listy miast, których ilość transakcji sprzedaży obejmuje 50% całości sprzedaży: [Measures].MEMBERS ON COLUMNS, TOPPERCENT({[Klienci G].[LokalizacjaKlientaH].[Miasto].MEMBERS}, 50, [Measures].[Ilosc]) ON ROWS rozkład ilości sprzedaży dla typów sklepów: [Nazwa Kategorii].MEMBERS ON COLUMNS, TOPPERCENT({[LokalizacjaKlientaH].[Miasto].MEMBERS}, 50, [Measures].[Ilosc]) ON ROWS WHERE [Measures].[Ilosc] Wyświetlanie listy 50% osób, których zarobki w roku 2004 były najwyższe Zastosowanie TOPSUM TOPPERCENT ([Osoby G].[Pracownik].[Pracownik].members, 50, ([Measures].[Brutto], [Data Zarobki].[Rok].[2004])) ON ROWS, {[Data Zarobki].[Rok].[2004]} ON COLUMNS FROM ZarobkiG MEMBER [Data Faktury].[Rok].[2002 + 2003] AS ([Measures].[Wartosc], [Data Faktury].[Rok].[2002]) + ([Measures].[Wartosc], [Data Faktury].[Rok].[2003]) {[Data Faktury].[Rok].[2002], [Data Faktury].[Rok].[2003], [Data Faktury].[Rok].[2002 + 2003]} ON COLUMNS, TOPSUM([Towar G].[Nazwa Towaru].[Nazwa Towaru].members, 10000, [Data Faktury].[Rok].[2002 + 2003]) ON ROWS FROM BiznesG WHERE [Measures].[Wartosc] 19

Funkcje statystyczne AVG, MEDIAN, MAX, MIN, VAR oraz STDDEV. Format jest jednakowy dla wszystkich: FUNKCJA(zbiór, wyrażenie_numeryczne) MEMBER [DataFakturyH].[SredniaSprzedaz] AS AVG(DESCENDANTS([DataFakturyH].[Rok], [DataFakturyH].[Miesiac])) MEMBER [DataFakturyH].[SredniaIlosc] AS COUNT(DESCENDANTS([DataFakturyH].[Rok], [DataFakturyH].[Miesiac]),EXCLUDEEMPTY) {[DataFakturyH].[Rok],[SredniaSprzedaz],[SredniaIlosc]} ON COLUMNS, [KategoriaTowaruG].[Nazwa Kategorii] ON ROWS WHERE [Measures].[Ilosc] Jeśli zapytanie ma zwracać wzrost procentowy MEMBER Measures.[WzrostZysku] AS ([Measures].[Zysk]) / ([Measures].[Zysk], [DataFakturyH].PREVMEMBER), FORMAT_STRING = '#.00%' {[Measures].[Zysk], [WzrostZysku] } ON COLUMNS, DESCENDANTS([DataFakturyH].[Rok], [DataFakturyH].[Miesiac]) ON ROWS Problemem - pierwszy okres czasu powoduje dzielenie przez zero... Funkcje te, zwane user-defined functions (UDF) mogą przyjmować argumenty i zwracać wartości w składni MDX. UDF mogą być tworzone w dowolnym języku wspomagającym COM (Common Object Model), Na dodatek, MDX obsługuje wiele funkcji z biblioteki Microsoft Visual Basic for Applications (VBA) Expression Services. Biblioteka ta jest dołączona do OLAP Services i jest automatycznie rejestrowana. Możemy zapytać o miary dla miasta, gdzie wartość zawiera łańcuch KA : Measures.MEMBERS ON COLUMNS, FILTER({[LokalizacjaKlientaH].[Miasto].MEMBERS}, VBA!INSTR(1, [Miasto].CURRENTMEMBER.Name, "KA")>0) ON ROWS Ten problem może zostać w omnięty przez użycie IIF i sprawdzenie istnienia pustej komórki: MEMBER Measures.[WzrostZysku] AS IIF( ISEMPTY([DataFakturyH].PREVMEMBER), 1, ([Measures].[Zysk]) / ([Measures].[Zysk], [DataFakturyH].PREVMEMBER)), FORMAT_STRING = '#.00%' {[Measures].[Zysk], [WzrostZysku] } ON COLUMNS, DESCENDANTS([DataFakturyH].[Rok], [DataFakturyH].[Miesiac]) ON ROWS Prefiks VBA nie jest potrzebny. Wskazuje jedynie pełnokwalifikowane pochodzenie funkcji. 20

Taka sama funkcjonalność może być osiągnięta przy użyciu funkcji COALESCEEMPTY, która przypisuje pustej wartości komórki liczbę lub łańcuch i go zwraca. W tym przypadku, pusta komórka z poprzedniego członu czasu, byłaby zastąpiona wartością bieżącym członem czasu: MEMBER Measures.[WzrostZysku] AS ([Measures].[Zysk]) / COALESCEEMPTY(([Measures].[Zysk], [DataFakturyH].PREVMEMBER),[Measures].[Zysk]), FORMAT_STRING = '#.00%' {[Measures].[Zysk], [WzrostZysku] } ON COLUMNS, DESCENDANTS([DataFakturyH].[Rok], [DataFakturyH].[Miesiac]) ON ROWS Średnia bieżąca - CENTRALNA MEMBER Measures.SredniaBiezaca AS AVG({[Miesiac].CURRENTMEMBER, [Miesiac].PREVMEMBER, [Miesiac].NEXTMEMBER},[Measures].[Wartosc]), FORMAT_STRING = '#.00 zł' [KategoriaProduktuH].[Nazwa Kategorii].[THAN] ON COLUMNS, [DataFakturyH].[Miesiac].MEMBERS ON ROWS WHERE Measures.SredniaBiezaca Średnia dla miast dla wybranych województw za lata 2001 do 2004 MEMBER [Measures].[lubelskie AVG] AS AVG({[Klienci G].[lubelskie].CHILDREN},[Measures].[Wartosc]) MEMBER [Measures].[łódzkie AVG] AS AVG({[Klienci G].[łódzkie].CHILDREN},[Measures].[Wartosc]) MEMBER [Measures].[pomorskie AVG] AS AVG({[Klienci G].[pomorskie].CHILDREN},[Measures].[Wartosc]) {([Measures].[lubelskie AVG]), ([Measures].[łódzkie AVG]), ([Measures].[pomorskie AVG])} ON COLUMNS, {([Data Faktury].[2001]:[2003])} ON ROWS FROM BiznesG Średnia bieżąca - WSTECZNA MEMBER Measures.SredniaBiezaca AS AVG({[Miesiac].CURRENTMEMBER, [Miesiac].PREVMEMBER, [Miesiac].PREVMEMBER.PREVMEMBER},[Measures].[Wartosc]), FORMAT_STRING = '#.00 zł' [KategoriaProduktuH].[Nazwa Kategorii].[THAN] ON COLUMNS, [DataFakturyH].[Miesiac].MEMBERS ON ROWS WHERE Measures.SredniaBiezaca 21