<?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</title>
	<atom:link href="http://www.ixto.de/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ixto.de/blog</link>
	<description>Business Intelligence, Database Consulting, Software Development</description>
	<lastBuildDate>Fri, 03 Sep 2010 11:25:45 +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>Lookup in Reporting Services – oder: Jetzt kommt zusammen, was zusammen gehört!</title>
		<link>http://www.ixto.de/blog/sql-server-2008/lookup-%e2%80%93-oder-jetzt-kommt-zusammen-was-zusammen-gehort/</link>
		<comments>http://www.ixto.de/blog/sql-server-2008/lookup-%e2%80%93-oder-jetzt-kommt-zusammen-was-zusammen-gehort/#comments</comments>
		<pubDate>Mon, 30 Aug 2010 11:41:55 +0000</pubDate>
		<dc:creator>David Veenhuis</dc:creator>
				<category><![CDATA[Reporting Services 2008]]></category>
		<category><![CDATA[SQL Server 2008]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=122</guid>
		<description><![CDATA[SQL Server 2008 R2 SSRS wartet mit einer interessanten Neuerung auf, nämlich der Suche in Datasets. Damit gibt es Möglichkeiten zwei Datasets in einem Datenbereich zu verknüpfen.
Grundsätzlich gilt: Ein Datenbereich in einem Report kann nur an ein Dataset gebunden sein. Es ist also sinnvoll, alle benötigten Felder bereits vom Datenbankserver in ein Dataset vereinigen zu [...]]]></description>
			<content:encoded><![CDATA[<p>SQL Server 2008 R2 SSRS wartet mit einer interessanten Neuerung auf, nämlich der Suche in Datasets. Damit gibt es Möglichkeiten zwei Datasets in einem Datenbereich zu verknüpfen.</p>
<p>Grundsätzlich gilt: Ein Datenbereich in einem Report kann nur an ein Dataset gebunden sein. Es ist also sinnvoll, alle benötigten Felder bereits vom Datenbankserver in ein Dataset vereinigen zu lassen. Es sind aber auch Situationen denkbar, in denen es nicht möglich ist, die benötigten Felder in ein Dataset zu integrieren (z.B. bei der Nutzung von bereits bestehenden <em>Shared</em><em> Datasets</em> oder bei verschiedenen Quellen). Die Möglichkeiten in einem Datenbereich auf Inhalte eines zweiten Datasets zuzugreifen waren bisher wenig komfortabel. Es gab dazu nur die Funktionen <em>Last</em>, <em>First</em> und die Aggregatfunktionen, die auf das gesamte Ziel-Dataset anzuwenden sind. Ein wahlfreier Zugriff auf eine beliebige Zeile in dem Ziel-Dataset, anhand eines Suchwertes, wurde nicht von SSRS unterstützt. Um das zu erreichen, war es nötig, das komplette Dataset in einem Hashtable zu cachen und dann mittels einer Custom-Code-Funktion den gesuchten Wert zu ermitteln.</p>
<p>Mit der Veröffentlichung von SQL Server 2008 R2 SSRS gibt es dafür jetzt die Lookup-Funktionen. Diese gibt es gleich in drei Versionen: <em>Lookup</em>, <em>LookupSet</em> und <em>MultiLookup</em>.</p>
<p>Die <em>Lookup</em>-Funktion wertet einen Wert (Ausdruck) pro Zeile aus und sucht durch Vergleich mit diesem Wert eine passende Zeile im Ziel-Dataset. <em>LookupSet</em> wertet ebenfalls einen Wert pro Zeile im aktuellen Dataset aus, liefert aber alle passenden Zeilen aus dem Ziel-Dataset. <em>MultiLookup</em> wertet mehrere Werte pro Zeile des aktuellen Datasets aus und liefert alle passenden Zeile aus dem Ziel-Dataset. Konkret wird für jede passende Zeile ein Wert zurückgegeben, der das Ergebnis der Auswertung eines Ausdrucks über die Felder der Zeile ist. Im einfachsten Fall wird der Wert eines der Felder zurückgegeben.</p>
<p>Diese drei Lookup-Funktionen sollen hier demonstriert werden.</p>
<pre><code><span style="font-family: Calibri; font-size: 12pt;"><strong>

Lookup</strong>

				</span></code></pre>
<p><strong>Ein Beispiel für den Einsatz von Lookup:</strong></p>
<p><strong><br />
</strong></p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SSRS_Lookup/Lookup_1.GIF" alt="" /><span style="font-size: 10pt;"> </span><span style="font-family: Times New Roman;"><br />
</span>Der Umsatz pro Mitarbeiter aus Dataset2 soll in der Tabelle  angezeigt werden, die mit Dataset1 verknüpft ist.<br />
<img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SSRS_Lookup/Lookup_2.GIF" alt="" /><span style="font-size: 10pt;"> </span><span style="font-family: Times New Roman;"><br />
</span>Dazu wird ein neues Feld mit einem Ausdruck erstellt. Der hier verwendete Ausdruck lautet: <em>=Lookup(Fields!MitarbeiterID.Value, Fields!PersonalID.Value, Fields!Umsatz.Value, &#8220;DataSet2&#8243;)</em></p>
<ul>
<li><em>Der erste Parameter, <em>Fields!MitarbeiterID.Value</em>, ist ein Feld der Tabelle (Datenbereichs), die an Dataset1 gebunden ist. Es ist aber auch möglich einen Ausdruck zu verwenden, um z.B. mehrere Felder zu konkatenieren, wenn der Vergleich mit den Zeilen im Ziel-Dataset mehrere Spalten berücksichtigen soll.</em></li>
<li><em>Der zweite Parameter ,<em> Fields!PersonalID.Value</em> , ist ein Feld aus dem Dataset2, in dem nach einer passenden Zeile gesucht werden soll. Es kann auch ein Ausdruck verwendet werden. Wie bei einem <em>Join</em> wird verglichen ob dieser Wert mit dem Suchwert (der erste Parameter) übereinstimmt.</em></li>
<li><em>Der dritte Parameter, <em>Fields!Umsatz.Value</em> , gibt den Rückgabewert der Funktion an. Auch hier kann anstelle eines Feldes ein Ausdruck angegeben werden. Bei <em>Lookup</em> wird der Rückgabewert aus der ersten Zeile ermittelt, bei der die Suche erfolgreich war. Gibt es keine Zeile, die die Bedingung erfüllt, liefert der <em>Lookup</em>-Aufruf <em>Nothing</em> zurück.</em></li>
<li><em>Der vierte Parameter benennt das Ziel-Dataset (hier Dataset2), in dem ein passender Wert gesucht wird.</em></li>
</ul>
<p><em><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SSRS_Lookup/Lookup_3.GIF" alt="" /> <code><span style="font-family: Calibri;"> </span></code></em><br />
Die mit Dataset1 verbundene Tabelle enthält jetzt die gewünschten Werte aus DataSet2.</p>
<p><code><span style="font-family: Calibri; font-size: 12pt;"><em><em><strong> </strong></em></em><strong>LookupSet</strong><em><em><strong> </strong></em></em></span></code><code><em><em> <span style="font-family: Calibri; font-size: 12pt;"> </span></em></em><span style="font-family: Calibri; font-size: 12pt;"> </span></code> Bei der <em>Lookup</em>-Funktion wird wie bereits beschrieben nur die erste Zeile berücksichtigt, auf die der Suchwert passt. <em>LookupSet</em> wertet immer alle Zeilen des Ziel-Datasets aus und liefert für jede passende Zeile einen Wert zurück. <em>LookupSet</em> gibt diese Werte in Form eines Array zurück. Dieses Array kann nicht direkt als Ausgabe eines Textfeldes verwendet werden. Es muss also eine Bearbeitung z.B. mit der VB-Funktion <em>Join</em> erfolgen wodurch aus dem Array ein anzeigefähiger Wert wird. Das Array kann auch als Argument für eine Custom-Code-Funktion verwendet werden, um einen Anzeigewert zu bestimmen.</p>
<pre><code><span style="font-family: Calibri; font-size: 12pt;"><em><em><strong>
</strong></em></em>

<strong>Beispiel für die Verwendung von LookupSet</strong><em><em><strong>

</strong></em></em></span></code></pre>
<p> </p>
<p><em><em><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SSRS_Lookup/LookupSet_1.GIF" alt="" /><br />
<span style="font-family: Calibri;"><em>=Join(LookupSet(Fields!ProductCategoryID.Value, Fields!ProductCategoryID.Value, Fields!Name.Value, &#8220;DataSet2&#8243;),&#8221;, &#8220;)<br />
</em></span></em></em></p>
<pre><code><span style="font-family: Calibri;"><span style="font-size: 12pt;"><em><em>					</em></em></span></span></code></pre>
<pre><code><span style="font-family: Calibri; font-size: 12pt;">Zu Jeder Zeile in DataSet1 werden alle passenden Zeilen aus DataSet2 gesucht. Join wandelt das Ergebnis-Array in einen String um, der anschließend im Feld Subcategory zu sehen ist.<em><em>
</em></em></span></code></pre>
<p><em><em><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SSRS_Lookup/LookupSet_2.GIF" alt="" /></em></em></p>
<pre><code><span style="font-family: Calibri;"><em><em>Zu Jeder <em>ProductCategory</em> sind nun alle <em>Subcategories</em> in einem Feld zu sehen.
</em></em></span></code></pre>
<p> </p>
<pre><code><span style="font-family: Calibri; font-size: 12pt;">

<em><em><strong>

</strong></em></em><strong>MultiLookup</strong><em><em><strong>
</strong></em></em></span></code></pre>
<p> </p>
<pre><code><span style="font-family: Calibri; font-size: 12pt;">MulitLookup nimmt keinen einzelnen Wert sondern ein Array von Suchwerten pro Zeile. Ein Aufruf von MultiLookup wird dann so durchgeführt, dass für jedes Element des Suchwerte-Arrays ein gesonderter Lookup-Aufruf durchgeführt wird. Die Ergebnisse der einzelnen Lookup's werden dann dem Ergebnis-Array zugefügt.
</span></code></pre>
<pre><code><span style="font-family: Calibri; font-size: 12pt;">Ein Mehrwertiger Parameter kann direkt als Suchwert verwendet werden. Ein String, der eine Liste von Werten enthält, muss erst in ein Array umgewandelt werden. Dazu eignet sich die VB-Funktion Split.
</span></code></pre>
<pre><code><span style="font-family: Calibri; font-size: 12pt;"><strong>Beispiel:</strong> Ein Mehrwertiger Parameter enthält mehrere Monate, die als Auflistung von Zahlwerten angegeben sind. Mithilfe eines Aufrufes der Funktion MultiLookup werden die Zahlwerte in den
jeweiligen Monatsnamen umgewandelt. Dabei wird das Dataset Monatsnamen als Ziel-Dataset für die Suche verwendet.<em><em>
</em></em></span></code></pre>
<p><em><em><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SSRS_Lookup/MultiLookup_1.GIF" alt="" /></em></em></p>
<p><em><em><br />
<img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SSRS_Lookup/MultiLookup_2.GIF" alt="" /><code><span style="font-family: Calibri;"> </span></code></em></em><br />
Anzeige der Parameterwerte in einem Textfeld mit dem Ausdruck <em>=Join(Parameters!Monate.Value,&#8221;, &#8220;)</em></p>
<p><em><em><code><span style="font-family: Calibri;"><em><br />
</em></span></code><br />
<img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SSRS_Lookup/MultiLookup_3.GIF" alt="" /><br />
</em></em>Anzeige der Werte nach Änderung des Ausdrucks auf <em>=Join(MultiLookup(Parameters!Monate.Value, Fields!MonatNr.Value,Fields!MonatName.Value,&#8221;Monatsnamen&#8221;),&#8221;, &#8220;)</em></p>
<p><span style="font-family: Calibri;"><em><em><em><br />
</em></em></em></span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2008/lookup-%e2%80%93-oder-jetzt-kommt-zusammen-was-zusammen-gehort/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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:</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0021.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002[1]" border="0" alt="clip_image002[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0021_thumb.jpg" width="244" height="115" /></a></p>
<p>&#160;</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>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0041.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image004[1]" border="0" alt="clip_image004[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0041_thumb.jpg" width="244" height="113" /></a></p>
<p>&#160;</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>&#160;</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>
<p>&#160;</p>
<p> <font color="#000000" size="2" face="Courier New">
<p align="left"></p>
<p>   <font color="#0000ff" size="2" face="Courier New">UPDATE</font><font color="#000000" size="2" face="Courier New"> dbo</font><font color="#808080" size="2" face="Courier New">.</font><font color="#000000" size="2" face="Courier New">FactResellerSales</font>
<p align="left"></p>
<p>   <font color="#0000ff" size="2" face="Courier New">SET</font><font color="#000000" size="2" face="Courier New"> DiscountAmount </font><font color="#808080" size="2" face="Courier New">=</font><font color="#000000" size="2" face="Courier New"> </font><font color="#808080" size="2" face="Courier New">NULL</font>
<p align="left"></p>
<p>   <font color="#0000ff" size="2" face="Courier New">WHERE</font><font color="#000000" size="2" face="Courier New"> DiscountAmount </font><font color="#808080" size="2" face="Courier New">=</font><font color="#000000" size="2" face="Courier New"> 0</font></font>
<p>&#160;</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>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0061.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image006[1]" border="0" alt="clip_image006[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0061_thumb.jpg" width="182" height="244" /></a></p>
<p>&#160;</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>
<p>&#160;</p>
<p> <font color="#800000" size="2" face="Courier New"><font color="#000000" size="2" face="Courier New">
<p align="left"></p>
<p>     <font color="#800000" size="2" face="Courier New">SP_REFRESHVIEW</font><font color="#000000" size="2" face="Courier New"> </font><font color="#ff0000" size="2" face="Courier New">N’dbo.v_FactResellerSales’</font><font color="#808080" size="2" face="Courier New">;</font>
<p align="left"></p>
<p>   </font>
<p align="left">&#160;</p>
<p align="left">
<p> 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:</font>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0081.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image008[1]" border="0" alt="clip_image008[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0081_thumb.jpg" width="244" height="236" /></a></p>
<p>&#160;</p>
<p>Dann gibt es eine Eigenschaft AllowNull, die leider immer noch auf False stand. Und </p>
<p>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>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0101.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image010[1]" border="0" alt="clip_image010[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0101_thumb.jpg" width="244" height="215" /></a></p>
<p>&#160;</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>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0121.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image012[1]" border="0" alt="clip_image012[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0121_thumb.jpg" width="244" height="216" /></a></p>
<p>&#160;</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>&#160;</p>
<p>Die nun folgende manuelle Aufbereitung war wohl die leichteste Übung, und endlich:</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0141.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image014[1]" border="0" alt="clip_image014[1]" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/AnalysisServicesunddasnachtrglicheErlaub_11BCD/clip_image0141_thumb.jpg" width="208" height="106" /></a></p>
<p>&#160;</p>
<p>Ich bin die 0en los!</p>
]]></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>0</slash:comments>
		</item>
		<item>
		<title>MS-DOS lebt – im ForEachLoop-SSIS Container!</title>
		<link>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/ms-dos-lebt-%e2%80%93-im-foreachloop-ssis-container-2/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/ms-dos-lebt-%e2%80%93-im-foreachloop-ssis-container-2/#comments</comments>
		<pubDate>Thu, 29 Apr 2010 21:32:12 +0000</pubDate>
		<dc:creator>Chris Jacob</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>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=91</guid>
		<description><![CDATA[Wer hätte gedacht dass man heutzutage noch über die Vermächtnisse einer 20 Jahre alten Software stolpern kann – und das in den Integration Services!
Aber beginnen wir von vorne: immer wenn die Bearbeitung mehrere gleichartiger Dateien mittels SSIS gefragt ist, kommt früher oder später der ForEach-Loop-Container zum Einsatz. Damit lässt sich z.B. recht komfortabel über Dateien [...]]]></description>
			<content:encoded><![CDATA[<p>Wer hätte gedacht dass man heutzutage noch über die Vermächtnisse einer 20 Jahre alten Software stolpern kann – und das in den Integration Services!</p>
<p>Aber beginnen wir von vorne: immer wenn die Bearbeitung mehrere gleichartiger Dateien mittels SSIS gefragt ist, kommt früher oder später der ForEach-Loop-Container zum Einsatz. Damit lässt sich z.B. recht komfortabel über Dateien mit einer bestimmten Namensstruktur innerhalb eines Ordners iterieren. So könnte ein mögliches Importszenario vorsehen, dass mehrere Exceldateien in einem Ordner ausgelesen werden sollen – den ForEach-Loop-Container könnte man dann wie folgt konfigurieren:</p>
<p>Soweit so gut, der Rest des Paketes könnte dann wie folgt aussehen. Innerhalb des Loops wird eine Variable mit dem aktuellen Dateipfad ausgelesen um alle gefundenen Dateien nach Beendigung des Containers in einer MessageBox anzuzeigen:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/042910_2132_MSDOSlebti2.png" alt="" /></p>
<p>Ich habe bisher den Inhalt des betroffenen Ordners unterschlagen, hier ist er:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/042910_2132_MSDOSlebti3.png" alt="" /></p>
<p>Und siehe da: unser Paket findet zwei Exceldateien – wunderbar! Oder doch nicht? Störend an dieser Stelle könnte die Excel-Datei sein, die im neuen 2007er Format gespeichert wurde. Diese hat die Endung .xlsx! Eigentlich ganz praktisch, denn die beiden Exceltypen unterscheiden sich grundlegend und erfordern ggf. eine differenzierte Behandlung innerhalb der SSIS. Weitere prüfende Blicke in die Konfiguration des ForEach-Loops lassen letztlich nur einen Schluss zu: egal wie man es dreht und wendet, der Ausdruck im &#8220;Files&#8221;-Feld des Editors lässt sich nicht dahingehend ändern dass er nur .xls Dateien erwischt (was man eigentlich erwarten würde) – der Ausdruck verhält sich also wie *.xls*!</p>
<p>An dieser Stelle wirken die Books Online einmal mehr erhellend und decken auf, dass es sich quasi um erwünschtes Verhalten handelt – der Ausdruck verhält sich nämlich wie beim dir-Befehl in Windows (siehe: <a href="http://msdn.microsoft.com/en-us/library/ms187670.aspx">http://msdn.microsoft.com/en-us/library/ms187670.aspx</a>). Dieser wiederum ist aus Kompatibilitätsgründen so gestrickt, dass er nur drei Zeichen der Dateinamenerweiterung betrachtet – die gute alte 8.3-Dateinamenbeschränkung aus MS-DOS Zeiten schlägt hier also wieder einmal zu!</p>
<p>Eine Differenzierung nach Dateierweiterung muss also später geschehen, die könnte dann z.B. so aussehen: innerhalb des ForEach-Loop-Containers fügen wir eine Rangfolgeeinschränkung (zu deutsch: einen Pfeil) ein und binden daran eine SSIS-Expression. Diese prüft, ob die letzten drei Buchstaben des ausgelesenen Dateinamens auch tatsächlich x, l und s sind:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/042910_2132_MSDOSlebti4.png" alt="" /></p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/042910_2132_MSDOSlebti5.png" alt="" /></p>
<p>So modifiziert, verrichtet das Paket ordnungsgemäß seinen Dienst und findet tatsächlich nur eine Excel-Datei:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/042910_2132_MSDOSlebti6.png" alt="" /></p>
<p>Da kann man sich natürlich schon fragen ob es sich um ein Bug oder ein Feature handelt, aber genau wegen diesen Ecken und Kanten lieben wir die Integration Services so sehr – man entdeckt eben immer wieder etwas Neues!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/ms-dos-lebt-%e2%80%93-im-foreachloop-ssis-container-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Codeplex Perlen &#8211; heute: Enhanced SSIS Execute Package Task</title>
		<link>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/codeplex-perlen-heute-enhanced-ssis-execute-package-task/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/codeplex-perlen-heute-enhanced-ssis-execute-package-task/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 13:33:26 +0000</pubDate>
		<dc:creator>Chris Jacob</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>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=81</guid>
		<description><![CDATA[Divide et impera – das von Machiavelli vor gut 500 Jahren geprägte Prinzip des Teilen und Herrschens ist heutzutage eine allseits beliebte Technik zur Problemlösung. Auch in den Integration Services finden sich eine Menge Möglichkeiten, um große Aufgaben in kleinere, übersichtliche Schritte zu unterteilen. Beispiele sind unterschiedliche Datenflüsse für unterschiedliche Aufgaben, die Strukturierung mittels Sequenzcontainern [...]]]></description>
			<content:encoded><![CDATA[<p>Divide et impera – das von Machiavelli vor gut 500 Jahren geprägte Prinzip des Teilen und Herrschens ist heutzutage eine allseits beliebte Technik zur Problemlösung. Auch in den Integration Services finden sich eine Menge Möglichkeiten, um große Aufgaben in kleinere, übersichtliche Schritte zu unterteilen. Beispiele sind unterschiedliche Datenflüsse für unterschiedliche Aufgaben, die Strukturierung mittels Sequenzcontainern und nicht zuletzt die Möglichkeit, aus einem SSIS Paket andere SSIS Pakete aufzurufen.
</p>
<p>Doch mit steigender Komplexität der Pakete (Verbindungsmanager, Paketvariablen) und ausgiebiger Nutzung der Paketkonfiguration gelangt man mit den SSIS-Bordmitteln einmal mehr an die Grenzen des Wartbaren. Die Integration Services bieten von Haus aus die Möglichkeit, andere SSIS Pakete aufzurufen, doch die Übergabe von Variablen und Verbindungsmanagern an das &#8220;Kindpaket&#8221; gestaltet sich sehr aufwändig (viel Expression-Hacking). Die Möglichkeit, Rückgabewerte vom Kindpaket zu empfangen fehlt gar gänzlich.
</p>
<p>In diese Nische stürzt sich ein Codeplex-Projekt, welches ich im Folgenden kurz vorstellen möchte: der &#8220;Enhanced SSIS Execute Package Task&#8221;. Unter <a href="http://ssisexec.codeplex.com/">http://ssisexec.codeplex.com/</a> ist das noch recht unbekannte Projekt zu finden (derzeit für SSIS 2005 und SSIS 2008 R2 – siehe &#8220;Downloads&#8221;). Hilfreich bei der Installation (es wird eine dll und ein schmales readme geliefert) ist folgender Eintrag in den Books Online: <a href="http://msdn.microsoft.com/en-us/library/ms403356.aspx">http://msdn.microsoft.com/en-us/library/ms403356.aspx</a> Hat man die Komponente erfolgreich installiert lässt sie sich über einen Rechtsklick in die Toolbox -&gt; Choose Items in die Liste der Kontrollfluss Tasks aufnehmen.
</p>
<p>
<img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/enhanced_1.png" alt="" />
	</p>
<p>Die Komponente bietet eine grafische Oberfläche zum Mappen der Variablen bzw. Verbindungsmanagern zwischen den Paketen. Diese können entweder im Dateisystem oder in der MSDB serverseitig gespeichert sein. Somit lassen sich recht schnell und komfortabel Konfigurationen zwischen Paketen übergeben. Wie das aussehen könnte sieht man in folgendem screenshot: Hier wird von einem Steuerpaket, welches den Pfad zu einer Exceldatei via Paketkonfiguration erhält, ein Kindpaket aufgerufen wobei der Verbindungsmanager zwischen den Paketen übergeben wird.
</p>
<p>
<img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/enhanced_2.png" alt="" />
	</p>
<p><strong>Hinweis:</strong> Das Projekt hat derzeit noch den <strong>Alpha-Status</strong> – vom Einsatz in einer Produktivumgebung rate ich also dringend ab! Laut Aussage des Authors scheint es aber stabil zu laufen und dieser freut sich mit Sicherheit über ausgiebiges feedback in Form von Kommentaren oder Anmerkungen. In diesem Sinne: happy testing!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/codeplex-perlen-heute-enhanced-ssis-execute-package-task/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Excel und führende Nullen vs. SSIS</title>
		<link>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/excel-und-fuhrende-nullen-vs-ssis/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/excel-und-fuhrende-nullen-vs-ssis/#comments</comments>
		<pubDate>Sat, 27 Feb 2010 08:03:47 +0000</pubDate>
		<dc:creator>Chris Jacob</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>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=79</guid>
		<description><![CDATA[Wer kennt sie nicht: die Problematik der führenden Nullen in Excel. Um beispielsweise Postleitzahlen mit führenden Nullen korrekt darzustellen, bedarf es in aller Regel Einiges an Formatierungsaufwand, da Excel Zahlen gerne als numerischen Wert interpretiert. Befüllt man nun mit den SSIS ein Excel-Ziel, gehen führende Nullen beim ersten Öffnen der Excel-Mappe verloren, ganz gleich ob [...]]]></description>
			<content:encoded><![CDATA[<p>Wer kennt sie nicht: die Problematik der führenden Nullen in Excel. Um beispielsweise Postleitzahlen mit führenden Nullen korrekt darzustellen, bedarf es in aller Regel Einiges an Formatierungsaufwand, da Excel Zahlen gerne als numerischen Wert interpretiert. Befüllt man nun mit den SSIS ein Excel-Ziel, gehen führende Nullen beim ersten Öffnen der Excel-Mappe verloren, ganz gleich ob man z.B. eine Spalte PLZ als Text oder Zahl durchleitet.</p>
<p>Abhilfe schafft hier ein kleiner Trick, der in den screenshots unten zu sehen ist. Mittels des Tasks &#8220;Abgeleitete Spalte&#8221; erstellt man eine neue Textspalte, deren Inhalt die Spalte mit den führenden Nullen eingebettet in Hochkommata und ein vorangestelltes Gleichheitszeichen ist (Escape-Sequenz beachten!).</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/030110_0803_Excelundfhr1.png" alt="" /></p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/030110_0803_Excelundfhr2.png" alt="" /></p>
<p>Als Resultat interpretiert Excel fortan den Wert in der Spalte als Formel und die führende Null wird korrekt dargestellt.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/excel-und-fuhrende-nullen-vs-ssis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Totgesagte leben länger – PerformancePoint Services in SharePoint 2010</title>
		<link>http://www.ixto.de/blog/sharepoint-2010/totgesagte-leben-langer-%e2%80%93-performancepoint-services-in-sharepoint-2010/</link>
		<comments>http://www.ixto.de/blog/sharepoint-2010/totgesagte-leben-langer-%e2%80%93-performancepoint-services-in-sharepoint-2010/#comments</comments>
		<pubDate>Fri, 15 Jan 2010 13:28:59 +0000</pubDate>
		<dc:creator>Stefanie Arndt</dc:creator>
				<category><![CDATA[PerformancePoint Services]]></category>
		<category><![CDATA[SharePoint 2010]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/sharepoint-2010/totgesagte-leben-langer-%e2%80%93-performancepoint-services-in-sharepoint-2010/</guid>
		<description><![CDATA[Der PerformancePoint Server ist tot – lang leben die PerformancePoint Services! Anfang dieses Jahres kündigte Microsoft die Zusammenführung vom PerformancePoint Server mit dem Microsoft SharePoint Server Enterprise an (zur Microsoft Pressemitteilung).
Mit SharePoint 2010 am Horizont und den Vorbereitungen zum Office 2010 Release, hat sich nun auch für PerformancePoint einiges getan. Bevor wir uns aber damit [...]]]></description>
			<content:encoded><![CDATA[<p>Der PerformancePoint Server ist tot – lang leben die PerformancePoint Services! Anfang dieses Jahres kündigte Microsoft die Zusammenführung vom PerformancePoint Server mit dem Microsoft SharePoint Server Enterprise an (<a href="http://www.microsoft.com/presspass/features/2009/jan09/01-27KurtDelbeneQA.mspx">zur Microsoft Pressemitteilung</a>).</p>
<p>Mit SharePoint 2010 am Horizont und den Vorbereitungen zum Office 2010 Release, hat sich nun auch für PerformancePoint einiges getan. Bevor wir uns aber damit beschäftigen, was neu und aufregend an den PerformancePoint Services für SharePoint 2010 ist, werfen wir einen Blick darauf, was PerformancePoint ist und warum es für Sie wichtig ist.</p>
<p><strong>Die Definition<br />
</strong></p>
<p>Die PerformancePoint Services ermöglichen das Erstellen von aussagekräftigen Dashboards mit aggregierten Daten und Inhalten, die Ihnen eine vollständige Sicht auf Ihr Unternehmen und dessen Entwicklung in allen Ebenen geben.</p>
<p>Die Blitzvorstellung der PerformancePoint Services wäre daher, dass sie der einfachste Weg sind, um in SharePoint 2010 Business Intelligence Dashboards zu erstellen und bereitzustellen.</p>
<p>Die Idee des Dashboards (dt.: Armaturenbrett) kommt tatsächlich daher, wo Sie es vermuten würden. Es ist die Anzeige des Piloten Cockpits, das Armaturenbrett im Auto… im Wesentlichen also wie eine jede Aktivität kontrolliert und bewertet werden kann – sei es das Fahren eines Formel 1 Wagens oder das Führen eines erfolgreichen mittelständischen Unternehmens.</p>
<p>In einem jeden Unternehmen bedeutet das Kontrollieren des unternehmerischen Erfolgs der Zugang zu Daten. SharePoint 2010 bietet viele Technologien zur Datenauswertung, aber PerformancePoint lebt und atmet Daten. Wir ersetzen die Tankanzeige und den Tacho durch KPIs, Scorecards und Datenvisualisierung, und ermöglichen Ihnen auf diese Art den Einstieg in die Daten und die Beantwortung Ihrer Fragen.</p>
<p><strong>Die Praxis<br />
</strong></p>
<p>Nach diesem Vertriebs-Kauderwelsch soll es nun darum gehen, woraus die PerformancePoint Services gemacht sind und wie Sie diese für sich nutzen können. Die PerformancePoint Services sind ein Teil von SharePoint 2010 geworden und tauchen dort als Webpartseite auf, wo es versierte SharePoint Benutzer erwarten würden. Das Ganze kommt in zwei Teilen.</p>
<p>Die PerformancePoint Services beginnen als Autorenerlebnis. Der Dashboard Designer ist ein Werkzeug zum &#8220;bottom-up&#8221;-Modellieren: Key Performance Indicators (KPIs), Scorecards, grafische Analysen und Diagramme, Reports, Filter und Dashboards. Jedes dieser Elemente ist einzigartig für PerformancePoint Services und bringt Funktionalität mit, die zusammen mit der Serverkomponente die schwierigen Teile erledigt &#8211; wie Datenverbindung und Sicherheit.</p>
<p>Der Dashboard Designer funktioniert nach dem WYSIWYG-Prinzip. Die einzelnen Elemente werden genau so im Browser dargestellt, wie sie erstellt wurden. Das bringt uns zum zweiten Teil, dem Anwendererlebnis. Die PerformancePoint Services wurden unter dem Gedanken des gemeinsamen Benutzens und Austauschens entwickelt. Die erstellten Elemente werden in einem Dashboard zusammengepackt und auf einer SharePoint Seite angezeigt, die regelt, wer was sehen darf. Das bedeutet, Sie entwerfen und publizieren, was die Anwender benutzen… ohne IT, ohne komplizierte Workflows.</p>
<p><a href="http://blogs.msdn.com/performancepoint/archive/2009/10/20/what-is-performancepoint-services-for-sharepoint-2010.aspx">Link zum englischen Original Blogeintrag</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sharepoint-2010/totgesagte-leben-langer-%e2%80%93-performancepoint-services-in-sharepoint-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Was gibt es neues beim SQL Server 2008 R2 SSRS</title>
		<link>http://www.ixto.de/blog/sql-server-2008/was-gibt-es-neues-beim-sql-server-2008-r2-ssrs/</link>
		<comments>http://www.ixto.de/blog/sql-server-2008/was-gibt-es-neues-beim-sql-server-2008-r2-ssrs/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 22:24:02 +0000</pubDate>
		<dc:creator>Sven Bayer</dc:creator>
				<category><![CDATA[Reporting Services 2008]]></category>
		<category><![CDATA[SQL Server 2008]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/sql-server-2008/was-gibt-es-neues-beim-sql-server-2008-r2-ssrs/</guid>
		<description><![CDATA[Die November CTP des SLQ Server 2008 R2 steht seit einiger Zeit zum Download bereit und bietet zahlreiche neue Features. In diesem Artikel sollen die zahlreichen Neuerungen, die die Reporting Services erhalten haben, beschrieben werden. Wir beschränken uns auf die Features, die unmittelbar mit der Entwicklung der Berichte zu tun haben und lassen die Änderungen, [...]]]></description>
			<content:encoded><![CDATA[<p>Die November CTP des SLQ Server 2008 R2 steht seit einiger Zeit zum Download bereit und bietet zahlreiche neue Features. In diesem Artikel sollen die zahlreichen Neuerungen, die die Reporting Services erhalten haben, beschrieben werden. Wir beschränken uns auf die Features, die unmittelbar mit der Entwicklung der Berichte zu tun haben und lassen die Änderungen, die bezüglich der erweiterten Sharepoint Integration vorhanden sind, außen vor. Der Report Manager hat ein neues Äußeres bekommen und der Report Builder steht jetzt in Version 3.0 zur Verfügung, die auch benötigt wird, um mit den neuen Features arbeiten zu können:</p>
<h3>Freigegebene Data Sets</h3>
<p>Genau wie freigegebene Datenquellen, die in jedem größerem Projekt verwendet werden, um Änderungen an der Datenquelle an zentraler Stelle zu realisieren, können jetzt auch Data Sets freigegeben werden und in einem geeigneten Ordner auf dem Server zu speichern. Freigegebene Data Sets können von allen Berichten verwendet werden, so können Sie z.B. für einen Parameter, der in mehreren Berichten vorkommt, ein Data Set anpassen, dieses freigeben und es dann auch in den anderen Berichten verwenden.<br />
Mit dem Report Builder können Sie alle freigegebenen Data Sets auf dem Server verwenden, mit dem BIDS hingegen können Sie nur die freigegebenen Data Sets ihres Projekts verwenden.</p>
<h3>Report Part Gallery</h3>
<p>Seit der November CTP ist es möglich Teile eines Berichts zu veröffentlichen. Diese Report Parts können dann in anderen Berichten verwendet werden. Im Gegensatz zu den freigegebenen Data Sets, können Report Parts in einem neuen Bericht weiter angepasst werden, ohne dass die Vorlage davon beeinflusst wird. Ein Report Part wird sozusagen ein normales Berichtselement im neuen Report. Falls das Original aktualisiert wurde, wird Ihnen dies mitgeteilt, damit Sie Ihre verwendeten Elemente aktualisieren können.<br />
Beim Hinzufügen eines Report Parts werden automatisch die zugehörigen Data Sets und Datenquellen mit angelegt.<br />
Report Parts können sowohl mit dem BIDS, als auch mit dem Report Builder erstellt werden. Sie können aber zurzeit nur mit dem Report Builder verwendet werden, indem Sie einfach per Drag&amp;Drop aus der Report Part Gallery in den Bericht gezogen werden.</p>
<p>Folgende Elemente stehen zur Verfügung:</p>
<ul>
<li>Charts</li>
<li>Tabellen, Matrizen und Listen</li>
<li>Messgeräte</li>
<li>Maps</li>
<li>Bilder</li>
<li>Rectangles</li>
</ul>
<h3>Neue Berichtselemente zur Datenvisualisierung</h3>
<p>Die neuen Berichtselemente sind speziell konzipiert worden, um in Tabellen und Matrizen eingesetzt zu werden.</p>
<h3><font color="#999999">Sparklines und Data Bars</font></h3>
<p>Sparklines und Data Bars sind einfache Charts, die nur die wesentlichen Elemente beinhalten und gänzlich auf Legenden, Achsen und Beschriftungen verzichten. Sie werden in erster Linie in Tabellen und Matrizen verwendet, um viel Information auf möglichst geringem Raum zu repräsentieren.<br />
Typischerweise zeigen Data Bars nur einen Wert pro Zeile an, um den Vergleich der Werte untereinander zu vereinfachen:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/122309_2210_Wasgibtesne2.png" /></p>
<p>Im Gegensatz zu den Sparklines, die normalerweise den zeitlichen Verlauf wiederspiegeln:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/122309_2210_Wasgibtesne3.png" /></p>
<p>Bei den Sparklines wäre noch anzumerken, dass sie nur in Gruppen- und nicht in Detailzeilen verwendet werden können.</p>
<h3><font color="#999999">Indikatoren</font></h3>
<p>Indikatoren werden verwendet, um den Status eines Wertes auf den ersten Blick erkennen zu können. Sie werden häufig in Tabellen und Matrizen eingesetzt. Ein Indikator ist ein vereinfachtes Messgerät und kann auch in eben dieses umgewandelt werden. Sie können Trends anhand von Pfeilen, Abstimmungen durch Sterne und Status durch Bilder wie z.B. der Ampel darstellen:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/122309_2210_Wasgibtesne4.png" /></p>
<h3>Erweiterungen der RDL Ausdruckssprache</h3>
<h3><font color="#999999">Aggregationen von Aggregationen</font></h3>
<p>In der aktuellen Version ist es endlich möglich Ausdrücke zu verwenden, die Aggregationen von Aggregationen bilden. Dadurch können Werte, wie z.B. der Durchschnitt der monatlichen Einnahmen gebildet werden.<br />
<span style="font-family: Courier New">=Avg(Sum(Fields!Reseller_Sales_Amount.Value, &#8220;Month&#8221;),&#8221;Year&#8221;)</span><strong><br />
</strong></p>
<h3><font color="#999999">OverallPageNumber und OverallTotalPages</font></h3>
<p>Zeigt die Gesamtseitenzahl und die aktuelle Seitenzahl bezogen auf das gesamte Dokument. Im Gegensatz zu den schon bekannten Feldern <span style="font-family: Courier New">PageNumber</span> und <span style="font-family: Courier New">TotalPages</span>, die die Seitenzahlen abhängig von einer Sequenz angeben(die Seitenzahlen können durch ein PageBreak zurückgesetzt werden). Diese Eigenschaften können nur im Seitenkopf oder –fuß verwendet werden.</p>
<h3><font color="#999999">RenderFormat</font></h3>
<p>Eine weitere neue, in meinen Augen sehr nützliche Eigenschaft, ist die Globale <span style="font-family: Courier New">RenderFormat</span>. Zum Einen kann der Name durch <span style="font-family: Courier New">Globals!RenderFormat.Name</span> ermittelt werden und zum Anderen, mit der Expression <span style="font-family: Courier New">=Globals!RenderFormat.IsInteractive,</span> ob es sich um ein interaktives Ausgabeformat handelt.</p>
<p>Durch die Möglichkeit das Ausgabeformat zu ermitteln ergeben sich ganz neue Gestaltungsmöglichkeiten. So können für ein Excel-Export z.B. Spalten einer Tabelle ein- oder ausgeblendet werden. Es können Abhängig vom Ausgabeformat komplett unterschiedliche Elemente angezeigt werden.<br />
Bei nicht interaktiven Formaten können, durch den Drilldown versteckte Elemente, sichtbar gemacht werden.</p>
<h3><font color="#999999">PageName</font></h3>
<p>Endlich können Excelsheets einer Excel-Datei mit Namen versehen werden. Dafür müssen Sie einfach den PageName angeben. Wenn Sie den PageName dynamisch vergeben und den Gruppennamen verwenden für den ein PageBreak existiert, bekommt jedes Excelsheet den Namen der Gruppe.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/122309_2210_Wasgibtesne5.png" /></p>
<p>Mit der Eigenschaft PageBreak/Disabled kann z.B., abhängig vom RenderFormat, der Seitenumbruch deaktiviert werden.</p>
<h3>Maps</h3>
<p>Was man in früheren Versionen der Reporting Services von Drittanbietern kaufen musste, wurde in der aktuellen Version integriert. Dieses neue Berichtselement dient zur Visualisierung von Daten abhängig von ihrer geographischen Lage. Es stehen eine Vielzahl von Karten in der Kartengalerie zur Verfügung (zurzeit, wohl aus rechtlichen Gründen, nur Karten der USA). Falls Sie eine andere Karte benötigen, können auch ESRI-Shapefiles oder SQL Spatial Datentypen verwendet werden. Sie können hinter Ihre Karte noch eine Bing Karte legen, um die Darstellung noch etwas aufzuwerten. Folgende Kartenvisualisierungen stehen zur Verfügung:</p>
<ul>
<li><strong>Basic Map (Basis Karte)</strong> – Es werden einfach nur Gebiete angezeigt. So können z.B. Ihre Verkaufsgebiete angezeigt werden.</li>
<li><strong>Color Analytical Map (Farbanalytische Karte) </strong>– Informationen werden durch Farbvariationen hervorgehoben. Z.B. werden die Verkaufszahlen pro Gebiet farblich gekennzeichnet.</li>
<li><strong>Bubble Map (Blasen Karte)</strong> – Informationen werden durch die Größe der Blasen angezeigt. Die Blasen liegen zentriert in den zugehörigen Gebieten.</li>
</ul>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/122309_2210_Wasgibtesne6.png" /></p>
<h3><font color="#000000">Report Viewer</font></h3>
<p>Der neue Report Viewer verwendet AJAX für die Seitennavigation und die Interaktivität. So wird beim Öffnen eines Drilldowns die aktuelle Scrollposition beibehalten.<br />
Das Aussehen wurde angepasst und optimiert, um mehr Platz für den Bericht zu haben.</p>
<h3></h3>
<p>Wir konnten natürlich nur einen kurzen Überblick über die neuen Features der Reporting Services des SQL Server 2008 R2 geben und werden daher in den nächsten Blogeinträgen gezielt und detailliert einzelne der oben genannten Features beschreiben.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2008/was-gibt-es-neues-beim-sql-server-2008-r2-ssrs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SSAS 2005 MDX Tuning – unnötige MEMBER und fast noch schlimmer: STRTOMEMBER</title>
		<link>http://www.ixto.de/blog/sql-server-2005/ssas-2005-mdx-tuning-%e2%80%93-unnotige-member-und-fast-noch-schlimmer-strtomember/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/ssas-2005-mdx-tuning-%e2%80%93-unnotige-member-und-fast-noch-schlimmer-strtomember/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 16:29:55 +0000</pubDate>
		<dc:creator>Marcel Ebner</dc:creator>
				<category><![CDATA[Analysis Services 2005]]></category>
		<category><![CDATA[SQL Server 2005]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/sql-server-2005/ssas-2005-mdx-tuning-%e2%80%93-unnotige-member-und-fast-noch-schlimmer-strtomember/</guid>
		<description><![CDATA[&#8220;Das beste MDX ist das, das man nicht schreibt&#8221; (über den Buschfunk: Mosha Pasumansky)
Aber wer kommt denn auf die Idee, dass dieses Zitat wortwörtlich zu nehmen ist?
Ich sah mich mit einer Kundendimension von 172.000 Kunden konfrontiert, die etwa 200 Vertretern zugeordnet waren. Ergebnis der Abfrage sollten die Kunden sein, die in einem gewissen Monat keine [...]]]></description>
			<content:encoded><![CDATA[<p>&#8220;Das beste MDX ist das, das man nicht schreibt&#8221; (über den Buschfunk: Mosha Pasumansky)</p>
<p>Aber wer kommt denn auf die Idee, dass dieses Zitat wortwörtlich zu nehmen ist?</p>
<p>Ich sah mich mit einer Kundendimension von 172.000 Kunden konfrontiert, die etwa 200 Vertretern zugeordnet waren. Ergebnis der Abfrage sollten die Kunden sein, die in einem gewissen Monat keine Umsätze, dafür aber im Rest des Jahres Umsätze erzielt hatten. Übersetzt in den AdventureWorks Cube, wobei der Vertreter hier durch die Dimension &#8220;Produkt&#8221; ersetzt wird, sah die Abfrage zuerst so aus:</p>
<p><span style="font-family: Courier New; color: blue; font-size: 10pt">WITH<br />
</span></p>
<p><span style="font-family: Courier New"><span style="font-size: 10pt"><span style="color: blue">MEMBER</span><br />
</span><span style="color: #c00000; font-size: 12pt; text-decoration: underline"><strong><em>UmsatzDezember03</em></strong></span><span style="font-size: 10pt"><br />
<span style="color: blue">AS</span><br />
</span></span></p>
<p><span style="font-family: Courier New; font-size: 10pt">(<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">    [Measures].[Internet Sales Amount]<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">    ,<span style="color: maroon">STRTOMEMBER</span>(&#8216;[Date].[Calendar].[Month].&amp;[2003]&amp;[12]&#8216;, <span style="color: blue">CONSTRAINED</span>)<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">)<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt"><span style="color: blue">SET</span> Kunden <span style="color: blue">AS</span><br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt"><span style="color: maroon">EXCEPT</span>(<span style="color: maroon">EXISTS<br />
</span></span></p>
<p><span style="font-family: Courier New; font-size: 10pt">(<span style="color: maroon">NONEMPTY</span>([Customer].[Customer].[Customer].<span style="color: blue">MEMBERS<br />
</span></span></p>
<p><span style="font-family: Courier New; font-size: 10pt">        ,[Measures].[Internet Sales Amount])<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">        ,[Product].[Product Categories].[Category].&amp;[1])<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">,<span style="color: maroon">NONEMPTY</span>([Customer].[Customer].[Customer].<span style="color: blue">MEMBERS<br />
</span></span></p>
<p><span style="font-family: Courier New"><span style="font-size: 10pt">    ,</span><span style="color: #c00000; font-size: 12pt; text-decoration: underline"><strong><em>UmsatzDezember03</em></strong></span><span style="font-size: 10pt">))<br />
</span></span></p>
<p><span style="font-family: Courier New; font-size: 10pt"><br />
<span style="color: blue">SELECT</span><br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">{<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">    [Measures].[Internet Sales Amount]<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">} <span style="color: blue">ON</span> 0,<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">{<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">    Kunden<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">} <span style="color: blue">ON</span> 1 <span style="color: blue">FROM</span> [Adventure Works]<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt"><br />
<span style="color: blue">WHERE</span> [Date].[Calendar].[Calendar Year].&amp;[2003]<br />
</span></p>
<p>Um der besseren Lesbarkeit willen erstellte ich das berechnete MEMBER UmsatzDezember03 um das &#8211; zugegeben etwas komplizierte – Kundenset zu filtern.</p>
<p>Die ursprüngliche Abfrage (nicht das Beispiel hier) benötigte 45 Sekunden, was bei einer so kleinen Dimension von 172.000 Membern nicht akzeptabel war. Query-Tuning war also unumgänglich.</p>
<p>Nehmen wir uns des Beispiels oben an: Diese Abfrage &#8211; mit <a href="http://cid-74f04d1ea28ece4e.skydrive.live.com/self.aspx/MDXStudio/v0.4.12/MDXStudio2005.zip">&#8220;MDX Studio&#8221;</a> auf dem AdventureWorks Cube ausgeführt &#8211; berechnete 44.240 Zellen und benötigte 2,6 Sekunden für die Ausführung.</p>
<p>Mosha&#8217;s Befehl zur Sparsamkeit gehorchend, verzichtete ich auf das Hilfsmember und brachte den Ausdruck für UmsatzDezember03 direkt in das Kundenset.</p>
<p><span style="font-family: Courier New; color: blue; font-size: 10pt">WITH<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt"><span style="color: blue">SET</span> Customers <span style="color: blue">AS</span><br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt"><span style="color: maroon">EXCEPT</span>(<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">    <span style="color: maroon">EXISTS</span>(<span style="color: maroon">NONEMPTY</span>([Customer].[Customer].[Customer].<span style="color: blue">MEMBERS<br />
</span></span></p>
<p><span style="font-family: Courier New; font-size: 10pt">                ,[Measures].[Internet Sales Amount])<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">        ,[Product].[Product Categories].[Category].&amp;[1])<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">,<span style="color: maroon">NONEMPTY</span>([Customer].[Customer].[Customer].<span style="color: blue">MEMBERS<br />
</span></span></p>
<p><span style="font-family: Courier New; font-size: 10pt">    ,(<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">    [Measures].[Internet Sales Amount]<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">    ,<span style="color: maroon">STRTOMEMBER</span>(&#8216;[Date].[Calendar].[Month].&amp;[2003]&amp;[12]&#8216;,<span style="color: blue"> CONSTRAINED</span>)<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">)))<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt"><br />
<span style="color: blue">SELECT</span><br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">{<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">    [Measures].[Internet Sales Amount]<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">} <span style="color: blue">ON</span> 0,<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">{<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">    Customers<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt">} <span style="color: blue">ON</span> 1 <span style="color: blue">FROM</span> [Adventure Works]<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt"><br />
<span style="color: blue">WHERE</span> [Date].[Calendar].[Calendar Year].&amp;[2003]</span></p>
<p>Dies führte zu einer Berechnung von nur 7.272 Zellen, benötigte aber immer noch 2,6 Sekunden für die Ausführung. Nachdem ich mir auch das <span style="font-family: Courier New; color: blue; font-size: 10pt">CONSTRAINED</span> Flag in der <span style="color: maroon">STRTOMEMBER </span>Funktion erspart hatte, lag die Ausführungszeit bei 0,6 Sekunden.</p>
<p>Was war passiert? Offensichtlich führte das Einfügen des berechneten Members UmsatzDezember03 dazu, das die Berechnung für den Term <span style="font-family: Courier New"><span style="font-size: 10pt"><span style="color: maroon">NONEMPTY</span>([Customer].[Customer].[Customer].<span style="color: blue">MEMBERS</span>,</span><span style="color: #c00000; font-size: 12pt; text-decoration: underline"><strong><em>UmsatzDezember03</em></strong></span><span style="font-size: 10pt">)</span></span> für <strong>jedes</strong> einzelne Member der Kundendimension ausgeführt wurde – d.h. je mehr Member in der Dimension enthalten sind, desto langsamer wird die Abfrage.</p>
<p>Darüber hinaus ist festzustellen, dass das CONSTRAINED Flag die Query ebenfalls verlangsamt – was uns zu dem Schluss führt, das Mosha&#8217;s Zitat tatsächlich wortwörtlich zu nehmen ist. Allein das Einsparen der Worte &#8220;MEMBER, AS, STRTOMEMBER und CONSTRAINED&#8221; führt in obigem Beispiel zu einer Beschleunigung der Abfrage von 500% und zu einer 86%-igen Reduktion der berechneten Zellen.<span style="font-family: Courier New; color: blue; font-size: 10pt"><br />
</span></p>
<p>In den Analysis Services 2008 tritt dieses Problem nicht mehr auf. &#8220;Hilfsmember&#8221; können hier ohne Scham verwendet werden. Beide auf einem SQL Server 2008 ausgeführten Abfragen berechneten nur die nötigen 7.272 Zellen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/ssas-2005-mdx-tuning-%e2%80%93-unnotige-member-und-fast-noch-schlimmer-strtomember/feed/</wfw:commentRss>
		<slash:comments>0</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><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/112609_1341_RangeLookup1.png" /></p>
<p><span style="text-decoration: underline"><strong>Lösung mittels Script Task – Wunderwaffe &#8220;Binary Search&#8221;<br />
</strong></span></p>
<p>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" /></p>
<p>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" /></p>
<p>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" /></p>
<p>Nun kann ich mir noch die Programmiersprache auswählen (ich nehm mal C#) und endlich mit der eigentlichen Arbeit beginnen.</p>
<p>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" /></p>
<p>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" /></p>
<p>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" /></p>
<p>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" /></p>
<p>Damit wird lediglich festgelegt, dass beim Vergleich zweier NumericRangeItems die Schlüssel (also die Einkommensgrenze) miteinander verglichen werden.</p>
<p>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" /></p>
<p>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.</p>
<p>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.</p>
<p>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" /></p>
<p>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.</p>
<p>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" /></p>
<p><span style="text-decoration: underline"><strong>Lösung mittels Lookup – Mit Caching<br />
</strong></span></p>
<p>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:</p>
<p><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></p>
<p>Dieses Statement liefert im Management das folgende Ergebnis:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/102709_1200_RangeLookup2.png" /></p>
<p>Dies könnte als Quelle für den Lookup Task verwendet werden der dann wie jeder andere gewöhnliche Lookup konfiguriert werden kann.</p>
<p>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.</p>
<p>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.</p>
<p>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>
	</channel>
</rss>
