<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ixto-Blog &#187; Markus Schechner</title>
	<atom:link href="http://www.ixto.de/blog/author/mschechner/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ixto.de/blog</link>
	<description>Business Intelligence, Database Consulting, Software Development</description>
	<lastBuildDate>Mon, 26 Sep 2011 09:23:18 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Analysis Services und das nachtr&#228;gliche Erlauben von NULL-Werten in den Quelldaten &#8211; oder: Wie werd ich blo&#223; die 0en los?</title>
		<link>http://www.ixto.de/blog/sql-server-2008/analysis-services-und-das-nachtrgliche-erlauben-von-null-werten-in-den-quelldaten-oder-wie-werd-ich-blo-die-0en-los/</link>
		<comments>http://www.ixto.de/blog/sql-server-2008/analysis-services-und-das-nachtrgliche-erlauben-von-null-werten-in-den-quelldaten-oder-wie-werd-ich-blo-die-0en-los/#comments</comments>
		<pubDate>Wed, 30 Jun 2010 18:22:55 +0000</pubDate>
		<dc:creator>Markus Schechner</dc:creator>
				<category><![CDATA[Analysis Services 2008]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[NOT NULL]]></category>
		<category><![CDATA[NullProcessing]]></category>
		<category><![CDATA[SSAS]]></category>
		<category><![CDATA[view]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=106</guid>
		<description><![CDATA[Ich hatte vor kurzem eine interessante Begegnung mit einem SSAS Cube (2008), über die ich an dieser Stelle gerne berichten möchte.
Dabei ging es um einen Cube, bei dem für ein bestimmtes Measure die Leerzeilenunterdrückung nicht so richtig funktionierte. Wenn man dieses Measure, das eigentlich eher selten gefüllt war, abfragte, dann sah das in etwa so [...]]]></description>
			<content:encoded><![CDATA[<p>Ich hatte vor kurzem eine interessante Begegnung mit einem SSAS Cube (2008), über die ich an dieser Stelle gerne berichten möchte.</p>
<p>Dabei ging es um einen Cube, bei dem für ein bestimmtes Measure die Leerzeilenunterdrückung nicht so richtig funktionierte. Wenn man dieses Measure, das eigentlich eher selten gefüllt war, abfragte, dann sah das in etwa so aus:<br />
<a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0021.jpg"><img style="display: inline; border-width: 0px;" title="clip_image002[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0021_thumb.jpg" border="0" alt="clip_image002[1]" width="244" height="115" /></a></p>
<p><span id="more-106"></span></p>
<p>Wie in diesem aus der Adventure Works stammenden Beispiel (wir sehen hier den Reseller Sales Discount Amount nach Reseller Telefonnummer) wurden die leeren Zellen mit einer 0 angezeigt, was ja bekanntlich nicht leer ist und somit auch nicht unterdrückt werden kann. Bei kurzem Blick in die Quelle fand ich in etwa folgendes Bild:</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0041.jpg"><img style="display: inline; border-width: 0px;" title="clip_image004[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0041_thumb.jpg" border="0" alt="clip_image004[1]" width="244" height="113" /></a></p>
<p>War also alles korrekt, was die Analysis Services so angezeigt haben. Der verwunderliche Teil der Geschichte beginnt aber auch erst jetzt.</p>
<p>Da es für Measures, bei denen mich die 0en gar nicht interessieren, nur bedingt Sinn macht, diese in der Datenbank abzulegen, habe ich also die Definition der Tabelle so geändert, dass die betroffene Spalte ab sofort NULL-Werte erlaubt. Danach wurden dann noch mit einem kleinen Statement wie unten die 0en eliminiert.</p>
<div>
<div><span style="font-family: Courier New; color: #000000; font-size: x-small;"> </span></div>
<div><span style="font-family: Courier New; color: #000000; font-size: x-small;"><span style="font-family: Courier New; color: #0000ff; font-size: x-small;">UPDATE</span><span style="font-family: Courier New; color: #000000; font-size: x-small;"> dbo</span><span style="font-family: Courier New; color: #808080; font-size: x-small;">.</span><span style="font-family: Courier New; color: #000000; font-size: x-small;">FactResellerSales</span> </span></div>
<p><span style="font-family: Courier New; color: #000000; font-size: x-small;"><span style="font-family: Courier New; color: #0000ff; font-size: x-small;">SET</span><span style="font-family: Courier New; color: #000000; font-size: x-small;"> DiscountAmount </span><span style="font-family: Courier New; color: #808080; font-size: x-small;">=</span><span style="font-family: Courier New; color: #000000; font-size: x-small;"> </span><span style="font-family: Courier New; color: #808080; font-size: x-small;">NULL</span> </p>
<p><span style="font-family: Courier New; color: #0000ff; font-size: x-small;">WHERE</span><span style="font-family: Courier New; color: #000000; font-size: x-small;"> DiscountAmount </span><span style="font-family: Courier New; color: #808080; font-size: x-small;">=</span><span style="font-family: Courier New; color: #000000; font-size: x-small;"> 0</span> </p>
<p>Wie fast zu erwarten ist, reicht das aber noch nicht aus, denn bis die Zahlen dann wirklich im Cube landen, haben wir ja noch ein paar Abstraktionsebenen vor uns. In diesem Fall war die nächste zu überwindende Hürde die View, die der Cube für den Datenzugriff benutzt:</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0061.jpg"><img style="display: inline; border-width: 0px;" title="clip_image006[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0061_thumb.jpg" border="0" alt="clip_image006[1]" width="182" height="244" /></a></p>
<p>Dort war die Spalte nämlich weiterhin als NOT NULL definiert (im Bild ganz unten). Also erst mal rasch die Metadaten der View aktualisiert:</p>
<div><span style="font-family: Courier New; color: #800000; font-size: x-small;"><span style="font-family: Courier New; color: #000000; font-size: x-small;"> </span></span></div>
<div><span style="font-family: Courier New; color: #800000; font-size: x-small;"><span style="font-family: Courier New; color: #000000; font-size: x-small;"><span style="font-family: Courier New; color: #800000; font-size: x-small;">SP_REFRESHVIEW</span><span style="font-family: Courier New; color: #000000; font-size: x-small;"> </span><span style="font-family: Courier New; color: #ff0000; font-size: x-small;">N’dbo.v_FactResellerSales’</span><span style="font-family: Courier New; color: #808080; font-size: x-small;">;</span> </span></span></div>
<p><span style="font-family: Courier New; color: #800000; font-size: x-small;"><span style="font-family: Courier New; color: #000000; font-size: x-small;">Prompt stimmt die View mit der Realität überein. Aber selbstverständlich reicht auch das noch nicht, damit die 0en aus meinem Cube verschwinden. Es gibt da ja auch noch die Data Source View in den Analysis Services, die Metadaten speichert und die ich deswegen vorsorglich aktualisierte. Das Visual Studio meldete mir aber leider nach dem Klick auf den Refresh-Knopf, dass keine Änderungen gefunden wurden. Und wenn man sich dann die Eigenschaften der Spalte in der DSV anschaut: </p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0081.jpg"><img style="display: inline; border-width: 0px;" title="clip_image008[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0081_thumb.jpg" border="0" alt="clip_image008[1]" width="244" height="236" /></a></p>
<p>Dann gibt es eine Eigenschaft AllowNull, die leider immer noch auf False stand. Und<br />
natürlich sind die 0en nach erneuter Aufbereitung auch immer noch im Cube.</p>
<p>Da ich bei meiner View als Datenquelle bleiben wollte habe ich also kurzfristig „Tabelle ersetzen durch neue benannte Abfrage“ gewählt und danach dann wieder die ursprüngliche View über „Tabelle ersetzen durch andere Tabelle“ übernommen. Und endlich: AllowNull steht auf true. Das Ganze also schnell auf dem Server bereitgestellt, aufbereitet und … NICHTS! Immer noch grinsen mich die 0en förmlich an.</p>
<p>Hm, ist vielleicht beim Measure selbst noch was falsch eingestellt?</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0101.jpg"><img style="display: inline; border-width: 0px;" title="clip_image010[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0101_thumb.jpg" border="0" alt="clip_image010[1]" width="244" height="215" /></a></p>
<p>Eigentlich sieht alles gut aus. NullProcessing steht auf Automatic, was der Default ist. Ich persönlich musste das zwar bisher auch noch nie ändern, aber irgendwann ist ja immer das erste Mal:</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0121.jpg"><img style="display: inline; border-width: 0px;" title="clip_image012[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0121_thumb.jpg" border="0" alt="clip_image012[1]" width="244" height="216" /></a></p>
<p>Nach dem Ändern des NullProcessing auf Preserve verwunderte dann beim Bereitstellen, dass die automatische Aufbereitung keinen Anlass sah, die betroffene Measure Group neu mit Daten zu befüllen. Wen wundert’s dann noch, dass die 0en auch immer noch da waren.</p>
<p>Die nun folgende manuelle Aufbereitung war wohl die leichteste Übung, und endlich:</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0141.jpg"><img style="display: inline; border-width: 0px;" title="clip_image014[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0141_thumb.jpg" border="0" alt="clip_image014[1]" width="208" height="106" /></a></p>
<p>Ich bin die 0en los!</p>
<p></span></span></span></p>
<div><span style="font-family: Courier New; color: #000000; font-size: x-small;"><span style="font-family: Courier New; color: #800000; font-size: x-small;"><span style="font-family: Courier New; color: #000000; font-size: x-small;"> </span></span></span></div>
<div><span style="font-family: Courier New; color: #000000; font-size: x-small;"><span style="font-family: Courier New; color: #800000; font-size: x-small;"><span style="font-family: Courier New; color: #000000; font-size: x-small;"> </span></span></span></div>
<p><span style="font-family: Courier New; color: #000000; font-size: x-small;"><span style="font-family: Courier New; color: #800000; font-size: x-small;"><span style="font-family: Courier New; color: #000000; font-size: x-small;"> </p>
<p></span></span> </p>
<p></span></div>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2008/analysis-services-und-das-nachtrgliche-erlauben-von-null-werten-in-den-quelldaten-oder-wie-werd-ich-blo-die-0en-los/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Range-Lookups mit den Integration Services – Teil III</title>
		<link>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-iii/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-iii/#comments</comments>
		<pubDate>Thu, 26 Nov 2009 13:41:58 +0000</pubDate>
		<dc:creator>Markus Schechner</dc:creator>
				<category><![CDATA[Integration Services 2005]]></category>
		<category><![CDATA[Integration Services 2008]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[Binary Search]]></category>
		<category><![CDATA[Caching]]></category>
		<category><![CDATA[fortlaufende Werte]]></category>
		<category><![CDATA[Lookup]]></category>
		<category><![CDATA[SSIS]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-iii/</guid>
		<description><![CDATA[In den vorangegangenen beiden Teilen dieses Artikels (Teil I, Teil II) haben wir uns mit den Möglichkeiten des Range-Lookups beschäftigt, die ohne weitere Programmierung oder zusätzliche Komponenten mit reinen SSIS-Boardmitteln realisiert werden können. Nun wollen wir uns mit einer dritten Variante beschäftigen, um in unserem Beispielszenario die Kunden nach Ihrem Einkommen in die bereits bekannten [...]]]></description>
			<content:encoded><![CDATA[<p>In den vorangegangenen beiden Teilen dieses Artikels (<a href="http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-i-2/">Teil I</a>, <a href="http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-ii/">Teil II</a>) haben wir uns mit den Möglichkeiten des Range-Lookups beschäftigt, die ohne weitere Programmierung oder zusätzliche Komponenten mit reinen SSIS-Boardmitteln realisiert werden können. Nun wollen wir uns mit einer dritten Variante beschäftigen, um in unserem Beispielszenario die Kunden nach Ihrem Einkommen in die bereits bekannten Einkommensgruppen einzuteilen:</p>
<p><span id="more-74"></span><br />
<br\><br />
<img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup1.png" alt="" /></p>
<p><span style="text-decoration: underline;"><strong>Lösung mittels Script Task – Wunderwaffe &#8220;Binary Search&#8221;<br />
</strong></span><br />
<br\><br />
Wenn einen die mitgelieferten Standardkomponenten der Integration Services mal wieder nicht so richtig ans Ziel bringen, dann gibt es ja zum Glück immer noch den Script Task, den wir auch dazu nutzen können, um einen eigenen Lookup zu realisieren. Und genau das werden wir jetzt tun. Script Transformation in unseren Datenfluss gezogen und schon kann es mit der Definition der Eingabespalten beginnen. In unserem Fall reicht das YearlyIncome aus:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup2.png" alt="" /><br />
<br\><br />
Danach müssen wir dann noch die zugehörige Ausgabespalte definieren, die dann später unsere Gruppen-ID aufnehmen soll:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup3.png" alt="" /><br />
<br\><br />
Da ich die möglichen Gruppen direkt im Script-Task aus der Datenbank lesen möchte (es gibt auch andere, durchaus sauberere Wege), benötige ich auch noch einen Verbindungsmanager (der Einfachheit halber mit dem .NET Provider für SQL Server):</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup4.png" alt="" /><br />
<br\><br />
Nun kann ich mir noch die Programmiersprache auswählen (ich nehm mal C#) und endlich mit der eigentlichen Arbeit beginnen.<br />
<br\><br />
Als erstes benötige ich einen gefüllten Cache, der die möglichen Ausprägungen meiner Gehaltsgruppen aufnehmen kann. Diesen definiere ich als globale generische Liste einer eigens dafür gedachten Klasse Namens &#8220;NumericRangeItem&#8221;:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup5.png" alt="" /><br />
<br\><br />
Im PreExecute übernehme ich dann den Freigegebenen Verbindungsmanager und fülle einmalig den besagten Cache:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup6.png" alt="" /><br />
<br\><br />
Im FillCache() werden dann die oben gezeigten Zeilen aus der Datenbank gelesen und für jede Zeile ein neues NumericRangeItem in den Cache übernommen. Das NumericRangeItem ist dabei im wesentlichen ein Key-Value-Pair, wobei IncomeFrom als Key und die zugehörige IncomeGroupID als Value übernommen wird :</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup7.png" alt="" /><br />
<br\><br />
Besonderheit ist, dass es die Schnittstelle IComparable implementiert. Dazu muss die Klasse also eine Methode namens CompareTo enthalten, die aber auch ziemlich simpel ist.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup8.png" alt="" /><br />
<br\><br />
Damit wird lediglich festgelegt, dass beim Vergleich zweier NumericRangeItems die Schlüssel (also die Einkommensgrenze) miteinander verglichen werden.<br />
<br\><br />
Ergebnis ist, dass ich nach dem PreExecute alle Einkommensgrenzen als generische Liste vergleichbarer Elemente im Speicher habe. Belohnt werde ich für diesen Aufwand dann damit, dass eine solche Liste eine Methode namens BinarySearch() zur Verfügung stellt, die wir dann für den eigentlichen Lookup nutzen können:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup9.png" alt="" /><br />
<br\><br />
Für jede Zeile die ein Einkommen enthält wird die Funktion GetID aufgerufen, die einen numerischen Wert übergeben bekommt und das dazu passende NumericRangeItem zurückgibt. Der zu suchende Wert wird dabei selbst in einem NumericRangeItem verpackt, damit der Vergleich funktioniert. Und dann kann BinarySearch() die eigentliche Arbeit übernehmen. Dabei wird immer in die Mitte der Wertmenge geschaut und überprüft ob der dort vorhandene Wert größer oder kleiner als der Vergleichswert ist und dann mit der jeweils passenden Hälfte weitergearbeitet. Dadurch kann man mit BinarySerach auch in großen Datenmengen sehr schnell suchen (im schlimmsten Fall werden log<sub>2</sub>(<em>N</em>) + 1 Iterationen benötigt =&gt; zum Durchsuchen von 1 Mio Datensätzen werden höchstens 20 Versuche gebraucht). Was das Ganze für unser Szenario aber erst nutzbar macht, ist, dass auch für Werte, die nicht gefunden werden können ein Ergebnis geliefert wird.<br />
<br\><br />
Mathematisch ist dieser negative Rückgabewert das Komplement des nächstgrößeren Index. Da wir über die Untergrenzen suchen (IncomeFrom) erhalten wir also mit if (iScore &lt; 0) iScore = (short)(~iScore &#8211; 1); genau das Ergebnis, dass wir für unseren RangeLookup brauchen.<br />
<br\><br />
Das Ergebnis sieht dann wie zu hoffen war folgendermaßen aus:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup10.png" alt="" /><br />
<br\><br />
Dieses Bild haben wir so ähnlich bereits im Teil I gesehen, nur dass das Ergebnis diesmal in nicht mal einem Sechstel der Zeit berechnet war. Bei größeren Datenmengen verstärkt sich dieser Effekt sogar noch weiter. In unserem kleinen Beispiel benötigt der Script Task noch fast die Hälfte für das PreExecute, in dem ja auch der Cache gefüllt werden muss. Wenn wir aber nicht mehr 18k sondern ein paar Millionen Datensätze durch die Pipeline schicken, fällt dieser Overhead nicht mehr ins Gewicht.<br />
<br\><br />
Mit der Wunderwaffe BinarySearch brauchen wir also in Zukunft keine Angst mehr vor Range-Lookups bei großen Datenmengen zu haben.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-iii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Range-Lookups mit den Integration Services – Teil II</title>
		<link>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-ii/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-ii/#comments</comments>
		<pubDate>Fri, 30 Oct 2009 13:01:22 +0000</pubDate>
		<dc:creator>Markus Schechner</dc:creator>
				<category><![CDATA[Integration Services 2005]]></category>
		<category><![CDATA[Integration Services 2008]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[Caching]]></category>
		<category><![CDATA[Common Table Expression]]></category>
		<category><![CDATA[CTE]]></category>
		<category><![CDATA[fortlaufende Werte]]></category>
		<category><![CDATA[Lookup]]></category>
		<category><![CDATA[SSIS]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-ii/</guid>
		<description><![CDATA[Wie im Teil I versprochen wollen wir uns nun mit einer weiteren Möglichkeit für Range-Lookups mit den Integration Services auseinandersetzen.
Dazu zur Erinnerung noch einmal unsere Quelltabelle, aus der wir die zugehörigen IDs ermitteln wollen:



Lösung mittels Lookup – Mit Caching


Wie wir festgestellt haben, verliert der Lookup bei ausgeschaltetem Caching enorm an Geschwindigkeit. Alternativ könnte man also [...]]]></description>
			<content:encoded><![CDATA[<p>Wie im <a href="http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-i-2/trackback/">Teil I</a> versprochen wollen wir uns nun mit einer weiteren Möglichkeit für Range-Lookups mit den Integration Services auseinandersetzen.</p>
<p>Dazu zur Erinnerung noch einmal unsere Quelltabelle, aus der wir die zugehörigen IDs ermitteln wollen:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/102709_1200_RangeLookup1.png" alt="" /></p>
<p><span id="more-73"></span><br />
<br\><br />
<span style="text-decoration: underline;"><strong>Lösung mittels Lookup – Mit Caching<br />
</strong></span><br />
<br\><br />
Wie wir festgestellt haben, verliert der Lookup bei ausgeschaltetem Caching enorm an Geschwindigkeit. Alternativ könnte man also versuchen, den Range-Lookup mit aktiviertem Caching zu realisieren. Da der Lookup dann aber nur genaue Übereinstimmungen als Treffer wertet, muss für jeden möglichen Wert eine Zeile in der Lookup Tabelle existieren. Angenommen die Einkommen sind im beschriebenen Fall als volle Eurobeträge gespeichert, ließe sich das mit folgender rekursiven Common Table Expression (CTE) realisieren:<br />
<br\><br />
<span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">WITH</span> IncomeGroups<span style="color: gray;">(</span>IncomeGroupID<span style="color: gray;">,</span>Income<span style="color: gray;">,</span> IncomeTo<span style="color: gray;">)<br />
</span></span></p>
<p><span style="font-family: Courier New; color: blue; font-size: 10pt;">AS<br />
</span></p>
<p><span style="font-family: Courier New; color: gray; font-size: 10pt;">(<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">SELECT</span>    [IncomeGroupID]<span style="color: gray;">,</span>[IncomeFrom] <span style="color: blue;">as</span> Income<span style="color: gray;">,</span> [IncomeTo]<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">FROM</span>    dbo<span style="color: gray;">.</span>_MATCH_IncomeGroup<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">WHERE</span>    IncomeGroupID <span style="color: gray;">&lt;</span> 7<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">UNION</span><br />
<span style="color: gray;">ALL<br />
</span></span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">SELECT</span> [IncomeGroupID]<span style="color: gray;">,</span> Income <span style="color: gray;">+</span> 1<span style="color: gray;">,</span> [IncomeTo]<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">FROM</span> IncomeGroups<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">WHERE</span> Income <span style="color: gray;">+</span> 1 <span style="color: gray;">&lt;=</span> IncomeTo<br />
</span></p>
<p><span style="font-family: Courier New; color: gray; font-size: 10pt;">)<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">SELECT</span> Income<span style="color: gray;">,</span> IncomeGroupID<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">FROM</span> IncomeGroups<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">ORDER</span><br />
<span style="color: blue;">BY</span> 1<span style="color: gray;">,</span>2<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">OPTION </span><span style="color: gray;">(</span>MAXRECURSION 0<span style="color: gray;">)</span></span><br />
<br\><br />
Dieses Statement liefert im Management das folgende Ergebnis:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/102709_1200_RangeLookup2.png" alt="" /><br />
<br\><br />
Dies könnte als Quelle für den Lookup Task verwendet werden der dann wie jeder andere gewöhnliche Lookup konfiguriert werden kann.<br />
<br\><br />
Anschließend müsste dann die oberste Grenze, die in der Quelle bewusst ausgelassen wurde (denn 999.999.999 Datensätze wollte ich nun wirklich nicht erzeugen) per Abgeleitete Spalte (derived column) gesetzt werden.<br />
<br\><br />
Für Situationen in denen sehr viele Datensätze verarbeitet werden müssen, könnte dies eine gute Alternative zu der Variante ohne Caching sein. Es wird aber auch schnell klar, dass auch dieses Verfahren seine Grenzen hat. Für eine Aufteilung in Altersklassen von Kunden, für die es nur sehr wenige Ausprägungen in den Quelldaten gibt, ist dies wahrscheinlich die beste Lösung. Wenn es aber darum geht Firmenumsätze, die in die Milliarden gehen, in Gruppen einzuteilen, wird sowohl die Abfragezeit der Rekursion, als auch der benötigte Speicherplatz den Rahmen sprengen. Spätestens aber wenn die Grenzen nicht mehr mit ganzen Zahlen definierbar sind, ist dann wirklich Schluss.<br />
<br\><br />
Um auch für diese Situationen gerüstet zu sein, wird sich der nächste und vermutlich letzte Teil dieses Artikels mit der dritten Alternative, dem Range-Lookup mittels Script Task auseinandersetzen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-ii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Excel 2010 &#8211; Comeback des OLAP-Writebacks</title>
		<link>http://www.ixto.de/blog/sql-server-2005/excel-2010-comeback-des-olap-writebacks/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/excel-2010-comeback-des-olap-writebacks/#comments</comments>
		<pubDate>Thu, 01 Oct 2009 12:29:28 +0000</pubDate>
		<dc:creator>Markus Schechner</dc:creator>
				<category><![CDATA[Analysis Services 2005]]></category>
		<category><![CDATA[Analysis Services 2008]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[Excel 2010]]></category>
		<category><![CDATA[Olap]]></category>
		<category><![CDATA[Writeback]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/sql-server-2005/excel-2010-comeback-des-olap-writebacks/</guid>
		<description><![CDATA[Hallo zusammen,

ich habe in einer Feature-Liste für das neue Excel 2010 etwas gelesen, was ich unbedingt mal ausprobieren musste: Das allseits gefürchtete/geliebte Writeback für OLAP-Cubes kommt zurück.

Meine Ergebnisse möchte ich Euch natürlich nicht vorenthalten. Ich habe mir in einem 2008er Cube (Adventure Works 2008) eine kleine, einfache Partition mit Planzahlen gebaut und habe dort das [...]]]></description>
			<content:encoded><![CDATA[<p>Hallo zusammen,<br />
<br\><br />
ich habe in einer Feature-Liste für das neue Excel 2010 etwas gelesen, was ich unbedingt mal ausprobieren musste: Das allseits gefürchtete/geliebte Writeback für OLAP-Cubes kommt zurück.<br />
<br\><br />
Meine Ergebnisse möchte ich Euch natürlich nicht vorenthalten. Ich habe mir in einem 2008er Cube (Adventure Works 2008) eine kleine, einfache Partition mit Planzahlen gebaut und habe dort das Writeback im Modus ROLAP aktiviert (die AS können das mit dem Zurückschreiben übrigens durchweg seit mind. Version 2000 und mit dem Excel Add-in for SQL Server Analysis Services konnte man das sogar schon mal benutzen).</p>
<p><span id="more-70"></span><br />
<br\><br />
Dann habe ich mich mit Excel 2010 auf diesen Cube verbunden und die &#8220;What-If-Analyis&#8221; aktiviert.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/093009_1024_Excel2010Co1.png" alt="" /><br />
<br\><br />
Folgende Settings habe ich genommen.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/093009_1024_Excel2010Co2.png" alt="" /><br />
<br\><br />
Dann hab ich mein Measure mit zwei Dimensionen in die Pivot-Tabelle gepackt…</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/093009_1024_Excel2010Co3.png" alt="" /><br />
<br\><br />
… und den Wert für Europa erhöht.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/093009_1024_Excel2010Co4.png" alt="" /><br />
<br\><br />
Nach dem Neuberechnen der Pivot-Tabelle haben sich alle zugehörigen Werte erhöht.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/093009_1024_Excel2010Co5.png" alt="" /><br />
<br\><br />
Allerdings ist das ganze bis dahin nur eine Art Simulation. Erst wenn man es explizit sagt, werden die Änderungen in den Cube übernommen.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/093009_1024_Excel2010Co6.png" alt="" /><br />
<br\><br />
Dort landen sie dann in der vorher definierten Tabelle.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/093009_1024_Excel2010Co7.png" alt="" /><br />
<br\><br />
Nett, oder? Und die aus alten Zeiten bekannten Performanceprobleme beim Writeback auf größere Datenmengen sollen seit SQL Server 2008 auch der Vergangenheit angehören, da nicht mehr nur ROLAP, sondern auch MOLAP unterstützt wird. Das kann man aber auf einer Adventure Works schlecht überprüfen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/excel-2010-comeback-des-olap-writebacks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Range-Lookups mit den Integration Services – Teil I</title>
		<link>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-i-2/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-i-2/#comments</comments>
		<pubDate>Mon, 28 Sep 2009 11:26:14 +0000</pubDate>
		<dc:creator>Markus Schechner</dc:creator>
				<category><![CDATA[Integration Services 2005]]></category>
		<category><![CDATA[Integration Services 2008]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[BETWEEN]]></category>
		<category><![CDATA[Caching]]></category>
		<category><![CDATA[fortlaufende Werte]]></category>
		<category><![CDATA[Lookup]]></category>
		<category><![CDATA[SSIS]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/allgemein/range-lookups-mit-den-integration-services-%e2%80%93-teil-i-2/</guid>
		<description><![CDATA[In den von uns gebauten Integration Services Paketen ist der Lookup der wohl am meisten genutzte Task und im Grunde macht er seine Arbeit auch meistens gut und schnell. Spätestens wenn man während des ETLs jedoch fortlaufende Werte wie z.B. das Einkommen eines Kunden in Gruppen übersetzen will, stößt man mit dem Lookup an seine [...]]]></description>
			<content:encoded><![CDATA[<div><span>In den von uns gebauten Integration Services Paketen ist der Lookup der wohl am meisten genutzte Task und im Grunde macht er seine Arbeit auch meistens gut und schnell. Spätestens wenn man während des ETLs jedoch fortlaufende Werte wie z.B. das Einkommen eines Kunden in Gruppen übersetzen will, stößt man mit dem Lookup an seine Grenzen. Diese Artikel-Reihe beschreibt zwei Workarounds, mit denen sich dieses Problem mit dem Lookup trotzdem bewältigen lässt und schlägt zum Schluss eine wesentlich performantere Lösung mittels Script Task vor.</span></div>
<div><span><span id="more-64"></span></span><span> <br />
</span><br />
<br\><br />
Zur besseren Nachvollziehbarkeit bezieht sich das folgende Szenario auf die Microsoft Demo-Datenbank AdventureWorksDW2008, die unter <a href="http://msftdbprodsamples.codeplex.com/">http://msftdbprodsamples.codeplex.com/</a> heruntergeladen werden kann. Alle Screenshots basieren auf dem SQL Server 2008, die beschriebenen Vorgehensweisen lassen sich aber auch mit dem SQL Server 2005 realisieren.<br />
<br\><br />
<span style="text-decoration: underline;"><strong>Ausgangssituation<br />
</strong></span><br />
<br\><br />
In den Quelldaten für die Kunden gibt es eine Spalte, die das jährliche Einkommen der jeweiligen Kunden enthält (wie ein Fahrradhändler an solche Informationen kommt ist nicht nur Ihnen ein Rätsel). Um nach dieser Information später im Cube bzw. den Berichten besser auswerten zu können, sollen mehrere Einkommensgruppen entstehen, in die die einzelnen Kunden einsortiert werden müssen. Die dafür nötige Zuordnungstabelle hat folgenden Aufbau:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/092809_1108_RangeLookup1.png" alt="" /><br />
<br\><br />
Um den &#8220;normalen&#8221; ETL-Aufwand für dieses Beispiel möglichst gering zu halten, nutzen wir als Quelldaten für die Kunden bereits die Kundendimension des DWHs, in der alle relevanten Kundeninformationen bereits zusammen vorliegen. Diese sollen nun um die IncomeGroupID aus unserer Zuordnungstabelle ergänzt werden.<br />
<br\><br />
<span style="text-decoration: underline;"><strong>Lösung mittels Lookup – Ohne Caching<br />
</strong></span><br />
<br\><br />
Die hohe Geschwindigkeit des Lookups resultiert vor allem daraus, dass alle dem Lookup zu Grunde liegenden Daten bereits vor der eigentlichen Ausführung in den Hauptspeicher geladen werden und das Nachschlagen der Einzelwerte dann direkt im RAM erfolgen kann. In diesem Modus kann man aber leider nur exakt gleiche Werte wiederfinden. Eine Zuordnung zu einem Bereich, wie er in diesem Fall nötig ist, ist mit eingeschaltetem Caching nicht möglich. Da aber der Weg zum Ziel auch bei ausgeschaltetem Caching alles andere als intuitiv ist, wollen wir uns das doch mal genauer anschauen.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/092809_1125_RangeLookup2.png" alt="" /><br />
<br\><br />
Die Quelldaten werden 1:1 aus der Tabelle DimCustomer gelesen, mit dem Lookup um die zusätzliche Spalte ergänzt und ins Ziel (hier ins Nirvana) geschrieben. Der Lookup ist dabei folgendermaßen konfiguriert:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/092809_1125_RangeLookup3.png" alt="" /><br />
<br\><br />
Der Cache muss also wie gesagt deaktiviert werden.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/092809_1125_RangeLookup4.png" alt="" /><br />
<br\><br />
Als Quelle werden die untere und obere Grenze und die daraus resultierende GruppenID benötigt.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/092809_1125_RangeLookup5.png" alt="" /><br />
<br\><br />
Die Verknüpfung wird erst einmal so eingerichtet, als ob ein Standard-Lookup über eine Spalte eingerichtet wird, damit wir die Ergebnisspalte auswählen können.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/092809_1125_RangeLookup6.png" alt="" /><br />
<br\><br />
Erst unter dem Punkt &#8220;Erweitert&#8221; kommt dann die eigentliche Besonderheit ins Spiel. Durch das deaktivieren des Caches, können wir eine benutzerdefinierte Abfrage angeben, die für JEDE! Zeile des Datenflusses ausgeführt wird. Diese kann dann wie gezeigt parametrisiert werden. Resultat ist also, dass nicht mehr nach einem speziellen Wert gesucht wird, sondern der Ausdruck &#8220;YearlyIncome BETWEEN IncFrom AND IncTo&#8221; ausgewertet und die gewünschte GruppenID zurückgegeben wird.<br />
<br\><br />
Um das Ergebnis begutachten zu können, hängen wir hinter den Lookup einen Datenviewer mit den wichtigsten Spalten und lassen das ganze laufen.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/092809_1125_RangeLookup7.png" alt="" /><br />
<br\><br />
Wie man sieht erhalten wir das gewünschte Ergebnis. Allerdings deutet sich bereits bei dieser sehr kleinen Datenmenge an, dass die Geschwindigkeit nicht gerade Rekordverdächtig ist. Für kleine bis mittlere Datenmengen ist diese Lösung aber durchaus brauchbar.<br />
<br\><br />
Demnächst werden wir uns dann noch mit zwei weiteren Alternativen beschäftigen, die je nach Szenario eine bessere Performance erreichen können.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/range-lookups-mit-den-integration-services-%e2%80%93-teil-i-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Korrekte MDX-Berechnungen mit den Analysis Services trotz Multiselect</title>
		<link>http://www.ixto.de/blog/sql-server-2005/mdx-2005/korrekte-mdx-berechnungen-mit-den-analysis-services-trotz-multiselect/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/mdx-2005/korrekte-mdx-berechnungen-mit-den-analysis-services-trotz-multiselect/#comments</comments>
		<pubDate>Mon, 05 Jan 2009 09:08:36 +0000</pubDate>
		<dc:creator>Markus Schechner</dc:creator>
				<category><![CDATA[MDX im SQL Server 2005]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/sql-server-2005/mdx/korrekte-mdx-berechnungen-mit-den-analysis-services-trotz-multiselect/</guid>
		<description><![CDATA[Seit mehreren Jahren wird immer wieder über die Problematik von berechneten Elementen in den Analysis Services in Verbindung mit Multiselects diskutiert.

So schrieb Mosha bereits 2005 in Writing multiselect friendly MDX calculations über die Probleme, die auftreten wenn eine Berechnung ein CURRENTMEMBER benötigt und Sets in der WHERE Clause verwendet werden.

Das Thema ist aber leider immer [...]]]></description>
			<content:encoded><![CDATA[<p>Seit mehreren Jahren wird immer wieder über die Problematik von berechneten Elementen in den Analysis Services in Verbindung mit Multiselects diskutiert.<br />
<br\><br />
So schrieb Mosha bereits 2005 in <a href="http://sqlblog.com/blogs/mosha/archive/2005/11/18/writing-multiselect-friendly-mdx-calculations.aspx" target="_blank">Writing multiselect friendly MDX calculations</a> über die Probleme, die auftreten wenn eine Berechnung ein CURRENTMEMBER benötigt und Sets in der WHERE Clause verwendet werden.<br />
<br\><br />
Das Thema ist aber leider immer noch aktuell und wurde durch Excel 2007 und dessen Vorliebe für Subselects beim Auswählen mehrerer Elemente der gleichen Hierarchie eher noch verschlimmert. Denn dann geben die Analysis Services unter Umständen keinen Fehler mehr zurück, sondern zeigen einfach falsche Werte an.</p>
<p> <span id="more-46"></span><br />
<br\><br />
Da die Hoffnung „Mit Katmai wird alles besser“ für diese Problematik auch nicht zutrifft, wird im Folgenden noch mal auf die Problematik eingegangen und anschließend mit Hilfe von SCOPE eine mögliche Lösung erklärt. Die Beispiele basieren wie immer auf dem Adventure Works Cube, den es bei <a href="http://www.codeplex.com/MSFTDBProdSamples" target="_blank">Codeplex</a> zum Download gibt.<br />
<br\><br />
<strong><span style="text-decoration: underline;">Das Problem</span></strong><br />
<br\><br />
Um das eigentliche Problem zu verstehen, benötigen wir zwei berechnete Elemente. Zum einen werden wir uns „Ratio to Parent Product“ anschauen, das bereits in der Adventure Works enthalten ist und folgende Definition hat:</p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US">Create</span><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> <span style="color: blue;">Member</span> <span style="color: blue;">CurrentCube</span>.[Measures].[Ratio to Parent Product] </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> </span> </p>
<div><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">As</span> <span style="color: blue;">Case </span></span></div>
<p><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> </p>
<p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> </span> </p>
<p><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">        </span><span style="color: blue;">When</span> [Product].[Product Model Categories].<span style="color: maroon;">CurrentMember</span>.<span style="color: blue;">Level</span>.<span style="color: maroon;">Ordinal</span> </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">             </span>= 0 </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">        </span><span style="color: blue;">Then</span> 1 </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> </span> </p>
<p><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">        </span><span style="color: blue;">Else</span> [Measures].[Sales Amount] </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">             </span>/ </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">             </span>( [Product].[Product Model Categories].<span style="color: maroon;">CurrentMember</span>.<span style="color: maroon;">Parent</span>, </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">               </span>[Measures].[Sales Amount] ) </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> </span> </p>
<p><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">    </span><span style="color: blue;">End</span>, </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; line-height: 115%; font-family: &amp;#39;Courier New&amp;#39;;">Format_String</span><span style="font-size: 10pt; line-height: 115%; font-family: &amp;#39;Courier New&amp;#39;;"> = <span style="color: #a31515;">&#8220;Percent&#8221;</span> ;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; line-height: 115%; font-family: &amp;#39;Courier New&amp;#39;;"> </span></p>
<p>Zusätzlich definieren wir uns ein einfaches eigenes Measure, dass die Anzahl der Produkte für die jeweilige Auswahl anzeigt:</p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US">Create</span><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> <span style="color: blue;">MEMBER</span> <span style="color: blue;">CurrentCube</span>.[Measures].[Number of Products] </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US">AS </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">    </span><span style="color: blue;">COUNT</span>(<span style="color: blue;">EXISTING</span>([Product].[Product].[Product].<span style="color: blue;">MEMBERS</span>)); </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> </span></p>
<p><br\><br />
EXISTING sorgt dabei dafür, dass nicht immer die gleiche Anzahl zurückgegeben wird, sondern das Measure für die jeweils ausgewählten Koordinaten des Cubes neu berechnet wird.<br />
<br\><br />
Nun können wir uns das ganze in Excel ansehen. Wenn wir die beiden berechneten Measures und zusätzlich noch den Sales Amount auswählen und die „Product Categories“ auf den Zeilen ausgeben, dann ergibt sich folgendes Bild:</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image002.jpg"><img style="border-width: 0px;" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image002_thumb.jpg" border="0" alt="clip_image002" width="519" height="145" /></a><br />
<br\><br />
Wie zu erwarten war, werden sowohl Number of Products, als auch die Ratio to Parent richtig für die einzelnen Produktkategorien angezeigt. Dass die Summe der Einzelwerte der „Number of Products“ nicht dem Gesamtergebnis entspricht, liegt übrigens daran, dass 209 Produkte dem, unglücklicherweise unsichtbaren, UnknownMember zugeschlagen wurden.<br />
<br\><br />
Wenn wir nun die Produktkategorien von den Zeilen in den Filter verschieben und dort mehrere Elemente auswählen,</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image004.jpg"><img style="border-width: 0px;" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image004_thumb.jpg" border="0" alt="clip_image004" width="211" height="251" /></a></p>
<p>dann nutzt Excel im Hintergrund ein SUBSELECT, um diese Einschränkung abzubilden. Das Ergebnis sieht dann folgendermaßen aus:</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image006.jpg"><img style="border-width: 0px;" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image006_thumb.jpg" border="0" alt="clip_image006" width="390" height="106" /></a></p>
<p>Für den Sales Amount wird korrekt die Summe der Kategorien „Accessoires“ und „Bikes“ angezeigt, was beweist, dass Excel mit seinem MDX nicht völlig daneben liegen kann. Trotzdem stimmen die Zahlen der anderen beiden Measures nicht. Es sieht aus, als wäre gar keine Einschränkung gemacht worden. Würde man sich ein Measure definieren, das <span style="font-size: 10pt; line-height: 115%; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: de; mso-fareast-font-family: calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: en-us; mso-bidi-language: ar-sa;">[Product].[Product Model Categories].<span style="color: maroon;">CurrentMember</span>.Name</span> ausgibt, dann könnte man sehen, dass genau das geschehen ist. Innerhalb der MDX-Scripts, gibt es nur eine gewählte Produktkategorie, nämlich „[All]“. Unsere berechneten Elemente bekommen von der Tatsache, dass sie in einem beschränkten Subcube laufen, nichts mit.<br />
<br\><br />
<strong><span style="text-decoration: underline;">Die Lösung?</span></strong><br />
<br\><br />
Die Grundidee, um dieses Problem zu umgehen, ist echte Measures anzulegen und diese dann per SCOPE so zu überschreiben, dass die eigentlichen Werte dann wieder per MDX ermittelt werden.<br />
<br\><br />
Beginnen wir also mit dem Anlegen eines „echten“ Measures für die Anzahl der Produkte. Da es diesen Wert auf Faktenebene nicht gibt, müssen wir uns also erst mal eine Spalte erzeugen, die wir später als Quelle für unser neues Measure nutzen können. Wir erzeugen uns also in der Data Source View für die FactSalesSummary eine leere Dummy-Spalte.</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image008.jpg"><img style="border-width: 0px;" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image008_thumb.jpg" border="0" alt="clip_image008" width="414" height="397" /></a><br />
<br\><br />
Dazu überarbeiten wir die Abfrage, die hinter der Faktentabelle liegt so, dass in beiden Teilen des UNIONS die neue Spalte „Dummy“ auftaucht.</p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US">SELECT</span><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">     </span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-tab-count: 1;">      </span>&#8230; </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-tab-count: 1;">      </span><span style="color: gray;">,</span> <span style="color: gray;">NULL</span> <span style="color: blue;">AS</span> [Dummy] </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US">FROM</span><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> FactResellerSales </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US">UNION </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US">SELECT</span><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">     </span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-tab-count: 1;">      </span>&#8230; </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-tab-count: 1;">      </span><span style="color: gray;">,</span> <span style="color: gray;">NULL</span> <span style="color: blue;">AS</span> [Dummy] </span></p>
<p><span style="font-size: 10pt; color: blue; line-height: 115%; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: de; mso-fareast-font-family: calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: en-us; mso-bidi-language: ar-sa;">FROM</span><span style="font-size: 10pt; line-height: 115%; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: de; mso-fareast-font-family: calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: en-us; mso-bidi-language: ar-sa;"> FactInternetSales</span><br />
<br\><br />
Nun können wir diese Spalte im Cube verwenden und erzeugen uns auf dessen Basis ein neues Measure Namens „Scoped Number of Products“.</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image010.jpg"><img style="border-width: 0px;" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image010_thumb.jpg" border="0" alt="clip_image010" width="323" height="329" /></a><br />
<br\><br />
Dabei ist zu beachten, dass die Aggregat-Funktion, die bei Usage ausgewählt wird, später auch wirklich Anwendung findet. Während bei berechneten Elementen auf jeder Ebene im Cube die Berechnung stattfindet, wird beim SCOPING „nur“ für den explizit überschriebenen Subcube das MDX verwendet. Für alle nicht überschriebenen Bereiche wird normal aggregiert, wobei allerdings die „neuen“ Werte herangezogen werden.<br />
<br\><br />
Wir wählen also bei Usage die Summe aus und haben unser neues Measure. Nach dem Bereitstellen und Aufbereiten des überarbeiteten Cubes können wir das auch schon verwenden, erhalten aber selbstverständlich nur leere Zellen. Die eigentliche Berechnung müssen wir nun noch unter „Calculations“ definieren:</p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US">SCOPE</span><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> ([Measures].[Scoped Number of Products], [Product].[Product].[Product].<span style="color: blue;">MEMBERS</span> ); </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">    </span><span style="color: blue;">THIS</span> = 1; </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">    </span><span style="color: blue;">SCOPE</span> ([Product].[Product].[All Products].<span style="color: maroon;">UnknownMember</span>); </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">       </span><span style="color: blue;">THIS</span> = 0; </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">    </span><span style="color: blue;">END</span> <span style="color: blue;">SCOPE</span>; </span></p>
<p><span style="font-size: 10pt; color: blue; line-height: 115%; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us; mso-fareast-font-family: calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: en-us; mso-bidi-language: ar-sa;" lang="EN-US">END</span><span style="font-size: 10pt; line-height: 115%; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us; mso-fareast-font-family: calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: en-us; mso-bidi-language: ar-sa;" lang="EN-US"> <span style="color: blue;">SCOPE</span>;</span><br />
<br\><br />
Für alle Elemente des Levels “Product” in der Hierarchie “Product” der Dimension “Product” wird damit der Wert des Measures „Scoped Number of Products“ auf 1 gesetzt. Alle anderen Ebenen und Hierarchien, wie z. B. der All-Knoten, werden dabei ignoriert, da wir dafür ja die bereits definierte Summen-Funktion nutzen wollen.<br />
<br\><br />
Um eine Vergleichbarkeit mit dem alten berechneten Element herzustellen, verhindert das zweite SCOPE lediglich, dass das unsichtbare UnknownMember der Produkt-Hierarchie mitgezählt wird.<br />
<br\><br />
Um zu überprüfen, ob die Zahlen passen, nehmen wir das neue Measure nun in unsere erste Abfrage von oben mit auf:</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image012.jpg"><img style="border-width: 0px;" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image012_thumb.jpg" border="0" alt="clip_image012" width="476" height="145" /></a><br />
<br\><br />
Soweit, so gut. Spannender wird es jetzt aber, wenn wir die Kategorien wieder von den Zeilen in den Filter verschieben und nur die ersten beiden Elemente auswählen &#8211; Excel also wieder sein beliebtes SUBSELECT ausführt:</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image014.jpg"><img style="border-width: 0px;" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image014_thumb.jpg" border="0" alt="clip_image014" width="321" height="106" /></a><br />
<br\><br />
Wie erhofft ergibt 35 + 125 nun nicht mehr 606, sondern Excel gibt die korrekte Summe 160 zurück. Dadurch, dass wir das Measure auf der untersten Ebene der Produktdimension überschrieben haben, nutzen die Analysis Services nicht mehr bestehende Aggregate, sondern müssen alle betroffenen Produkte zur Laufzeit berechnen. Die anschließend stattfindende Aggregation der Werte wird dann nur für den betroffenen Subcube, also unter Berücksichtigung des Subselects, durchgeführt.<br />
<br\><br />
Um zu zeigen, dass dies nicht nur für simples Zählen funktioniert, erzeugen wir uns ein weiteres Measure auf Basis unserer Dummy-Spalte, nennen es „Scoped Ratio to Parent Product“ und erweitern unser MDX-Script um folgenden Ausdruck:</p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; color: blue; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US">SCOPE</span><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"> ([Measures].[Scoped Ratio to Parent Product], [Product].[Product Model Categories].<span style="color: blue;">MEMBERS</span>); </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">    </span><span style="color: blue;">SCOPE</span>(<span style="color: blue;">DESCENDANTS</span>([Product].[Product Model Categories].[All Products], , <span style="color: blue;">AFTER</span>)); </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">        </span><span style="color: blue;">THIS</span> = [Measures].[Sales Amount] </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">             </span>/ ( [Product].[Product Model Categories].<span style="color: maroon;">CurrentMember</span>.<span style="color: maroon;">Parent</span>, </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">               </span>[Measures].[Sales Amount] ); </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">    </span><span style="color: blue;">END</span> <span style="color: blue;">SCOPE</span>; </span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: normal; mso-pagination: none; mso-layout-grid-align: none;"><span style="font-size: 10pt; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us;" lang="EN-US"><span style="mso-spacerun: yes;">    </span><span style="color: blue;">Format_String</span>(<span style="color: blue;">THIS</span>) = <span style="color: #a31515;">&#8220;Percent&#8221;</span> ; </span></p>
<p><span style="font-size: 10pt; color: blue; line-height: 115%; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us; mso-fareast-font-family: calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: en-us; mso-bidi-language: ar-sa;" lang="EN-US">END</span><span style="font-size: 10pt; line-height: 115%; font-family: &amp;#39;Courier New&amp;#39;; mso-ansi-language: en-us; mso-fareast-font-family: calibri; mso-fareast-theme-font: minor-latin; mso-fareast-language: en-us; mso-bidi-language: ar-sa;" lang="EN-US"> <span style="color: blue;">SCOPE</span>;</span><br />
<br\><br />
Dabei sorgt das DESCENDANTS(…) dafür, dass alle Elemente der Hierarchie “Product Model Categories” außer dem All-Knoten überschrieben werden. Das Ergebnis in Excel sieht dann folgendermaßen aus:</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image016.jpg"><img style="border-width: 0px;" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/KorrekteMDXBerechnungenmitdenAnalysisSer_87F6/clip_image016_thumb.jpg" border="0" alt="clip_image016" width="387" height="106" /></a><br />
<br\><br />
Auch hier sorgt das Überschreiben auf unterster Ebene dafür, dass die Berechnung richtig funktioniert. In dem Augenblick, in dem die einzelnen Knoten der ausgewerteten Hierarchie berechnet werden, gibt es eben immer ein CurrentMember, egal ob nun ein oder mehrere Knoten ausgewählt sind.<br />
<br\><br />
<strong><span style="text-decoration: underline;">Einschränkungen</span></strong><br />
<br\><br />
Zugegeben, habe ich mir das ganze hier etwas leicht gemacht. Die beiden Berechnungen einfach zu summieren, macht nämlich eigentlich keinen Sinn. Sowohl die Anzahl der Produkte, als auch die Prozente sind sogenannte semi-additive Measures, die eben nicht einfach summiert werden dürfen. Für beide fehlt also mindestens eine Sonderbehandlung für die Zeitdimension, die durch Nutzung anderer Aggregatfunktionen oder erweiterter SCOPE-Statements erreicht werden könnte, die den Rahmen dieses Beitrags sprengen würden.<br />
<br\><br />
Außerdem muss ich davor warnen jetzt ab sofort alle berechneten Elemente durch solche SCOPEs abzulösen, denn das ganze hat natürlich einen Haken. Der Grund, warum das Ganze funktioniert, nämlich das Berechnen auf unteren Ebenen, hat gleichzeitig negative Auswirkungen auf die Performance. Es können eben nicht mehr vorberechnete Werte aus den Aggregationen oder dem Cache übernommen werden. Bei jeder Abfrage, die sonst nur wenige Zellen zur Berechnung hätte nutzen müssen, muss jetzt unter Umständen ein Vielfaches an Daten berücksichtigt werden, um das gewünschte Ergebnis zu erhalten.<br />
<br\><br />
Nichts desto trotz zeigt das Ganze, dass es möglich ist, Berechnungen so zu definieren, dass sie Multiselect-fähig sind, obwohl sie Funktionen wie EXISTING oder CurrentMember benötigen. Wer mit relativ wenig Daten arbeitet, oder wem es nicht gelingt seinen Nutzern das Multiselect in Excel auszureden, der kommt so vielleicht zu einer Lösung.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/mdx-2005/korrekte-mdx-berechnungen-mit-den-analysis-services-trotz-multiselect/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dimensionsdatensicherheit als Fehlerquelle f&#252;r &quot;unsaubere&quot; Sets</title>
		<link>http://www.ixto.de/blog/sql-server-2005/mdx-2005/dimensionsdatensicherheit-als-fehlerquelle-fr-unsaubere-sets/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/mdx-2005/dimensionsdatensicherheit-als-fehlerquelle-fr-unsaubere-sets/#comments</comments>
		<pubDate>Mon, 28 Jul 2008 16:44:39 +0000</pubDate>
		<dc:creator>Markus Schechner</dc:creator>
				<category><![CDATA[MDX im SQL Server 2005]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/allgemein/dimensionsdatensicherheit-als-fehlerquelle-fr-unsaubere-sets/</guid>
		<description><![CDATA[Hallo liebe Reportbauer, MDXler und alle die es werden wollen,
ich bin vor kurzem bei einem Kunden &#252;ber ein Ph&#228;nomen gestolpert, dass ich Euch nicht vorenthalten will.
&#160;
Wie immer wieder von mir gepredigt wird, arbeiten wir in der Regel zur Ausklammerung bestimmter Dimensionsknoten mit so genannten &#8222;Negativ-Listen&#8220;. Das bedeutet, wenn wir aus der Dimension Buchstaben die Knoten [...]]]></description>
			<content:encoded><![CDATA[<p>Hallo liebe Reportbauer, MDXler und alle die es werden wollen,</p>
<p>ich bin vor kurzem bei einem Kunden &#252;ber ein Ph&#228;nomen gestolpert, dass ich Euch nicht vorenthalten will.</p>
<p>&#160;</p>
<p>Wie immer wieder von mir gepredigt wird, arbeiten wir in der Regel zur Ausklammerung bestimmter Dimensionsknoten mit so genannten &#8222;Negativ-Listen&#8220;. Das bedeutet, wenn wir aus der Dimension Buchstaben die Knoten A, B und E sehen wollen sagen wir nicht {A, B, E} sondern {Buchstaben.ALLE &#8211; {C, D}}. Dadurch w&#252;rden neue Knoten in der Dimension (z.B. der neu eingef&#252;hrte Buchstabe F <img src='http://www.ixto.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ) nicht per Default unterdr&#252;ckt, sondern w&#228;ren erst mal sichtbar. In den meisten echten Anwendungsf&#228;llen ist diese Negativ-Liste oft auch deutlich k&#252;rzer als die Positiv-Liste.<br />
<span id="more-35"></span> <br\> Aber genug &#252;ber den Sinn und Unsinn von Negativ-Listen, das Statement</p>
<p>&#160;</p>
<p><font color="#0000ff" size="2">SELECT</font>
</p>
<p>   <font size="2">{}</font>
<p><font color="#0000ff" size="2">ON</font><font size="2"> </font><font color="#0000ff" size="2">COLUMNS</font><font size="2">,</font></p>
<p>{[Product].[Category].[Accessories], [Product].[Category].[Bikes], [Product].[Category].[Clothing]}</p>
<p><font color="#0000ff" size="2">ON</font><font size="2"> </font><font color="#0000ff" size="2">ROWS</font></p>
<p>FROM</p>
<p><font size="2">[Adventure Works]</font></p>
<p>&#160;</p>
</p>
<p> liefert das gleiche Ergebnis zur&#252;ck, wie</p>
<p>&#160;</p>
<p><font color="#0000ff" size="2">SELECT</font>
</p>
<p>   <font size="2">{}</font>
<p><font color="#0000ff" size="2">ON</font><font size="2"> </font><font color="#0000ff" size="2">COLUMNS</font><font size="2">,</font></p>
<p>{[Product].[Category].[Category].</p>
<p><font color="#0000ff" size="2">MEMBERS</font><font size="2"> &#8211; [Product].[Category].[Components]} </font><font color="#0000ff" size="2">ON</font><font size="2"> </font><font color="#0000ff" size="2">ROWS</font></p>
<p>FROM</p>
<p><font size="2">[Adventure Works]</font></p>
<p>&#160;</p>
</p>
<p> Nun hat sich innerhalb des besagten Kundenprojektes heimlich durchgesetzt, dass die abgek&#252;rzte Schreibweise verwendet wird, also {&#8211; {C, D}} statt { Buchstaben.ALLE &#8211; {C, D}}. Also auch die folgende dritte Variante hat das gleiche Ergebnis wie die oberen beiden.</p>
<p>&#160;</p>
<p><font color="#0000ff" size="2">SELECT</font>
</p>
<p>   <font size="2">{}</font>
<p><font color="#0000ff" size="2">ON</font><font size="2"> </font><font color="#0000ff" size="2">COLUMNS</font><font size="2">,</font></p>
<p>{-{[Product].[Category].[Components]}}</p>
<p><font color="#0000ff" size="2">ON</font><font size="2"> </font><font color="#0000ff" size="2">ROWS</font></p>
<p>FROM</p>
<p><font size="2">[Adventure Works]</font></p>
<p>&#160;</p>
</p>
<p> Dies hat eigentlich auch super funktioniert, ist an K&#252;rze kaum noch zu &#252;bertreffen UND SOLLTE TROTZDEM NIE WIEDER GETAN WERDEN <img src='http://www.ixto.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>&#160;</p>
<p>Implizit erkennt der AS bei dieser Schreibweise, welche Elemente auf der linken Seite dieses Komplements geh&#246;ren, n&#228;mlich Buchstaben.ALLE. Sobald aber eine Dimensionssicherheit ins Spiel kommt wird&#8217;s gef&#228;hrlich. AS sucht die Knoten dann nur noch in dem Bereich in dem der Nutzer berechtigt ist. Wenn er den Knoten da nicht findet, wei&#223; er nicht, ob er nicht existiert, oder ob er nicht berechtigt ist und ersetzt ihn durch die leere Menge ({}).</p>
<p>&#160;</p>
<p>Aus { Buchstaben.ALLE &#8211; {C, D}} w&#252;rde also intern { Buchstaben.ALLE &#8211; { }}. Nicht schlimm, funktioniert super. Ihr k&#246;nnt Euch aber denken, dass das nicht mehr funktioniert, wenn aus {&#8211; {C, D}} durch dieses Verhalten {-{}} wird. Und das B&#246;se daran ist, dass das erst auftritt wenn der erste eingeschr&#228;nkte Nutzer darauf zugreift. F&#252;r Euch als Entwickler sieht es aus als w&#228;re alles fein, w&#228;hrend der arme Benutzer mit der Meldung &quot;<em>Die Menge muss eine einzige Hierarchie aufweisen, um mit dem Komplementoperator verwendet zu werden.</em>&quot; bzw. &quot;<em>The set must have a single hierarchy to be used with the complement operator.</em>&quot; begr&#252;&#223;t wird.</p>
<p>&#160;</p>
<p>Also kurz:</p>
<p>Niemals {&#8211; {C, D}}</p>
<p>Immer { Buchstaben.ALLE &#8211; {C, D}}&#160; oder aber EXCEPT(Buchstaben.ALLE, {C, D})</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/mdx-2005/dimensionsdatensicherheit-als-fehlerquelle-fr-unsaubere-sets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Trendlinie in Reporting Services 2005 dank MDX</title>
		<link>http://www.ixto.de/blog/sql-server-2005/reportingservices/trendlinie-in-reporting-services-2005-dank-mdx/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/reportingservices/trendlinie-in-reporting-services-2005-dank-mdx/#comments</comments>
		<pubDate>Fri, 11 Jan 2008 09:34:14 +0000</pubDate>
		<dc:creator>Markus Schechner</dc:creator>
				<category><![CDATA[Reporting Services 2005]]></category>

		<guid isPermaLink="false">http://www.ixto.de/wordpress/?p=21</guid>
		<description><![CDATA[Viele Controller kennen und lieben sie aus Excel: die Trendlinie. Mal eben die Umsätze der letzten Quartale als Balkendiagramm betrachtet und mit zwei Klicks den Trend visualisiert.
&#160;

&#160;
Um so verwirrter guckt dann dieser Controller, wenn man ihm versucht zu erklären, dass das mit den Reporting Services nicht möglich ist. Zum Glück stimmt das auch nicht ganz.
Mit [...]]]></description>
			<content:encoded><![CDATA[<p>Viele Controller kennen und lieben sie aus Excel: die Trendlinie. Mal eben die Umsätze der letzten Quartale als Balkendiagramm betrachtet und mit zwei Klicks den Trend visualisiert.</p>
<p>&nbsp;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/1cfd5452e220_B9BD/Excel.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="171" alt="Trendlinie in Excel" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/1cfd5452e220_B9BD/Excel_thumb.jpg" width="358" border="0"></a></p>
<p>&nbsp;</p>
<p>Um so verwirrter guckt dann dieser Controller, wenn man ihm versucht zu erklären, dass das mit den Reporting Services nicht möglich ist. Zum Glück stimmt das auch nicht ganz.</p>
<p>Mit Hilfe von <a href="http://www.dundas.com/Products/Chart/RS/index.aspx" target="_blank">Dundas Chart für Reporting Services</a> ist dies fast so einfach wie in Excel. Der Haken liegt dann nur noch bei den Lizenzkosten.</p>
<p>&nbsp;</p>
<p><span id="more-21"></span><br />
<br\></p>
<p>Aber auch ohne zusätzliche Software sind einfache Trendlinien mit SSRS möglich, denn genaugenommen ist das ja nichts weiter als ein &#8220;bisschen&#8221; Mathematik.</p>
<p>Grundlage für die oben gezeigte gerade Trendlinie ist die <em>einfache lineare Regression</em>. Und dafür gibt es in MDX Funktionen, die sich nutzen lassen, um diesen Trend zu berechnen. Die Grundlagen dieser MDX Funktionen und der mathematischen Konzepte dahinter hat Mosha bereits vor einigen Jahren in seinem <a href="http://www.mosha.com/msolap/articles/mdxlinreg.htm" target="_blank">Blog</a> veröffentlicht.</p>
<p>&nbsp;</p>
<p>Nun aber zurück zum eigentlichen Thema, das Erzeugen der oben gezeigten Grafik in den Reporting Services:</p>
<p>Mit dem Assistenten erstellen wir einen neuen Bericht auf den <em>Adventure Works</em> Cube aus der <a href="http://www.codeplex.com/MSFTDBProdSamples" target="_blank"><em>Adventure Works DW</em></a> Datenbank. Nach dem Umschalten des Designmodes kommt für das Dataset folgender Quellcode zum Vorschein:</p>
<p><font size="2"></font></p>
<p><font size="2"><font color="#0000ff" size="2">SELECT</font><font size="2"> </font></font></p>
<p><font size="2"><font color="#0000ff" size="2">NON</font><font size="2"> </font><font color="#0000ff" size="2">EMPTY</font><font size="2"> { [Measures].[Sales Amount] } </font><font color="#0000ff" size="2">ON</font><font size="2"> </font><font color="#0000ff" size="2">COLUMNS</font><font size="2">, </font></font></p>
<p><font size="2"><font color="#0000ff" size="2">NON</font><font size="2"> </font><font color="#0000ff" size="2">EMPTY</font><font size="2"> { </font><font size="2">([Date].[Calendar].[Calendar Quarter].ALLMEMBERS) } </font><font color="#0000ff" size="2">ON</font><font size="2"> </font><font color="#0000ff" size="2">ROWS</font><font size="2"> </font></font></p>
<p><font size="2"><font color="#0000ff" size="2">FROM</font><font size="2"> [Adventure Works] </font></font></p>
<p>&nbsp;</p>
<p>Um später die Lesbarkeit des Codes zu erhöhen, erstellen wir uns als erstes ein Set, dass alle Quartale enthält, die wir auch der Achse anzeigen wollen.</p>
<p><font color="#0000ff" size="2"></font></p>
<p><font color="#0000ff" size="2">WITH</font></p>
<p><font color="#0000ff" size="2">SET</font></p>
<p><font color="#0000ff" size="2"><font size="2">myMonate </font><font color="#0000ff" size="2">AS</font><font size="2"> </font><font size="2"><font size="2">([Date].[Calendar].[Calendar Quarter].ALLMEMBERS)</font></font></font></p>
<p>&nbsp;</p>
<p>Nun müssen wir für jede Zeile den Wert ermitteln, der für das jeweilige Quartal auf der Trendlinie liegt. Dazu nutzen wir die MDX-Funktion: LinRegPoint.</p>
<pre>&nbsp;</pre>
<pre>LinRegPoint(<em>Slice_Expression_x</em>, <em>Set_Expression</em>, <em>Numeric_Expression_y </em>[ ,<em>Numeric_Expression_x</em> ] )</pre>
<p><strong></strong>&nbsp;</p>
<p><strong>Slice_Expression_x</strong>: Hier wird ein numerischer Ausdruck erwartet, der als x-Wert genutzt werden soll. Da die Quartale nicht numerisch sind, können wir diese hier nicht direkt benutzen. Wir können jedoch die RANK-Funktion nutzen, um die Position des jeweiligen Quartales auf der X-Achse zu ermitteln. Diesen merken wir uns in einem eigenen Member:</p>
<p><font color="#0000ff" size="2">MEMBER</font></p>
<p><font color="#0000ff" size="2"><font size="2">Measures.myX </font><font color="#0000ff" size="2">AS</font><font size="2"> </font><font color="#800000" size="2">Rank</font><font size="2">([Date].[Calendar].</font><font color="#800000" size="2">CurrentMember</font><font size="2">, [Date].[Calendar].</font><font color="#800000" size="2">CURRENTMEMBER</font><font size="2">.</font><font color="#0000ff" size="2">LEVEL</font><font size="2">.</font><font color="#0000ff" size="2">MEMBERS</font><font size="2">)</font> </font></p>
<p><font color="#000000" size="2"><strong></strong></font>&nbsp;</p>
<p><font color="#000000" size="2"><strong>Set_Expression</strong>: An dieser Stelle wird definiert, über welches Set der Trend-Wert berechnet werden soll. Hier könnte z.B. die letzten 10 Perioden gewählt werden, oder ein Set, das von Berichtsparametern abhängig ist, genutzt werden. In unserem Fall wollen wir einfach alle Quartale zur Berechnung heranziehen und nutzen deshalb das eben erstellte Set <em>myMonate</em>.</font></p>
<p><font color="#000000" size="2"><strong></strong></font>&nbsp;</p>
<p><font color="#000000" size="2"><strong>Numeric_Expression_y</strong>: Der gewünschte y-Wert ist einleuchtend: <em>[Measures].[Sales Amount]</em>, dafür machen wir das ganze ja schließlich.</font></p>
<p><font color="#000000" size="2"><strong></strong></font>&nbsp;</p>
<p><font color="#000000" size="2"><strong>Numeric_Expression_x</strong>: Hier wird die Formel erwartet, die genutzt werden kann, um die x-Werte der anderen Punkte &#8220;vorauszusagen&#8221;. Wir können hier einfach den gleichen Ausdruck benutzen, wie bei Slice_Expression_x: myX</font></p>
<p><font color="#000000" size="2"></font>&nbsp;</p>
<p><font color="#000000" size="2">Wenn wir das alles einsetzen und dem Ganzen dann noch einen Namen geben, erhalten wir folgenden Ausdruck:</font></p>
<p><font color="#0000ff" size="2"></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2">MEMBER</font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><font size="2">Measures.[Sales Trend] </font><font color="#0000ff" size="2">AS</font><font size="2"> </font><font color="#800000" size="2">LinRegPoint</font><font size="2">(Measures.myX, myMonate, [Measures].[Sales Amount], Measures.myX)</font></font><font color="#0000ff" size="2"><font color="#0000ff" size="2"> </font></font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><font color="#0000ff" size="2"></font><font color="#000000" size="2"></font></font></font>&nbsp;</p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><font color="#000000" size="2">Unsere Quelle für das Berichts-Dataset sieht nun also folgendermaßen aus:</font></font><font color="#0000ff" size="2"> </font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2">WITH</font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2">SET</font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><font size="2">myMonate </font><font color="#0000ff" size="2">AS</font><font size="2"> ([Date].[Calendar].[Calendar Quarter].</font><font color="#800000" size="2">ALLMEMBERS</font><font size="2">)</font></font><font color="#0000ff" size="2"> </font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2">MEMBER</font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><font size="2">Measures.myX </font><font color="#0000ff" size="2">AS</font><font size="2"> </font><font color="#800000" size="2">Rank</font><font size="2">([Date].[Calendar].</font><font color="#800000" size="2">CurrentMember</font><font size="2">, [Date].[Calendar].</font><font color="#800000" size="2">CURRENTMEMBER</font><font size="2">.</font><font color="#0000ff" size="2">LEVEL</font><font size="2">.</font><font color="#0000ff" size="2">MEMBERS</font><font size="2">)</font></font><font color="#0000ff" size="2"> </font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2">MEMBER</font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><font size="2">Measures.[Sales Trend] </font><font color="#0000ff" size="2">AS</font><font size="2"> </font><font color="#800000" size="2">LinRegPoint</font><font size="2">(Measures.myX, myMonate, [Measures].[Sales Amount], Measures.myX)</font> </font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><font color="#0000ff" size="2">SELECT</font><font size="2"> </font></font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><font color="#0000ff" size="2">NON</font><font size="2"> </font><font color="#0000ff" size="2">EMPTY</font><font size="2"> { [Measures].[Sales Amount],Measures.[Sales Trend] } </font><font color="#0000ff" size="2">ON</font><font size="2"> </font><font color="#0000ff" size="2">COLUMNS</font><font size="2">, </font></font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><font color="#0000ff" size="2">NON</font><font size="2"> </font><font color="#0000ff" size="2">EMPTY</font><font size="2"> {myMonate} </font><font color="#0000ff" size="2">ON</font><font size="2"> </font><font color="#0000ff" size="2">ROWS</font><font size="2"> </font></font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><font color="#0000ff" size="2">FROM</font><font size="2"> [Adventure Works] </font></font></font></p>
<p><font color="#000000" size="2"><font size="2"></font></font>&nbsp;</p>
<p><font color="#000000" size="2"><font size="2">Und wenn wir das ganze als Grafik anzeigen, dann sieht das in etwa so aus:</font></font></p>
<p><font size="2"></font>&nbsp;</p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/1cfd5452e220_B9BD/SSRS.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="228" alt="Trendlinie in den Reporting Services" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/1cfd5452e220_B9BD/SSRS_thumb.jpg" width="412" border="0"></a> </font></font></p>
<p><font color="#000000" size="2"><font size="2"></font></font>&nbsp;</p>
<p><font color="#000000" size="2"><font size="2">Wenn das unseren Controller nicht glücklich macht <img src='http://www.ixto.de/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </font></font></p>
<p><font color="#000000" size="2"><font size="2"></font></font>&nbsp;</p>
<p><font color="#000000" size="2"><font size="2">An dieser Stelle sollte noch angemerkt werden, dass die LinRegPoint-Funktion mit Rekursion arbeitet und damit, vor allem bei vielen Zeit-Werten, eine potentielle Performancebremse ist. Wer also beim Darstellen des Trends mit diesem Verfahren an die Grenzen stößt, der sollte dann doch mal Dundas ausprobieren, oder auf die nächste Version des SQL Servers (2008) hoffen.</font></font></p>
<p><font color="#0000ff" size="2"><font color="#0000ff" size="2"></font></font></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/reportingservices/trendlinie-in-reporting-services-2005-dank-mdx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

