Författararkiv: Paul Fransson

Om Paul Fransson

Jag arbetar med Business Intelligence och har jobbat både i Sverige och utlandet med IT-projekt inom telekom, olja & gas, detaljhandel, transport, logistik och kemisk processindustri. Min tekniska erfarenhet är främst på Microsoft-plattformen där jag sysslat med både OLAP-kuber, databaser, rapportdesign och gränssnitt. Jag har också tidigare axlat både arkitekt och projektledarroller.Har en fil. Kand. i Informatik från Lund och gillar SCRUM. Bor med fru och dotter i Knivsta. Privat gillar jag att tillbringa tid med familjen, träna, dyka, resa, läsa historieböcker och deckare, programmera och besegra mina fiender på PS3an.

Qlikview set analysis vs MDX

I come from a Microsoft background but have made a couple of forays into the world of Qlikview. I noticed that just like MDX is used to enhance reports and cubes when working in the Microsoft BI environment, Qlikview provides set analysis expressions as a tool for sorting and querying subsets of data within a Qlikview document. The set analysis syntax is quite different from MDX so I thought a little comparison using the AdventureWorks data structure might be worthwhile.

In MDX a query scoped member or calculated measure totaling the sales amount for male customers would look like this:

sum([DimCustomer].[Gender].&[M],[Measures].[Sales Amount])

Translated into a Qlikview set analysis expression we end up with the following:

=sum({$<Customer.Gender = {'M'}>} OrderDetails.[Sales Amount])

An MDX scoped member or calculated measure totaling the sales for all male customers in Germany and France would be defined using a crossjoin (note the * operator):

sum({[DimSalesTerritory].[SalesTerritoryCountry].&[France],
[DimSalesTerritory].[SalesTerritoryCountry].&[Germany]} *
[DimCustomer].[Gender].&[M], [Measures].[Sales Amount])

Using Qlikview set analysis the above would look like this:

=sum({$ < Customer.Gender = {'M'},
SalesTerritory.SalesTerritoryCountry =
{'Germany','France'}>} OrderDetails.SalesAmount)

A total excluding France and Germany would look like this in MDX:

sum(except([DimSalesTerritory].[SalesTerritoryCountry].children,
{[DimSalesTerritory].[SalesTerritoryCountry].&[France],
[DimSalesTerritory].[SalesTerritoryCountry].&[Germany]},
[Measures].[Sales Amount])

using Qlikview set analysis we get this:

=sum({$ <SalesTerritory.SalesTerritoryCountry =
-{'Germany','France'} >} } OrderDetails.SalesAmount)

An mdx query calculating the two years with the highest sales from the AdventureWorks cube would look like this:

SELECT
sum(TOPCOUNT([DimDate].[CalendarYear].[CalendarYear], 2,
[Measures].[Sales Amount]),[Measures].[Sales Amount])
ON 0
from [AWModel]

In Qlikview you would create a chart displaying Sales Amount by Calendar Year and then select Properties–>Dimension Limits and check the ”Select which values are displayed” check box so you can set the chart to display only the two largest values.

Or you can create a list box for Calendar Year next to your chart and type the following set analysis expression into the search box:

=rank(sum(OrderDetails.SalesAmount))<=2

and press enter. The two years with the largest sales are now selected by the expression you just created.

I think it is quite safe to assume that one of the reasons it is quite time consuming to replace an OLAP-cube with a Qlikview document or vice versa, are the syntactical differences.

Notes: I have used the sum function on the MDX-statements for the sake of clarity. It is actually not needed since the property of the measure itself is set to sum in the SSAS cube definition. If we substitute the ”$” for ’1′, our selections will be independent of any selections in the Qlikview document.


En jämförelse mellan Qlikview set analys och MDX-frågor

Undertecknad härstammar från Microsoftbakgrund men har gjort några kortare inkursioner in i Qlikviews värld. En sak jag upptäckt är att precis som MDX används för ställa frågor och sortera data i kuber, så används set analys uttryck i Qlikview i liknande syfte. Syntaxen skiljer sig dock en del varför jag tycker att en jämförelse är på sin plats.

I MDX så ser en frågesammanhangsberoende medlem eller ett kalkylerat mått som räknar ut totalen för alla manliga kunder ut på följande vis:

sum([DimCustomer].[Gender].&[M],[Measures].[Sales Amount])

Översatt till ett set analys-uttryck så får vi följande:

=sum({$<Customer.Gender = {'M'}>} OrderDetails.[Sales Amount])

I MDX så skulle en frågesammanhangsberoende medlem eller ett kalkylerat mått som räknar ut totalen för alla manliga kunder i Tyskland och Frankrike använda sig av en crossjoin och se ut på följande vis:

sum({[DimSalesTerritory].[SalesTerritoryCountry].&[France],
[DimSalesTerritory].[SalesTerritoryCountry].&[Germany]}
* [DimCustomer].[Gender].&[M],
[Measures].[Sales Amount])

Ovanstående uttryck omvandlat till ett Qlikview set analys-uttryck ser ut så här:

=sum({$ < Customer.Gender = {'M'},
SalesTerritory.SalesTerritoryCountry
= {'Germany','France'}>} OrderDetails.SalesAmount)

En total som utesluter Tyskland och Frankrike ser ut så här om man använder sig av MDX:

sum(except([DimSalesTerritory].[SalesTerritoryCountry].children,

{[DimSalesTerritory].[SalesTerritoryCountry].&[France],
[DimSalesTerritory].[SalesTerritoryCountry].&[Germany]}, [Measures].[Sales Amount])

Ovanstående uttryck omvandlat till ett Qlikview set analys-uttryck ser ut så här:

=sum({$ <SalesTerritory.SalesTerritoryCountry = 
-{'Germany','France'} >} }
OrderDetails.SalesAmount)

En MDX-fråga som räknar ut de två åren med störst försäljning från AdventureWorks-kuben skulle se ut så här:

SELECT
sum(TOPCOUNT([DimDate].[CalendarYear].[CalendarYear], 2,
[Measures].[Sales Amount]),[Measures].[Sales Amount])
ON 0
from [AWModel]

I Qlikview skulle man lösa ovanstående med att skapa ett diagram som visar Sales Amount över Calender Year–>Dimension Limits och välj ”Select which values are displayed” check box så du kan ställa diagrammet till att visa endast de två största värdena.

En annan möjlig lösning är att skapa en list box och skriva följande set analys-uttryck i sökrutan:

=rank(sum(OrderDetails.SalesAmount))<=2

och trycka enter.

P.g.a. skillnaderna i syntax så är det ett rimligt antagande att det krävs en del jobb att ersätta en SSAS-kub med ett Qlikview-dokument eller vice versa.

Noteringar: Jag har använt sum-funktionen på MDX-uttrycken för att öka tydligheten. Uttrycket behövs egentligen inte då måttet är satt till att vara en sum i själva kubdefinitionen. Det är också värt att notera att vi kan byta ’$’ mot ’1’ i set analys-uttrycken om vi vill göra dem oberoende av gjorda val i Qlikview-dokumentet.


Räkna ut ålder från personnummersträng med en SSIS-expression

Att veta en kunds ålder när en transaktion inträffar är ett återkommande krav i många BI-projekt. Detta kan åstadkommas genom att extrahera födelsedatum från personnummret och sedan subtrahera transaktionsdatumet med detta datum när man kör sin ETL i SSIS.

Detta görs lämpligen i SSIS med hjälp av data flow-komponenten Derived Column. Förutsatt att du har lagt in en OLE DB Datasource eller annan datakälla så gör du bara följande:
1. Lägg in en Derived Column task i ditt data flow.
2. Koppla dataflödet från din datakälla till din Derived Column task.
3. Lägg in följande expression i Expressionfältet:

(DT_I4)(ISNULL(Personnummer) ? NULL(DT_I4) : FLOOR(DATEDIFF(”dd”,(DT_DBTIMESTAMP)(SUBSTRING(Personnummer,1,4) + ”-” + SUBSTRING(Personnummer,5,2) + ”-” + SUBSTRING(Personnummer,7,2)),Samtalsdatum) / 365.25))
4. Se till att en ny kolumn skapas genom att ”Derived Column” är satt till ”Add as new column”.
5. Döp fältet till ”Alder” eller liknande.

Notera att ovanstående förutsätter ett fyrsiffrigt år i personummret. Om du bara har två siffor att lira med så är det bara att ändra första substring-uttrycket till
”19″ + SUBSTRING(Personnummer,1,4)

Du har nu skapat en ny kolumn innehållande ett heltal för ålder för varje rad i ditt dataflöde.


Calculated measures och query scoped members

Calculated Measures är en kraftfull funktion i OLAP-kuber som används för att utöka kubfunktionalitet genom att kombinera vanliga measures och dimensioner med varandra. En calculated measure definieras i själva kuben medans en query scoped member å andra sidan definieras i en query. Ibland kan en query scoped member vara enda utvägen beroende på användarrättigheter eller p.g.a. prestandaskäl. Läs mer


Använda MDX för rullande totaler relativa till dags datum

Om det är en sak jag lärt mig under min IT-karriär så är det att chefer och räknenissar älskar löpande totaler och snittvärden.

Behoven kan variera något beroende på verksamhetstyp, en revisor eller financial controller är oftast intresserad av löpande totaler som visar endast stängda böcker, vilket i praktiken betyder att man jämför månaden innan nuvarande med föregående. Inom detaljhandeln stänger man sina försäljningsresultat varje dag och är därför intresserad av att jämföra gårdagens resultat med föregående dagar. Läs mer


Using MDX for rolling totals relative to current date.

If there is one thing I have learned during my career, it’s that managers and accountants love rolling totals and averages.

The needs might differ slightly depending on the type of business, an accountant or a financial controller is probably interested in a rolling total showing closed results only which in many cases means comparing previous month and months preceding it. A lot of retail operations close sales books every day, and someone monitoring sales is therefore interested in comparing yesterday’s results with the days preceding.

To retrieve data sets containing data for previous periods relative to today, we need to obtain the current date and this is surprisingly complicated if you are using MDX. One way to do it is by invoking VBA functions and parsing strings, but a better way to retrieve the current date is to simply create a named set that stores current date as suggested by Mosha Pashumansky.  We can then create a C# executable or SSIS script task that updates the named set to today’s date. To create a simple executable using AMO:

1. Open Visual Studio 2010 and create a console project.

2. Add references to System.Configuration and Microsoft.AnalysisServices (found in C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies for MS SQL 2008 R2) to your project.

3. Add the following namespaces to your Program.cs file:

using System.Globalization;

using Microsoft.AnalysisServices;

using System.Globalization;

4. Open the cube in  your SSAS solution, click the calculations tab, then click the  Script View tab and copy the entire MDX script.

5. Add a text file to  your console project and paste the MDX script into this file.

6.  Use the following code snippet to create the named set:

string connectionString = ConfigurationManager.ConnectionStrings["adw"].ConnectionString;

Server asServer = new Server();

asServer.Connect(connectionString);

Database adw = asServer.Databases.GetByName(ConfigurationManager.AppSettings["db"]); // this throws exception if the database is not found

Cube cb = adw.Cubes[0];

//CultureInfo helps us override local date format settings:

CultureInfo ci = new CultureInfo(”en-US”, false);

System.Threading. Thread.CurrentThread.CurrentCulture = ci;

DateTime time = DateTime.Now; // Use current time
string format = ”MMMM d, yyyy”;

Console.WriteLine(time.ToString(format));

//Retrieve cube mdx script:
MdxScript first = cb.MdxScripts[0];

//Read script minus [Today]
string text = System.IO. File.ReadAllText(@”C:\MDXScript.txt”);

//text = text + ”Create Set CurrentCube.[Today] As {[Date].[Date].[June 1, 2002]};”;
//Append [Today]:
text = text + ”Create Set CurrentCube.[Today] As {[Date].[Date].[" + time.ToString(format) + "]}”;

//Replace cube mdx script with the parsed script.
first.Commands[0].Text = text;

first.Update();

cb.Update();
adw.Update();

cb.Process();

Console.WriteLine(”Processing started”);

adw.Process();

asServer.Dispose();

Console.WriteLine(”processing finished”);

Console.ReadLine();

The above code could also be run inside an SSIS script component.The problem with Adventure Works is that the time dimension data is a couple of years old, so for demo purposes you want to use a hard coded date instead of the current date.

We can now use the [Today] named set to retrieve rolling averages and totals. The query below let’s us look at the reseller sales” for the last 100 days ending with yesterday. Note the use of the Lag function which retrieves yesterday’s date:

select [Measures].[Reseller Sales Amount] on 0,
LastPeriods(100,[Today].Item(0).Lag(1)) on 1
from [Adventure Works]

The current date named set can also be used together with the  ParallellPeriod function, but that’s another post.


Calculated measures and query scoped members in SSRS

Calculated Measures are a powerful feature in OLAP cubes. They are used to extend cube functionality trough combining actual measures and dimensions with each other. A calculated measure is defined in the cube whereas a query scoped member is defined in an MDX-query.  Sometimes a query scoped member might be the only option due to user rights or performance reasons.

Let’s say we want to define a query-scoped member that allows us to subtract the previous period’s sales from the current period to find out whether sales increased or decreased. First open SQL Server Management Studio then connect to  SSAS,  open the Adventure Works database and create the following query:

with member [Measures].[Sales Growth] as
([Measures].[Reseller Sales Amount]) -
(ParallelPeriod([Date].[Calendar].[Month],1,[Date].[Calendar].CurrentMember),[Measures].[Reseller Sales Amount])
select {[Measures].[Reseller Sales Amount],[Measures].[Sales Growth]} on columns,
non empty [Date].[Calendar].[Month].Members on rows
from [Adventure Works]

To define Sales Growth we make use of the ParallelPeriod function and the CurrentMember property. Let’s dissect the ParallelPeriod function call:

The first parameter is the Month level of the [Date].[Calendar] hierarchy. It defines the period:

(ParallelPeriod([Date].[Calendar].[Month],1,[Date].[Calendar].CurrentMember),[Measures].[Reseller Sales Amount])

The second parameter defines the period lag. By passing 1 as an argument we get the previous month:

(ParallelPeriod([Date].[Calendar].[Month],1,[Date].[Calendar].CurrentMember),[Measures].[Reseller Sales Amount])

The third argument defines the hierarchy which we will use to slice the value. The CurrentMember property tells the execution engine to look for the current member of the other axis:

(ParallelPeriod([Date].[Calendar].[Month],1,[Date].[Calendar].CurrentMember),[Measures].[Reseller Sales Amount])

Note that we can use both the [Date]. [Calendar].[Month] and [Date]. [Calendar].[Date] levels of the [Date].[Calendar] hierarchy to slice the data along the rows-axis. I.e.: [Date].[Calendar].[Date].Members  or [Date].[Calendar].[Month].Members

The above was all done in SQL Server Management Studio, to accomplish the same in an SSRS report:

  1. Fire up BIDS, and start a Report Wizard project that we connect to the SSAS Adventure Works database. Click next.
  2. Open the query designer, drag the [Date].[Calendar].[Month] dimension and [Measures].[Reseller Sales Amount]) to the results pane (the big one).
  3. In the lower left pane of the query designer, right click and select “Add New Calculated Member”.
  4. In the Calculated Member Builder window paste the following part of the query we designed in Management Studio:([Measures].[Reseller Sales Amount]) -
    (ParallelPeriod([Date].[Calendar].[Month],1,[Date].[Calendar].CurrentMember),[Measures].[Reseller Sales Amount])
  5. Type [Sales Growth] in the uppermost textbox.
  6. Click ok and then simply drag the calculated measure from the lower left pane to the center pane. You should now see both  [Measures].[Reseller Sales Amount] and[Measures].[Sales Growth] data.

You can now go on and create an SSRS report using the query scoped member.


BI Top 10 förutsägelser

Vilka förutsägelser om BI från förra året har slagit in?

I en artikel skriven den 5 mars på sajten Information Management så gjordes följande förutsägelser för 2010:

1. Företagsomfattande dataintegration. Många företag och myndigheter förutspåddes lägga pengar på att samla data från organisationens olika delar för att förbättra riskanalys och kundhantering.

Utfall: Enligt  IDC växte denna marknad globalt med 10.9% under första halvan av år 2010.Siffrorna för andra halvan finns ännu ej tillgängliga men det finns ingen anledning att tro att marknaden krympt
under andra halvan av 2010. Att stora aktörer ser framåt illustreras också av Dells uppköp av Boomi, ett företag som erbjuder integration i molnet.

2. Semantisk teknologi. Ökad använding av semantisk teknologi, d.v.s. att söka och organisera ostrukturerad data. Semantisk teknologi låter oss också kombinera ostrukturerad och strukturerad data.

Utfall: Enligt Information Management så har Facebook beslutat att ytterligare utveckla sitt erbjudande på detta område. Detta kommer att driva på utvecklingen. Räkna med fortsatt utveckling under resten av 2011. Även Microsofts integration av exempelvis RSS-flöden i SSRS är en del av denna trend.

​3. Ökad användning av avancerad analys inklusive automatiskt beslutsfattande.

Utfall: Inom t.ex. finansmarknaden är detta redan vanligt. Andra områden som t.ex. detaljhandel och tillverkning släpar dock efter och här finns det mycket att göra. Särskilt inom data mining är ett eftersatt område, enligt analytikerfirman Ventana research så använder sig bara ett av åtta företag av data mining men 80% av de totalt 2600 tillfrågade ansåg samtidigt att det var viktigt. Jag vet av egen erfarenhet att SQL Servers prognosfunktioner är sorgligt underutnyttjade.

4.  Höjning av datakvalitet. Många företag och myndigheter förutspåddes lägga pengar på att höja datakvaliten.

Utfall: Jag har inte hittat några siffror eller andra indikationer på hur det har gått. Däremot menar Gartner att Master Data Management, som är ett relaterat område, kommer bli hett under 2011.

5. Minskat avstånd mellan produktionsmiljö och analysdata. Man förutspådde en snabbare analyscykel där man går snabbare från analys till beslut och där analys av affärsdata och operativdata konvergerar.

Utfall: Detta är lika mycket en organisatorisk som en teknisk fråga, att verktygen blir bättre betyder inte automatiskt att beslutsfattande delegeras till de som bäst förstår datan därför är utfallet av denna förutsägelse svår att mäta. Jag tror att företag som vågar anpassa sin organisation efter den nya tekniken har mycket att hämta här.

​6. En ny generation driver fram nya prioriteringar inom Data Warehousing och BI. BI applikationer skall inte vara separata utan integreras med andra applikationer. Nya datakällor måste snabbt kunna länkas.​

Utfall: In-memory BI-verktyg som Qliktechs Qlikview och Microsofts PowerPivot låter oss snabbt länka data. Vad det gäller integration med andra applikationer så jobbar Qliktech mycket med att
integrera sina lösningar med smartphones, Microsoft PowerPivot å andra sidan integrerar utmärkt med räknenissens främsta vän, Excel, samt även med Sharepoint. Dessa nya verktygs akilleshäl är dock datakvalitet. Qlikview tillåter visserligen att man skriver scripts för att tvätta datan men det är komplicerat om man jämför med specialiserade ETL-verktyg som SSIS och Informatica.

​7. Nya möjligheter och ökade effekter drivna av CEP (Complex Event Processing). Analys av strömmande data nära realtid blir vanligare. Traditionella BI-system analyserar data lagrat i data warehouse medans CEP handlar om att analysera strömmande data från exempelvis PLCs, mobiltelefoni, finanssystem eller sociala medier.

Utfall: CEP är fortfarande hett, Twitter och Digg öppnade upp Streaming APIs. Microsoft släppte StreamInsight som är en CEP produkt som ingår i SQL Server 2008 R2 paketet. Skall bli spännande att följa detta område och se om användningen kommer att öka. På finansmarknaden används CEP för s.k algorithmic trading och även om vi förra året fick se en mystisk krasch den 6 maj där skenande CEP-system orsakade problemen så ökar användningen.

8. Ökad analys av ostrukturerad och semi-strukturerad data. Många organisationer har system för att versionskontroll och dokumenthantering men saknar verktyg för att integrera detta i beslutsprocessen. M.h.a. verktyg som t.ex.  MapReduce så kan man analysera denna typ av ostrukturerad data.

Utfall: Tack vare molnleverantörer som Gogrid och EC2 så blir det allt billigare att analysera stora datamängder m.h.a. t.ex. MapReduce. Molnleverantören Platform Computing noterar en fördubbling i efterfrågan på bl.a. Mapreduce lösningar och har skrivit avtal med flera Fortune 500 företag.

9. BI kan hjälpa till att vidga insikten vid beslutsfattande genom att inkorporera data från social computing.​

Utfall: Detta är en växande marknad och det märks genom att ett antal företag som t.ex. Gnip och Superfeedr som sysslar med att extrahera och förädla data från bl.a. Twitter, Gowalla och Facebook har poppat upp. Flera av Microsofts produkter, t.ex. SSRS och PowerPivot, låter oss ställa länka till Atom-feeds som är ett vanligt format för data från sociala medier.

10. Ökat intresse för molnlösningar för BI. Enligt Information Management så ökar komplexiteten och driftskonstnaderna för BI-lösningar vilket i sin tur driver ett ökat intresse för BI i molnet.​

Utfall: Vi ser redan ett antal aktörer som erbjuder färdiga SaaS lösningar, det är dock en lång väg att gå innan företag accepterar lagring av känslig data i molnet. Även regelverk och lagar kan motverka att BI flyttar till molnet. Existerande BI-lösningar hanterar inte datamodeller särskilt väl och detta gör dem oattraktiva för företag med komplex verksamhet. Enligt Martin Willcox på Teradata så ser detta företag, som erbjuder lösningar till främst större företag, i dagsläget ingen efterfrågan på molnlösningar från sina kunder. Jag har själv inte sett något som får mig att tro att Willcox har fel.


Följ

Få meddelanden om nya inlägg via e-post.