<?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; SQL Server 2008</title>
	<atom:link href="http://www.ixto.de/blog/category/sql-server-2008/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>Surrogate-Keys f&#252;r Parent-Child-Hierarchie mit SSIS erzeugen und Hierarchiestufen ausgeben</title>
		<link>http://www.ixto.de/blog/sql-server-2008/integration-services-2008/surrogate-keys-fr-parent-child-hierarchie-mit-ssis-erzeugen-und-hierarchiestufen-ausgeben/</link>
		<comments>http://www.ixto.de/blog/sql-server-2008/integration-services-2008/surrogate-keys-fr-parent-child-hierarchie-mit-ssis-erzeugen-und-hierarchiestufen-ausgeben/#comments</comments>
		<pubDate>Mon, 26 Sep 2011 09:16:17 +0000</pubDate>
		<dc:creator>Christopher Glomb</dc:creator>
				<category><![CDATA[Integration Services 2008]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=587</guid>
		<description><![CDATA[Das folgende Szenario bezieht sich auf die Microsoft Demo-Datenbank AdventureWorks 2008. Diese kann auf http://msftdbprodsamples.codeplex.com/ heruntergeladen werden. Die Umsetzung dieses Beispiels erfolgte mit Visual Studio 2008 und SQL Server 2008.
&#160;
Ich möchte in diesem Blogbeitrag erklären, wie man Surrogate-Keys für Parent-Child-Hierarchien und die jeweilige Hierarchiestufe des Mitarbeiters anlegen kann. Dabei hilft uns die Angestellten Tabelle der [...]]]></description>
			<content:encoded><![CDATA[<p>Das folgende Szenario bezieht sich auf die Microsoft Demo-Datenbank AdventureWorks 2008. Diese kann auf <a href="http://msftdbprodsamples.codeplex.com/">http://msftdbprodsamples.codeplex.com/</a> heruntergeladen werden. Die Umsetzung dieses Beispiels erfolgte mit Visual Studio 2008 und SQL Server 2008.</p>
<p>&#160;</p>
<p>Ich möchte in diesem Blogbeitrag erklären, wie man Surrogate-Keys für Parent-Child-Hierarchien und die jeweilige Hierarchiestufe des Mitarbeiters anlegen kann. Dabei hilft uns die Angestellten Tabelle der AdventureWorks Datenbank. Diese findet man unter dem Tabellennamen Employee im Schema HumanResources. Der Mitarbeiter wird über die Spalte EmployeeID identifiziert und der Vorgesetzte über die Spalte ManagerID. Angestellte die keinen Vorgesetzten haben, sind mit entsprechender ManagerID auf NULL gesetzt. Dementsprechend ist der/sind die Mitarbeiter der/die keinen Vorgesetzten hat/haben, die höchste Stufe in unserer Organisation (in unserem Fall also der Chef).</p>
<p>&#160;</p>
<p> <span id="more-587"></span>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb.png" width="585" height="287" /></a></p>
<p>&#160;</p>
<p>Wir müssen in unserer Tabelle in der später unsere Daten landen sollen zunächst zwei zusätzliche Spalten einfügen. Das wäre zum einen die Spalte <i>EmployeeBK</i> und <i>ManagerBK</i>. Die Erklärung dazu folgt dann später im Text.</p>
<p>&#160;</p>
<p>Außerdem benötigen wir in unserer Ausgangstabelle (Employee) eine Hilfsspalte (ich habe mich i.F. für istImportiert entschieden (NULL ist zulässig)) mit beliebigen Namen und dem Datentyp bit.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_3.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_3.png" width="585" height="137" /></a></p>
<p>&#160;</p>
<p>Als nächstes müssen wir dafür sorgen, dass alle Werte in dieser neuen Spalte den Wert 0 enthalten. Damit das Ganze gleich in SSIS passiert, ziehen wir uns einen SQL-Task auf unsere Arbeitsfläche und fügen den Befehl <strong>update [HumanResources].[Employee] set istImportiert = 0</strong> ein.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_4.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_4.png" width="600" height="490" /></a></p>
<p>&#160;</p>
<p>Für den nächsten Schritt benötigen wir eine Laufvariable mit dem Datentyp Integer und dem Standardwert 0. Danach legen wir einen for-Schleifencontainer an. Nachdem Ihr die Eigenschaften festgelegt habt, legen wir einen Datenflusstask in den Container.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_5.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_5.png" width="600" height="505" /></a></p>
<p>&#160;</p>
<p>Vorweg schon mal die Ansicht, wie es später in unserem Datenflusstask aussehen wird:</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_6.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_6.png" width="600" height="558" /></a></p>
<p>&#160;</p>
<p>&#160;</p>
<p><b><font size="3">Schritt 1</font></b></p>
<p><strong></strong></p>
<p>Wie üblich brauchen wir zunächst eine Quelle. Entscheidend ist hier natürlich, dass wir neben der ManagerID und der EmployeeID die Abfrage darauf einschränken, dass nur Daten geladen werden, wo der Wert für istImportiert = 0 ist.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_7.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_7.png" width="590" height="616" /></a></p>
<p>&#160;</p>
<p><b><font size="3">Schritt 2</font></b></p>
<p><strong><font size="3"></font></strong></p>
<p>In der Komponente für bedingtes Teilen erfolgt die Überprüfung, welche Daten unsere Wurzelknoten (also unsere Manager mit dem Eintrag null) sind. Alle anderen Mitarbeiter werden als Knoten ausgegeben. </p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_8.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_8.png" width="591" height="351" /></a></p>
<p>&#160;</p>
<p><b><font size="3">Schritt 3</font></b></p>
<p><strong></strong></p>
<p>Wir kümmern uns zunächst um die Mitarbeiter, die unseren Wurzelknoten repräsentieren. Dazu legen wir eine Abgeleitete Spalte mit dem folgenden Ausdruck an: </p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_9.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_9.png" width="600" height="69" /></a></p>
<p>&#160;</p>
<p>Im zweiten Teil von Schritt 3 müssen die anderen Hierarchiestufen überprüft werden. Hierfür legen wir eine Lookup Komponente an und verbinden diese mit der Ausgabe für Knoten aus der Conditional-Split Komponente. Damit wir es später nicht vergessen, ändern wir unter Allgemein die Einstellung wie nicht getroffene Einträge behandelt werden (auf Fehler ignorieren stellen). Unter Verbindung fügen wir ein SQL-Statement ein, das unsere Tabelle abfragt, in der letztendlich unsere Daten landen sollen. Jetzt kommt eine der erwähnten Spalten aus der Einleitung ins Spiel. EmployeeBK enthält später die Mitarbeiternummer welche aus EmployeeID kommt.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_10.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_10.png" width="409" height="392" /></a></p>
<p>&#160;</p>
<p>Wir verknüpfen die ManagerID mit EmployeeBK und lassen uns die EmployeeID (im SQL-Statement umbenannt zu EmployeeParentID) ausgeben. Überall wo wir keinen Treffer haben, wird NULL ausgegeben.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_11.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_11.png" width="600" height="304" /></a></p>
<p>&#160;</p>
<p><b><font size="3">Schritt 4</font></b></p>
<p><strong><font size="3"></font></strong></p>
<p>Mit dem nächsten Conditional Split überprüfen wir, ob EmployeeParentID einen Wert erhalten hat oder nicht. Alle Zeilen für die es einen Treffer gibt, gehen in diesem Beispiel an die Ausgabe „Vater gefunden“.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_12.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_12.png" width="600" height="354" /></a></p>
<p>&#160;</p>
<p><b><font size="3">Schritt 5</font></b></p>
<p><strong><font size="3"></font></strong></p>
<p>Mit Hilfe einer Union All Komponente verknüpfen wir die eingehenden Zeilen.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_13.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_13.png" width="599" height="587" /></a></p>
<p>&#160;</p>
<p><b><font size="3">Schritt 6</font></b></p>
<p><strong></strong></p>
<p>Über die Multicast Komponente lassen wir uns Kopien des Datasets erzeugen.</p>
<p>&#160;</p>
<p><b><font size="3">Schritt 7</font></b></p>
<p><strong></strong></p>
<p>In der Komponente OLE DB Befehl fügen wir für unsere Quelltabelle Employee ein Update Statement ein.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_14.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_14.png" width="600" height="441" /></a></p>
<p>&#160;</p>
<p>Außerdem muss in den Spaltenzuordnungen EmployeeID mit Param_0 verknüpft werden.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_15.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_15.png" width="598" height="323" /></a></p>
<p>&#160;</p>
<p><b><font size="3">Schritt 8</font></b></p>
<p><strong></strong></p>
<p>Als Erstes betrachten wir die Zuordnungen für unser Ziel (OLE_DST EmployeeNeu). Wie bereits erwähnt, stellt die EmployeeID in unserer Zieltabelle den Surrogate-Key dar. Außerdem muss darauf geachtet werden, dass unsere EmployeeParentID mit der ManagerID verknüpft wird.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_16.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_16.png" width="593" height="548" /></a></p>
<p>&#160;</p>
<p>Da wir uns immer noch im Schleifencontainer befinden, müssen wir im letzten Schritt dafür sorgen, dass kein Durchlauf mehr erfolgt, wenn unsere Laufvariable einen Wert ungleich 0 hat. Wir fügen eine Komponente „SQL ausführen“ (SQL UPDATE Employee) ein (siehe Bild)</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_17.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_17.png" width="365" height="475" /></a></p>
<p>&#160;</p>
<p>und legen folgende Einstellungen fest:</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_18.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_18.png" width="600" height="421" /></a></p>
<p>&#160;</p>
<p>Wenn noch nicht geschehen, muss im ResultSet unsere Laufvariable ausgegeben werden.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_19.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_19.png" width="600" height="113" /></a></p>
<p>&#160;</p>
<p><b><font size="3">Hierarchiestufe</font></b></p>
<p><strong><font size="3"></font></strong></p>
<p>Da ich abschließend wissen möchte, wie viele Vorgesetzte ein Mitarbeiter über sich hat, benötige ich eine zusätzliche Variable, die für jeden Durchlauf des Containers hochgezählt und dann in unsere Zieltabelle weggeschrieben wird. Hierfür lege ich zunächst eine Variable (iHierarchiestufe) mit dem Datentyp integer an (Startwert steht auf 1) und ergänze meine Zieltabelle um die Spalte Hierarchiestufe. Den Wert der Variablen füge ich mit Hilfe der Komponente „abgeleitete Spalte“ in eine neue Spalte ein.</p>
<p> <a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_20.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_20.png" width="607" height="569" /></a>
<p>&#160;</p>
<p>Außerdem muss ich noch das Mapping wie in Schritt 8 beschrieben ergänzen falls nicht schon geschehen. </p>
<p>&#160;</p>
<p>Natürlich muss dem Schleifencontainer noch mitgeteilt werden, dass unsere Variable pro Durchlauf hochgezählt wird (AssignExpression). Die Einstellung dafür bitte dem Bild For-Schleifen-Editor entnehmen.</p>
<p>&#160;</p>
<p>Abschließend schauen wir uns noch das Ergebnis für unsere Zieltabelle „EmployeeNeu“ an. Im ersten Durchlauf finden wir genau einen Mitarbeiter der keinen Vorgesetzten hat. Er steht dementsprechend an erster Stelle in der Hierarchie.</p>
<p>&#160;</p>
<p>Erster Durchlauf:</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_21.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_21.png" width="600" height="74" /></a></p>
<p>&#160;</p>
<p>Im zweiten Durchlauf (zweite Ebene in der Hierarchie) haben wir schon mehr Mitarbeiter getroffen. Die ehemalige EmployeeID aus der Quelltabelle befindet sich nun in der Spalte EmployeeBK. Unter ManagerBK finden wir die zugehörige Kennzeichnung des Vorgesetzten (ManagerID aus der Quelltabelle). Unter ManagerID befindet sich der neu erzeugte Surrogate Key.</p>
<p>&#160;</p>
<p>Zweiter Durchlauf:</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_22.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/8ad168261186_9839/image_thumb_22.png" width="600" height="190" /></a></p>
<p>&#160;</p>
<p>Da alle weiteren Hierarchiestufen nach dem gleichem Schema gefüllt werden, spare ich mir an dieser Stelle die Fotos für die nächsten Durchläufe. Viel Spaß beim Ausprobieren.</p>
<p>&#160;</p>
<p>Wenn ich euch mit dieser Anleitung helfen konnte, ihr weitere Fragen, Anmerkungen, Verbesserungsvorschläge oder Lösungen habt, freue ich mich auf Kommentare!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2008/integration-services-2008/surrogate-keys-fr-parent-child-hierarchie-mit-ssis-erzeugen-und-hierarchiestufen-ausgeben/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ExecutionValue beim Execute SQL-Task in SSIS</title>
		<link>http://www.ixto.de/blog/sql-server-2008/integration-services-2008/executionvalue-beim-execute-sql-task-in-ssis-2/</link>
		<comments>http://www.ixto.de/blog/sql-server-2008/integration-services-2008/executionvalue-beim-execute-sql-task-in-ssis-2/#comments</comments>
		<pubDate>Fri, 22 Jul 2011 09:56:18 +0000</pubDate>
		<dc:creator>David Veenhuis</dc:creator>
				<category><![CDATA[Integration Services 2008]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/allgemein/executionvalue-beim-execute-sql-task-in-ssis-2/</guid>
		<description><![CDATA[Es gibt einen einfachen Weg um festzustellen, wieviele Zeilen von der Ausführung von SQL-Anweisungen wie DELETE oder UPDATE mit dem Execute-SQL-Task betroffen sind. Dazu kann die ExecutionValue-Property des Execute-SQL-Tasks verwendet werden. Das wird hier am Beispiel einer DELETE-Anweisung vorgestellt.
&#160;
Auf die Property kann nicht direkt zugegriffen werden. Stattdessen wird der Property ExecValueVariable eine Package-Variable zugeordnet. In [...]]]></description>
			<content:encoded><![CDATA[<p>Es gibt einen einfachen Weg um festzustellen, wieviele Zeilen von der Ausführung von SQL-Anweisungen wie DELETE oder UPDATE mit dem Execute-SQL-Task betroffen sind. Dazu kann die ExecutionValue-Property des Execute-SQL-Tasks verwendet werden. Das wird hier am Beispiel einer DELETE-Anweisung vorgestellt.<span id="more-583"></span></p>
<p>&#160;</p>
<p>Auf die Property kann nicht direkt zugegriffen werden. Stattdessen wird der Property ExecValueVariable eine Package-Variable zugeordnet. In diese wird dann zur Laufzeit des Paketes die Anzahl der Zeilen, die von der ausgeführten SQL-Anweisung betroffen waren, eingetragen. Diese Variable kann im weiteren Package-Ablauf verwendet werden. Für die Anzahl der Zeilen wird eine Int-Variabel verwendet, die in disem Beispiel iExecValue genannt wird.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/ExecutionValue-beim-Execute-SQL-Task-in-_A742/image.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/ExecutionValue-beim-Execute-SQL-Task-in-_A742/image_thumb.png" width="430" height="107" /></a></p>
<p>&#160;</p>
<p>Als nächstes wird ein Execute-SQL-Task erstellt, der die Beispiel-Tabelle Example mittels einer DELETE-Anweisung leert. Die Tabelle enthält 3 Datensätze und somit erwarten wir die Zahl 3 als Anzahl der betroffenen Zeilen. Im Editor des Tasks wird die Connection ausgewählt und die Anweisung „DELETE FROM Example“ als Direkteingabe eingegeben.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/ExecutionValue-beim-Execute-SQL-Task-in-_A742/image_3.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/ExecutionValue-beim-Execute-SQL-Task-in-_A742/image_thumb_3.png" width="511" height="435" /></a></p>
<p>&#160;</p>
<p>Durch Rechtsklick auf den Task und Auswahl von „Eigenschaften“ wird der Eigenschaften-Editor des Tasks geöffnet. Da wird der Property ExecValueVariable über die Dropdpwn-Liste die vorher angelegte Variabel iExecValue aus. </p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/ExecutionValue-beim-Execute-SQL-Task-in-_A742/image_4.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/ExecutionValue-beim-Execute-SQL-Task-in-_A742/image_thumb_4.png" width="337" height="515" /></a></p>
<p>&#160;</p>
<p>Um nach Start des Paketes das Ergebnis zu prüfen, setzen wir einen Breakpoint auf das PostExecute-Ereignis des Tasks (Rechtsklick auf den Task, Haltepunkte bearbeiten wählen und dann den Eintrag für „OnPostExecute“ anhaken). Damit kann direkt nach Ausführung des SQL-Tasks geprüft werden, ob die Variable tatsächlich die gewünschte Anzahl der betroffenen Zeilen enthält.</p>
<p>&#160;</p>
<p>Anschließende wird das Paket ausgeführt. Bei Erreichen des Breakpoints fügen wir über Debuggen-&gt;Fenster-&gt;Überwachungsfenster1. Dort tippen wir in die Namensspalte den Namen unserer Variabel ein. Anschließend sehen wir, dass unsere Variable tatsächlich die Anzahl der von der SQL-Anweisung betroffenen Zeilen enthält:</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/ExecutionValue-beim-Execute-SQL-Task-in-_A742/image_5.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/ExecutionValue-beim-Execute-SQL-Task-in-_A742/image_thumb_5.png" width="526" height="174" /></a>#</p>
<p>&#160;</p>
<p>Es kann auch eine Stored Procedure aufgerufen werden, die wie in unserem Beispiel eine DELETE-Anweisung ausführt. In der Stored Procedure darf dann nicht SET NOCOUNT ON“ verwenden, da dann die Zahl der betroffenen Zeilen nicht ermittelt wird.</p>
<p>&#160;</p>
<p>In dem Beispiel kann TRUNCATE nicht verwendet werden, da bei TRUNCATE nicht zeilenweise gelöscht wird, wie bei DELETE. Bei TRUNCATE werden stattdessen die Datenseiten der betroffenen Tabelle deallokiert. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2008/integration-services-2008/executionvalue-beim-execute-sql-task-in-ssis-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pr&#252;fung auf Nachkommastellen bei Importen (SSIS)</title>
		<link>http://www.ixto.de/blog/allgemein/prfung-auf-nachkommastellen-bei-importen-ssis/</link>
		<comments>http://www.ixto.de/blog/allgemein/prfung-auf-nachkommastellen-bei-importen-ssis/#comments</comments>
		<pubDate>Mon, 30 May 2011 16:07:57 +0000</pubDate>
		<dc:creator>Ricardo Radke</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Integration Services 2005]]></category>
		<category><![CDATA[Integration Services 2008]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=549</guid>
		<description><![CDATA[Es gibt Mittel und Wege, Gültigkeitsprüfungen für Gleitkommazahlen innerhalb der Integration Services zu realisieren. Die Überlegungen zum Vorgehen können dabei von einfachen Konvertierungen bis hin zu komplexen Script-Tasks reichen.    

In diesem Beitrag möchte ich eine Möglichkeit erläutern, die so simpel ist, dass der ein oder andere vielleicht gar nicht erst daran gedacht [...]]]></description>
			<content:encoded><![CDATA[<p>Es gibt Mittel und Wege, Gültigkeitsprüfungen für Gleitkommazahlen innerhalb der Integration Services zu realisieren. Die Überlegungen zum Vorgehen können dabei von einfachen Konvertierungen bis hin zu komplexen Script-Tasks reichen.    </p>
<p></br>
<p>In diesem Beitrag möchte ich eine Möglichkeit erläutern, die so simpel ist, dass der ein oder andere vielleicht gar nicht erst daran gedacht hat – frei nach dem Motto: „Ich seh‘ den Wald vor lauter Bäumen nicht“.    </p>
<p> <span id="more-549"></span> <br /></br>  Nehmen wir an, es handelt sich bei unserer Zahl um einen Prozentwert, dessen Anzahl der Nachkommastellen wir auf 5 begrenzen und im Falle der Überschreitung einen Fehler ausgeben lassen wollen (z.B. wenn die Zielspalte in der Datenbank nicht mehr als 5 zulässt). Dies würde sich zwar mit einfachen Mitteln realisieren lassen, jedoch unter Umständen nicht immer zum gewünschten Ergebnis führen.    </p>
<p></br>Angenommen es handelt sich um den Wert <i>12,12345<b>00 </b></i>– so würden die beiden letzten Nachkommastellen nach „Schema-F“ abgeschnitten und ein Fehler erzeugt werden. Da es sich in diesem Falle aber um das Abschneiden von lediglich zwei nullen handelt und somit der numerische Wert trotzdem unverändert und somit gültig bleibt, muss hier eine andere Lösung her.     </p>
<p></br>
<p>Wie? Ganz einfach! Man vergleiche die Zahl mit sich selbst – und zwar konvertiert in einen Gleitkommawert mit 5, sowie mit 6 Nachkommastellen. Das ganze könnte dann z.B. so aussehen:    </p>
<p></br><i>(DT_NUMERIC, 10, 5)Wert == (DT_NUMERIC, 10, 6)Wert      <br /></i></p>
<p></br>
<p>Die folgende Abbildung sollte das Prinzip noch einmal veranschaulichen und weitere Erläuterungen überflüssig machen <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smiley" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/Prfung-auf-Nachkommastellen-bei-Importen_FE03/wlEmoticon-smile.png" />     </p>
<p></br><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/Prfung-auf-Nachkommastellen-bei-Importen_FE03/ssis_conversion.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="ssis_conversion" border="0" alt="ssis_conversion" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/Prfung-auf-Nachkommastellen-bei-Importen_FE03/ssis_conversion_thumb.png" width="494" height="263" /></a></p>
<p></br></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/allgemein/prfung-auf-nachkommastellen-bei-importen-ssis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jahreswerte auf Monate verlustfrei verteilen &#8211; Teil 1</title>
		<link>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/jahreswerte-auf-monate-verlustfrei-verteilen-teil-1/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/jahreswerte-auf-monate-verlustfrei-verteilen-teil-1/#comments</comments>
		<pubDate>Wed, 23 Feb 2011 09:15:00 +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=510</guid>
		<description><![CDATA[Ich habe wieder ein schönes Beispiel gefunden an der man die Flexibilität der Integration Services demonstrieren kann. Die Aufgabe ist recht einfach: es geht darum, einen Jahreswert mit Dezimalstellen (in unserem Fall ein numeric(6,2), z.B. ein Euro-Wert) gleichmäßig auf 12 Monate zu verteilen. Die Division sollte uns hoffentlich keine Kopfschmerzen bereiten, die Herausforderung liegt darin, [...]]]></description>
			<content:encoded><![CDATA[<p>Ich habe wieder ein schönes Beispiel gefunden an der man die Flexibilität der Integration Services demonstrieren kann. Die Aufgabe ist recht einfach: es geht darum, einen Jahreswert mit Dezimalstellen (in unserem Fall ein numeric(6,2), z.B. ein Euro-Wert) gleichmäßig auf 12 Monate zu verteilen. Die Division sollte uns hoffentlich keine Kopfschmerzen bereiten, die Herausforderung liegt darin, dass unser Datentyp nur zwei Nachkommastellen erlaubt und daher viele Werte bei der Division einen Genauigkeitsverlust erleiden würden.<br />
<span id="more-510"></span><br />
Ein kurzes Beispiel: teilen wir den Wert 100,00 € durch 12 erhalten wir pro Monat einen Wert von 8,3333. € Würden wir nun 12 mal den Wert 8,33 € als Monatswert in unsere Datenbank übernehmen, würden uns über das Jahr hinweg gesehen 0,04 € fehlen. Das Ziel wäre hier, diese 4 Eurocent (also den Differenzbetrag) auf den letzten Monat aufzuschlagen.</p>
<p>&#160;</p>
<p>Das Problem begegnet uns immer dann, wenn in der Datenbank Werte in einer anderen Granularität gespeichert werden (in diesem Fall monatsgenau) als diese von der darauf aufsetzenden Anwendung geliefert werden (diese erlaubt nur jahresgenaue Werte). Für spätere Auswertungen oder Änderungen möchten wir monatsgenaue Werte speichern, ohne den korrekten Jahreswert (die Summe der 12 Monate) zu verlieren.</p>
<p>&#160;</p>
<p>Auch hier führen wieder viele Wege nach Rom, daher zeige ich im ersten Teil neben der eigentlichen Problemstellung und dem Kern der Lösung eine von vier (!) Möglichkeiten die ich gefunden habe um die Aufgabe zu lösen.</p>
<p>&#160;</p>
<p>Zunächst einmal überlege ich mir geeignete Ausdrücke um die oben genannte Anforderung innerhalb eines SSIS-Datenfluss&#8217; umsetzen zu können. Für die Monate 1 bis 11 genügt folgender Ausdruck:</p>
<p>&#160;</p>
<p><font face="Consolas">(DT_NUMERIC,6,2)(Value / 12)</font></p>
<p>&#160;</p>
<p>Der Monat 12 erfordert eine Sonderbehandlung, welche durch folgenden Ausdruck gewährleistet wird:</p>
<p>&#160;</p>
<p><font face="Consolas">(DT_NUMERIC,6,2)(Value &#8211; (DT_NUMERIC,6,2)(11 * (DT_NUMERIC,6,2)(Value / 12)))</font></p>
<p>&#160;</p>
<p>Im Grunde ermittelt dieser Ausdruck die Differenz zwischen dem Jahreswert und der Summe der 11 Monatswerte um den Wert für Monat 12 zu berechnen. Beachten Sie dabei, dass es egal ist ob bei der Ermittlung der Monatswerte ab- oder aufgerundet oder gar abgeschnitten wird (was hier der Fall ist), der Wert für Monat 12 wird stets korrekt ermittelt.</p>
<p>&#160;</p>
<p>Einer der naheliegendsten Wege um diese Logik umzusetzen ist die Nutzung eines Cross Joins zwischen dem Jahreswert und 12 Monaten. Damit wird der Jahreswert von einer Zeile auf 12 Zeilen verteilt. Anschließend kann in einem &#8220;Abgeleitete Spalte&#8221;-Task der Wert mit Hilfe der oben beschriebenen Ausdrücke manipuliert werden.</p>
<p>&#160;</p>
<p>Folgender Screenshot zeigt den Datenfluss und zwei Data Viewer: einen nach dem Cross Join und einem nach dem Anwenden der Ausdrücke. Beachten Sie, dass sich der Wert für Monat 12 von allen anderen unterscheidet um einen korrekten Jahreswert zu gewährleisten.</p>
<p>&#160;</p>
<p><a href="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/cc00279c2c81_1174B/image.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/cc00279c2c81_1174B/image_thumb.png" width="572" height="291" /></a></p>
<p>&#160;</p>
<p>Im zweiten Teil zeige ich drei (!) weitere Vorgehensweisen, sowie die Ergebnisse eines Performancetests um zu ermitteln, wie sich die unterschiedlichen Wege im produktiven Einsatz bewähren könnten.</p>
<p></br></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/integration-services-2005/jahreswerte-auf-monate-verlustfrei-verteilen-teil-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sicheres Deployment einer BI-Lösung mit Bordmitteln und OpenSource-Tools</title>
		<link>http://www.ixto.de/blog/allgemein/sicheres-deployment-einer-bi-losung-mit-bordmitteln-und-opensource-tools/</link>
		<comments>http://www.ixto.de/blog/allgemein/sicheres-deployment-einer-bi-losung-mit-bordmitteln-und-opensource-tools/#comments</comments>
		<pubDate>Mon, 29 Nov 2010 13:34:18 +0000</pubDate>
		<dc:creator>Martin Ihrke</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=293</guid>
		<description><![CDATA[Die Bereitstellung einer Business Intelligence Lösung erscheint im ersten Moment als eine triviale Angelegenheit. Wer jedoch eine mühevoll und aufwendig entwickelte BI-Lösung nach erfolgreichem Test und Abnahme auf ein Produktivsystem übertragen musste, der weiss, wie mühevoll und aufwendig dieses Unterfangen trotz aller anfänglichen Vermutung sein kann.
Neben den technischen Herausforderungen, die eine für den rauen Betriebsalltag [...]]]></description>
			<content:encoded><![CDATA[<p>Die Bereitstellung einer Business Intelligence Lösung erscheint im ersten Moment als eine triviale Angelegenheit. Wer jedoch eine mühevoll und aufwendig entwickelte BI-Lösung nach erfolgreichem Test und Abnahme auf ein Produktivsystem übertragen musste, der weiss, wie mühevoll und aufwendig dieses Unterfangen trotz aller anfänglichen Vermutung sein kann.<br />
<span id="more-293"></span>Neben den technischen Herausforderungen, die eine für den rauen Betriebsalltag konfigurierte Umgebung mit sich bringt, sind auch fachliche Schwierigkeiten zu meistern, insbesondere dann, wenn eine bereits im laufenden Betrieb befindliche Lösung abgelöst werden soll. Einerseits sollen produktive Daten natürlich nicht verloren gehen, andererseits gilt es, Strukturänderungen und Steuerdaten vollständig und unbeschadet in die Produktivumgebung zu bringen. Es existieren zahlreiche Dritthersteller-Werkzeuge, die dies mehr oder weniger automatisch auf Knopfdruck realisieren können, diese kosten jedoch oft mehr als den sprichwörtlichen schmalen Taler und können damit das Projektbudget in die Höhe schnellen lassen. Aus diesem Grund möchte ich im folgenden Beitrag Lösungswege aufzeigen, die sich auf die Benutzung von SQL Server Bordmitteln und kostenlos erhältlichen OpenSource-Werkzeugen beschränken. Voraussetzung für das nachfolgend beschriebene Szenario ist, dass die produktive Umgebung nicht direkt aus der Entwicklungsumgebung erreichbar ist und somit nicht einfach ein direktes Deployment von dort aus geschehen kann. Ein Umstand, der aufgrund von strikten Sicherheitsbestimmungen sehr oft im realen Projektgeschäft angetroffen wird.</p>
<p><strong>Die Datenbank</strong></p>
<p>Zunächst sollte Klarheit darüber herrschen, welche Datenbankobjekte übertragen werden müssen. Vorbildliche Naturen können diese Frage mit einem Blick in die Historie ihrer professionellen Versionsverwaltung (natürlich inklusive Application LifeCycle Management) sogar des Nächtens im Halbschlaf beanworten (vielleicht haben sie auch mit Zettel und Stift mitgeschrieben), aber auch wenn diese Professionalität des Vorgehens nicht erreicht werden kann oder soll, gibt es es nützliche Hilfsmittel, die uns auf unter die Arme greifen helfen. Das OpenSource-Tool <em>OpenDBDiff</em> bietet die Möglichkeit, zwei Datenbank-Stände miteinander zu vergleichen. Es entsteht dabei ein SQL-Skript, dass ausgeführt auf der Zieldatenbank die ausgewählten Objekte synchronisiert. Dabei sei angemerkt, dass hierbei eigentlich nur Tabellenobjekte kritisch sind, da sich alle anderen, wie <em>Views</em>, <em>Stored Procedures</em> und <em>User-Defined Functions</em>, auch durch Löschen und Neu-Anlegen auf den gleichen Stand bringen lassen. Aber wenn wir OpenDBDiff ohnehin gestartet haben, sparen wir uns die Mühe.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/mi_deployment/mi_01.png" alt="" /></p>
<p>Der zweite Schritt besteht im Abgleich von Steuerdaten, die zumeist in Konfigurationstabellen schlummern. Dazu kann uns das Tool TableDiff dienen, mit dessen Hilfe Unterschiede in Tabellendaten abgeglichen werden, indem auch hier SQL-Skripte generiert werden. Das Tool ist Bestandteil der SQL Server Installation und lässt sich zumeist unter <em>C:\Program Files\Microsoft SQL Server\100\COM</em> finden und aufrufen, wobei der Pfad je nach SQL Server Version und dessen Installationsverzeichnis varieren kann. TableDiff geht dabei tabellenweise vor, weshalb es sich anbietet, eine Batchdatei zu programmieren, die den Aufruf pro Tabelle automatisiert.</p>
<p>rem Server festlegen</p>
<p>set sserver=localhost</p>
<p>set dserver=localhost</p>
<p>rem Datenbanken festlegen</p>
<p>set sdb=AdventureWorksDW</p>
<p>set ddb=AdventureWorksDW2008</p>
<p>rem Pfade definieren</p>
<p>set exepath=&#8221;C:\Program Files\Microsoft SQL Server\100\COM\tablediff.exe&#8221;</p>
<p>set destfolder=D:\SQL</p>
<p>rem Schema festlegen</p>
<p>set schema=dbo</p>
<p>for %%t in (dimCurrency dimScenario) do (</p>
<p>%exepath% /sourceserver %sserver% /sourcedatabase %sdb% /sourceschema %schema%  /sourcetable %%t /destinationserver %dserver% /destinationdatabase %ddb% /destinationschema %schema% /destinationtable %%t -f &#8220;%destFolder%\changeScript(%schema%_%%t).sql&#8221;</p>
<p>)</p>
<p>Wir haben nun eine Reihe von SQL-Skripten, die nur noch auf der Zieldaten ausgeführt werden müssen, um die Datenbankstruktur in einen identischen Zustand zu bringen.</p>
<p><strong>SSIS-Pakete und Cube-Defintionen</strong></p>
<p>Es gilt nun, sowohl SSIS-Pakete und Cube-Definitionen zu übertragen. Dies ist etwas einfacher, da sowohl für SSIS- als für SSAS-Projekte einen Deployment-Wizard existiert, der uns das Bereitstellen auf dem Zielsystem (fast) vollständig abnimmt. Im Falle von SSIS-Paketen besteht weiterhin die Möglichkeit, auf das Kommandozeilenwerkzeug dtutil zurückzugreifen, das, eingebettet in eine Batch-Datei, das Bereitstellen der Pakete nach einem Doppelklick automatisch übernehmen kann. Da wir selbst in kleineren Projekten intensiven Gebrauch von der SSIS-Paketkonfiguration machen, haben wir auch wenig Mühe damit, Informationen wie Server- oder Datenbanknamen zu aktualisieren. SSAS-Cubes  müssen nur noch verarbeitet werden und sind damit direkt bereit zum Einsatz. Aber auch hier gilt es, eine gewisse Vorsicht an den Tag zu legen, da doch der ein oder andere Fallstrick lauert. Einer dieser Fallstricke sind Cube-Rollen, die ohne weitere Konfiguration auf dem Zielserver überschrieben werden. Doch auch wenn wir dies explizit verhindern wollen (die entsprechende Option im Deployment Wizard heißt <em>Retain Roles und Members</em>), ist leider nicht immer gewährleistet, dass die bestehende Konfiguration erhalten bleibt. Hier hat sich der Workaround etabliert, die Rollendefinition auf dem Produktivserver zu sichern (Zu finden im entsprechenden Bereich in der XMLA-Datei, also der Datenbankdefinition, auf der SSAS-Datenbank) und nach dem Deployment zurückzuspielen.</p>
<p><strong>Die Berichte</strong></p>
<p>Für SSRS-Berichte hat sich ein ein Werkzeug bewährt, dass es uns ermöglicht, Berichte direkt vom (Test)Berichtsserver herunterzuladen und auf den (Produktiv)Berichtsserver zu übertragen. Dazu wird neben den Berichtsdefinitionen in Form von .rdl-Dateien eine Batchdatei generiert, in der nur noch die URL des Zielsystems hinterlegt werden muss. Nach einem Doppelklick können wir und zurücklehnen und die Deployment-Show genießen.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/mi_deployment/mi_02.png" alt="" /></p>
<p><strong>Fazit</strong></p>
<p>Mit dem vorgestellen Vorgehen und Werkzeugen ist es uns, ein recht elegantes Deployment unserer BI-Solution auf entfernte Umgebungen vorzunehmen. Großer Vorteil dabei ist die Möglichkeit, weite Teile durch Batch-Dateien und Konfigurationen zu automatisieren und damit den Aufwand mehrmaliger Deployments zu merklich reduzieren.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/allgemein/sicheres-deployment-einer-bi-losung-mit-bordmitteln-und-opensource-tools/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SSIS Error Handling Design Pattern: Transaktionen</title>
		<link>http://www.ixto.de/blog/sql-server-2008/integration-services-2008/ssis-error-handling-design-pattern-transaktionen/</link>
		<comments>http://www.ixto.de/blog/sql-server-2008/integration-services-2008/ssis-error-handling-design-pattern-transaktionen/#comments</comments>
		<pubDate>Fri, 15 Oct 2010 17:27:19 +0000</pubDate>
		<dc:creator>Ricardo Radke</dc:creator>
				<category><![CDATA[Integration Services 2008]]></category>
		<category><![CDATA[SSIS Transaktion Error Handling Errorhandling]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=217</guid>
		<description><![CDATA[Die Konfigurationsmöglichkeiten für das Transaktionsverhalten in SSIS Paketen reichen in bestimmten Fällen nur bedingt aus. Stellen wir uns einmal folgende Ausgangssituation am Beispiel eines betriebswirtschaftlichen Szenarios vor: Wir benötigen ein SSIS-Paket zum Import der monatlichen Verteilungsschlüssel von Hauptkostenstellen auf Nebenkostenstellen. Um die Richtigkeit der Daten zu gewährleisten, prüfen wir diese Verteilung, bevor die Daten importiert [...]]]></description>
			<content:encoded><![CDATA[<p>Die Konfigurationsmöglichkeiten für das Transaktionsverhalten in SSIS Paketen reichen in bestimmten Fällen nur bedingt aus. Stellen wir uns einmal folgende Ausgangssituation am Beispiel eines betriebswirtschaftlichen Szenarios vor: Wir benötigen ein SSIS-Paket zum Import der monatlichen Verteilungsschlüssel von <strong>Hauptkostenstellen</strong> auf <strong>Nebenkostenstellen</strong>. Um die Richtigkeit der Daten zu gewährleisten, prüfen wir diese Verteilung, bevor die Daten importiert werden. Wird eine <strong>Hauptkostenstelle</strong> nicht zu 100% verteilt, müssen wir auf diesen Fall reagieren.  <br />
<span id="more-217"></span><br />
<br\><br />
Hierbei wird ersichtlich, dass es sich nicht um einen technischen Fehler handelt (der etwa unser Paket zum Absturz bringt), sondern um einen <strong>logischen</strong> <strong>Fehler</strong>, der bei Nicht-Berücksichtigung für größere Schwierigkeiten nach dem Import aufgrund inhaltlich fehlerhafter Daten sorgen kann. Aber auch unter Berücksichtigung der Problematik stellt sich die Frage:<br />
<br\><br />
Macht es Sinn, einen nur teilweise erfolgreichen Import durchzuführen?<br />
<br\><br />
Diese Frage lässt sich nicht pauschal beantworten, da je nach Szenario ein bestimmtes Verhalten erwünscht sein kann. Im produktiven Einsatz würde sie höchstwahrscheinlich mit einem klaren „nein“ beantwortet werden, hingegen kann ein unvollständiger Import im Entwicklungs- und Testbetrieb in bestimmten Fällen durchaus sinnvoll sein.<br />
<br\><br />
Für genau solche Anforderungen haben wir ein Design-Pattern entwickelt, welches uns ermöglicht, ein transaktions-ähnliches Verhalten für inhaltliche, also nicht technische, Fehler innerhalb eines SSIS-Pakets per „Schalter“ ein- und ausschalten zu können.<br />
Dieses Verfahren werde ich Ihnen nun Schritt für Schritt vorstellen.<br />
<br\><br />
Am Ende des Beitrags finden Sie eine Übersicht der fertigen Lösung, die Ihnen hilft, das Gesamtbild nachzuvollziehen.<br />
<br\><br />
Werfen wir zunächst einen Blick auf die zu importierenden Quelldaten:<br />
<br\><br />
<img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/01.png" alt="" /><br />
<br\><br />
Die Hauptkostenstelle <strong>4712 </strong>wird nicht zu 100% verteilt &#8211; auf diesen Fall möchten wir reagieren. Dazu gehen wir wie folgt vor:<br />
<br\><br />
Zu Beginn wird dem Quelldatenfluss eine neue Spalte <em>JoinColumn </em>mithilfe der <em>DerivedColumn </em>- Komponente (dt.: abgeleitete Spalte) hinzugefügt.<br />
Den Wert setzten wir auf 0.<br />
<br\><br />
<img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/02.png" alt="" /><br />
<br\><br />
Dieses „Flag“ dient im späteren Verlauf dazu, eine in jedem Fall wahre Join-Bedingung zu erzeugen, da die Integration Services standardmäßig keinen <em>Cross-Join</em> unterstützen. Hintergrund ist, dass nach der Fehlerüberprüfung <strong>aller</strong> Zeilen an jeder <strong>einzelnen</strong> Zeile abzulesen sein soll, ob irgendwann ein ungültiger Datensatz aufgetreten ist.<br />
<br\><br />
Mithilfe eines <em>Conditional Split</em> (dt.: bedingtes Teilen) trennen wir die gültigen (ID 2 und 3) von den ungültigen Datensätzen (ID 5 und 6).<br />
<br\><br />
<em>Abhängig von Ihren Anforderungen, können sich in diesem Bereich auch mehrere komplexe, miteinander verkettete Operationen ansiedeln, um die gewünschte Trennung zwischen „gültig“ und „ungültig“ zu realisieren.</em><br />
<br\><br />
Am Ausgang der ungültigen Datensätze führen wir ein <em>RowSampling</em> (dt.: Zeilenstichprobe) mit folgenden Einstellungen durch:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/03.png" alt="" /><br />
<br\><br />
<img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/04.png" alt="" /><br />
<br\><br />
Das <em>RowSampling</em> bewirkt, dass entweder <strong>keine oder maximal eine Zeile</strong> weitergeleitet werden. Es dient somit lediglich als Indikator, ob ungültige Datensätze aufgetreten sind oder nicht, unabhängig von ihrer Anzahl.<br />
<br\><br />
Als nächstes legen wir eine neue Variable namens <em>FailOnError </em>vom Datentyp <em>Int32</em> an. Diese Variable entspricht dem oben angekündigten Schalter. Mit ihrer Hilfe schalten wir das Transaktionsverhalten ein oder aus.<br />
<br\><br />
<em>Denkbar wäre hier ein erweitertes Szenario, in dem man durch Paketkonfiguration den Wert der Variable außerhalb des Pakets setzen kann (z.B. Web-Frontend).</em><br />
<br\><br />
In unserem Fall setzten den Wert initial auf <em>0 – </em>das Transaktionsverhalten ist somit vorerst ausgeschaltet.<br />
<br\><br />
<img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/05.png" alt="" /><br />
<br\><br />
Nun fügen wir eine weitere Spalte Namens <em>ErrorFlag </em>mithilfe einer<em> DerivedColumn </em>am Ausgang der Zeilenstichprobe hinzu. Den Wert belegen wir mit dem der <em>FailOnError</em>-Variable, die je nach Konfiguration den Zustand 0 oder 1 hat<strong> ODER </strong>aber auch<strong> </strong><em>NULL</em><strong> </strong>sein kann, nämlich dann, wenn keine ungültigen Datensätze identifiziert wurden.</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/06.png" alt="" /><br />
<br\><br />
Im nächsten Schritt sortieren wir die Daten mithilfe der Sort-Komponente. Dieser Schritt ist notwendig, da die darauffolgende <em>Merge-Join</em> &#8211; Komponente nur mit Daten funktioniert, welche die Eigenschaft <em>isSorted = true</em> besitzen (diese Eigenschaft wird u.a. von der <em>Sort</em>-Komponente gesetzt).</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/07.png" alt="" /><br />
<br\><br />
Anschließend „joinen<em>“</em> wir den Wert des <em>ErrorFlags</em> mithilfe eines <em>Merge-Joins</em> (dt.: Zusammenführungsjoin) und unserer <em>JoinColumn</em> an die gültigen Datensätze (auch hier ist das „Vorschalten“ der <em>Sort</em>-Komponente notwendig).<br />
<br\><br />
Die Konfiguration des <em>Merge-Join’s </em>sieht dabei folgendermaßen aus:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/08.png" alt="" /><br />
<br\><br />
Am Ausgang des <em>Merge-Join‘s</em> sehen unsere Daten dann so aus:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/09.png" alt="" /><br />
<br\><br />
Die letzte und gleichzeitig entscheidende Komponente ist ein <em>Conditional Split</em> mit folgender Konfiguration:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/10.png" alt="" /><br />
<br\><br />
An dieser Stelle „trennt sich die Spreu vom Weizen“ – Abhängig davon, welchen Wert die <em>FailOnError</em> Variable hat, werden hier <strong>entweder</strong> alle gültigen <strong>ODER</strong> keine Datensätze weitergeleitet.<br />
<br\><br />
Nicht vergessen: ändern Sie den Wert der Variable von 0 auf <strong>1</strong>, um das Transaktionsverhalten <strong>ein</strong>zuschalten.<br />
<br\><br />
Zu guter Letzt das versprochene Gesamtbild:</p>
<p><img src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/RR_Transaktionen/11.png" alt="" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2008/integration-services-2008/ssis-error-handling-design-pattern-transaktionen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Deaktivieren von Reporting Services Abonnements</title>
		<link>http://www.ixto.de/blog/sql-server-2005/reportingservices/deaktivieren-von-reporting-services-abonnements/</link>
		<comments>http://www.ixto.de/blog/sql-server-2005/reportingservices/deaktivieren-von-reporting-services-abonnements/#comments</comments>
		<pubDate>Thu, 30 Sep 2010 14:50:16 +0000</pubDate>
		<dc:creator>Sven Bayer</dc:creator>
				<category><![CDATA[Reporting Services 2005]]></category>
		<category><![CDATA[Reporting Services 2008]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=145</guid>
		<description><![CDATA[Wenn man häufiger mit den Abonnements der Reporting Services zu tun hat, musste der ein oder andere, ich leider auch, mit bedauern feststellen, dass es keine Möglichkeit gibt die angelegten Abonnements zu deaktivieren. Um das Verenden eines Berichts zu verhindern, konnte man dessen Abonnement entweder löschen oder den Zeitpunkt für die Ausführung weit in die [...]]]></description>
			<content:encoded><![CDATA[<p>Wenn man häufiger mit den Abonnements der Reporting Services zu tun hat, musste der ein oder andere, ich leider auch, mit bedauern feststellen, dass es keine Möglichkeit gibt die angelegten Abonnements zu deaktivieren. Um das Verenden eines Berichts zu verhindern, konnte man dessen Abonnement entweder löschen oder den Zeitpunkt für die Ausführung weit in die Zukunft verlegen. Für mich zwei Methoden, die nicht wirklich benutzerfreundlich sind, entweder muss ich das Abonnement neu anlegen oder ich muss darauf achten meine Zeitänderungen wieder rückgängig zu machen und hab keine richtige Kontrolle über aktivierte oder deaktivierte Abonnements.</p>
<p> Ich möchte hier kurz beschreiben, wie es möglich ist, unter Verwendung der <em>ReportServer</em> Datenbank, die Ausführung der Abonnements einfach zu verwalten.</p>
<p><span id="more-145"></span><br />
<br\></p>
<h2>Die Grundidee</h2>
<p><br\><br />
Die Reporting Services speichern ihre Abonnements in der zugehörigen DB(Standardname: <em>ReportServer</em>). Die Tabelle in der alle Abonnements aufgeführt sind nennt sich <em>dbo.Subscriptions</em>:</p>
<p><img class="alignnone" title="Tabelle" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SB/blog1.png" alt="" width="1059" height="648" /><br />
<br\><br />
In dieser Tabelle gibt es eine Spalte mit dem Namen <em>InactiveFlags</em>. Bei einem aktiven Abo ist dieser Wert auf 0 gesetzt. Um das Abo zu deaktivieren muss dieser Wert auf 1 geändert werden.<br />
<br\><br />
<br\></p>
<h2>Die Umsetzung</h2>
<p><br\><br />
Zunächst benötigen wir noch einige Tabellen, um die Lesbarkeit zu erhöhen, indem wir die IDs durch die zugehörigen Namen für Bericht, Abonnement und Benutzer ersetzen:</p>
<div>
<table style="border-collapse: collapse;" border="0">
<colgroup span="1">
<col style="width: 191px;" span="1"></col>
<col style="width: 181px;" span="1"></col>
<col style="width: 18px;" span="1"></col>
<col style="width: 251px;" span="1"></col>
</colgroup>
<tbody>
<tr style="background: black;">
<td style="padding-left: 7px; padding-right: 7px; border-top: solid black 1.5pt; border-left: solid black 1.5pt;"><span style="color: white; font-family: Times New Roman; font-size: 10pt;"><strong>Tabelle</strong></span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: solid black 1.5pt;" colspan="2"><span style="color: white; font-family: Times New Roman; font-size: 10pt;"><strong>Information</strong></span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: solid black 1.5pt; border-right: solid black 1.5pt;"> </td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-left: solid black 1.5pt;">
<p style="text-align: justify;"><span style="font-family: Times New Roman; font-size: 10pt;">Dbo.Users u</span></p>
</td>
<td style="padding-left: 7px; padding-right: 7px;">
<p style="text-align: justify;"><span style="font-family: Times New Roman; font-size: 10pt;">Benutzername</span></p>
</td>
<td style="padding-left: 7px; padding-right: 7px; border-right: solid black 1.5pt;" colspan="2">
<p style="text-align: justify;"><span style="font-family: Times New Roman; font-size: 10pt;">u.UserID = OwnerID</span></p>
</td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-left: solid black 1.5pt;">
<p style="text-align: justify;"><span style="font-family: Times New Roman; font-size: 10pt;">Dbo.Catalog c</span></p>
</td>
<td style="padding-left: 7px; padding-right: 7px;">
<p style="text-align: justify;"><span style="font-family: Times New Roman; font-size: 10pt;">Berichtsname</span></p>
</td>
<td style="padding-left: 7px; padding-right: 7px; border-right: solid black 1.5pt;" colspan="2">
<p style="text-align: justify;"><span style="font-family: Times New Roman; font-size: 10pt;">c.ItemID = Report_OID</span></p>
</td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-left: solid black 1.5pt; border-bottom: solid black 1.5pt;">
<p style="text-align: justify;"><span style="font-family: Times New Roman; font-size: 10pt;">[dbo].[ReportSchedule] rs</span></p>
</td>
<td style="padding-left: 7px; padding-right: 7px; border-bottom: solid black 1.5pt;">
<p style="text-align: justify;"><span style="font-family: Times New Roman; font-size: 10pt;">SQL Server Agent Job Name</span></p>
</td>
<td style="padding-left: 7px; padding-right: 7px; border-bottom: solid black 1.5pt; border-right: solid black 1.5pt;" colspan="2">
<p style="text-align: justify;"><span style="font-family: Times New Roman; font-size: 10pt;">SubscriptionID = rs.SubscriptionID</span></p>
</td>
</tr>
</tbody>
</table>
</div>
<p> <br />
<br\><br />
Mit dem nachfolgendem SQL-Statement können wir die passenden Informationen auslesen:<br />
<br\><br />
<span style="font-family: Courier New;"><span style="color: blue;">SELECT<br />
</span>     s<span style="color: gray;">.</span>[SubscriptionID]<br />
     </span><span style="color: gray;">,</span>s<span style="color: gray;">.</span>[Description]<br />
             <span style="color: gray;">,</span>u<span style="color: gray;">.</span>UserName<br />
<span style="color: gray;">             ,</span>c<span style="color: gray;">.</span>Name as ReportName<br />
             <span style="color: gray;">,</span>[InactiveFlags]<br />
             <span style="color: gray;">,</span>rs<span style="color: gray;">.</span>ScheduleID <span style="color: blue;">AS</span> JobName<br />
             <span style="color: gray;">,</span>rs<span style="color: gray;">.</span>ReportAction<br />
             <span style="color: gray;">,</span>[ExtensionSettings]<br />
             <span style="color: gray;">,</span>[Locale]<br />
             <span style="color: gray;">,</span>s<span style="color: gray;">.</span>[ModifiedByID]<br />
             <span style="color: gray;">,</span>s<span style="color: gray;">.</span>[ModifiedDate]<br />
             <span style="color: gray;">,</span>[LastStatus]<br />
             <span style="color: gray;">,</span>[EventType]<br />
             <span style="color: gray;">,</span>[MatchData]<br />
             <span style="color: gray;">,</span>[LastRunTime]<br />
             <span style="color: gray;">,</span>[Parameters]<br />
             <span style="color: gray;">,</span>[DataSettings]<br />
             <span style="color: gray;">,</span>[DeliveryExtension]<br />
             <span style="color: gray;">,</span>[Version]<br />
             <span style="color: gray;">,</span>[ReportZone]<br />
             <span style="color: gray;">,</span>[OwnerID]<br />
             <span style="color: gray;">,</span>[Report_OID]<br />
<span style="color: blue;">FROM</span> [ReportServer]<span style="color: gray;">.</span>[dbo]<span style="color: gray;">.</span>[Subscriptions] s<br />
<span style="color: gray;">             inner </span><span style="color: gray;">join</span> dbo<span style="color: gray;">.</span>Users u <span style="color: blue;">on</span> u<span style="color: gray;">.</span>UserID <span style="color: gray;">=</span> OwnerID<br />
             <span style="color: gray;">inner </span><span style="color: gray;">join</span> [dbo]<span style="color: gray;">.</span>[Catalog] c <span style="color: blue;">on</span> s<span style="color: gray;">.</span>Report_OID <span style="color: gray;">=</span> c<span style="color: gray;">.</span>ItemID<br />
             <span style="color: gray;">inner </span><span style="color: gray;">join</span> [dbo]<span style="color: gray;">.</span>[ReportSchedule] rs <span style="color: blue;">on</span> s<span style="color: gray;">.</span>SubscriptionID <span style="color: gray;">=</span> rs<span style="color: gray;">.</span>SubscriptionID<br />
<br\><br />
Abhängig von den Abonnements sollte die Abfrage in etwa das folgende Ergebnis liefern:</p>
<div>
<table style="border-collapse: collapse;" border="0">
<colgroup span="1">
<col style="width: 126px;" span="1"></col>
<col style="width: 169px;" span="1"></col>
<col style="width: 115px;" span="1"></col>
<col style="width: 109px;" span="1"></col>
<col style="width: 122px;" span="1"></col>
</colgroup>
<tbody>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border: solid 0.5pt;"><span style="font-family: Times New Roman;">SubscriptionID</span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: solid 0.5pt; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;"><span style="font-family: Times New Roman;">Description</span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: solid 0.5pt; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;"><span style="font-family: Times New Roman;">UserName</span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: solid 0.5pt; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">
<p style="text-align: center;"><span style="font-family: Times New Roman;">ReportName</span></p>
</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: solid 0.5pt; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;"><span style="font-family: Times New Roman;">InactiveFlags</span></td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid 0.5pt; border-bottom: solid 0.5pt; border-right: solid 0.5pt;"><span style="font-family: Times New Roman;">929CDEE8-…</span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;"><span style="font-family: Times New Roman;">In &#8216;…&#8217; unter &#8216;Arbeitszeit Übersicht&#8217; speichern</span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Domäne\Bayer</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;"><span style="font-family: Times New Roman;">Arbeitszeit Übersicht</span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">0</td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid 0.5pt; border-bottom: solid 0.5pt; border-right: solid 0.5pt;"><span style="font-family: Times New Roman;">7A4B049E-…</span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;"><span style="font-family: Times New Roman;">In &#8216;…&#8217; unter &#8216;</span><br />
<span style="font-family: Times New Roman;">Fluktuation &#8216; speichern</span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Domäne\Bayer</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Fluktuation</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">0</td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid 0.5pt; border-bottom: solid 0.5pt; border-right: solid 0.5pt;"><span style="font-family: Times New Roman;">23E7F4EF-…</span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;"><span style="font-family: Times New Roman;">In &#8216;…&#8217; unter Haushalt&#8217; speichern</span></td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Domäne\Bayer</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Haushalt</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">0</td>
</tr>
</tbody>
</table>
</div>
<p> <br />
<br\><br />
Mit den oben stehenden Informationen können wir jetzt einzelne Abonnements aktivieren bzw. deaktivieren.<br />
<br\><br />
Für die Deaktivierung kann folgende Query verwendet werden:</p>
<p><span style="font-family: Courier New;">UPDATE Subscriptions set<br />
[InactiveFlags] = 1<br />
where<br />
[SubscriptionID] = &#8216;929CDEE8-…&#8217;<br />
END<br />
</span></p>
<p>Für die Aktivierung kann das gleiche Update-Statement verwendet werden, der Wert <em>InactiveFlags</em> muss jetzt nur auf 0 gesetzt werden.<br />
<br\><br />
<br\></p>
<h2>Ausführung von Abonnements</h2>
<p><br\><br />
Gelegentlich kommt es vor, dass ein Abonnement außerhalb der geplanten Zeiten durchgeführt werden soll.<br />
<br\><br />
Da die Ausführung der Abonnements über den SQL Server Agent gesteuert wird, haben wir die Möglichkeit die passenden Jobs von Hand zu starten. Dies kann im SQL Server Management Studio erfolgen.</p>
<p><img title="Tabelle" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SB/blog2.png" alt="" /><br />
<br\><br />
Oder es können vordefinierte gespeicherte Prozeduren aus der msdb Datenbank verwendet werden.<br />
<br\><br />
<em>EXEC msdb.dbo.sp_start_job ‚251601B4…&#8217;<br />
</em><br />
<br\><br />
Die IDs der für die angelegten Jobs und die IDs für die zugehörigen Abos sind in der <em>[dbo].[ReportSchedule] </em>Tabelle der <em>ReportServer</em> DB hinterlegt. Wenn man diese Tabelle noch mit der <em>dbo.Subscriptions</em> verbindet:</p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">SELECT</span><br />
<span style="color: #0000ff;">   </span>[ScheduleID]<br />
  </span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: gray;">,</span>[ReportID]<br />
</span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: gray;">  ,</span>rs<span style="color: gray;">.</span>[SubscriptionID]<br />
</span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: gray;">  ,</span>s<span style="color: gray;">.<span style="color: blue;">Description<br />
</span></span></span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: gray;">  ,</span>[ReportAction]<br />
</span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">FROM</span> [dbo]<span style="color: gray;">.</span>[ReportSchedule] rs<br />
</span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: gray;">INNER </span><span style="color: gray;">JOIN</span> dbo<span style="color: gray;">.</span>Subscriptions s <span style="color: blue;">ON</span> rs<span style="color: gray;">.</span>SubscriptionID <span style="color: gray;">=</span> s<span style="color: gray;">.</span>SubscriptionID<br />
</span><br />
können die JobIDs den zugehörigen Abos zugeordnet werden.<br />
<br\><br />
<br\></p>
<h2>Der passende Bericht</h2>
<p><br\><br />
Nachdem die Grundlagen für die Deaktivierung bzw. Aktivierung der Abonnements geklärt sind, kann ein einfacher Bericht erstellt werden, mit dem die Ausführung und der Status des Abos gesteuert werden kann.</p>
<p><img title="Tabelle" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SB/blog3.png" alt="" /><br />
<br\><br />
Für den Bericht muss eine Datenquelle für die <em>ReportServer</em> Datenbank erstellt werden und die folgenden Parameter werden benötigt, um die zugehörigen Funktionalitäten zu gewährleisten:</p>
<div>
<table style="border-collapse: collapse;" border="0">
<colgroup span="1">
<col style="width: 187px;" span="1"></col>
<col style="width: 83px;" span="1"></col>
<col style="width: 372px;" span="1"></col>
</colgroup>
<tbody>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border: solid 0.5pt;">Parameter</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: solid 0.5pt; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Typ</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: solid 0.5pt; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Beschreibung</td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid 0.5pt; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">SetActiv</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Text (0,1) Default: 0</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">0 – Keine Aktion wird ausgeführt1 – Der Status des ausgewählten Abos wird geändert</td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid 0.5pt; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">SubscriptionID</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Text</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">ID des Abos.Blank und null Value aktiviert</td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid 0.5pt; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">JobName</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Text</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">ID des JobsBlank und null Value aktiviert</td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid 0.5pt; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">InactiveFlags</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Text</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Neue Status für das zugehörige Abo0 – aktiviert1 – deaktiviert</p>
<p>Blank und null Value aktiviert</td>
</tr>
<tr>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid 0.5pt; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Execute</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Text (0,1)</td>
<td style="padding-left: 7px; padding-right: 7px; border-top: none; border-left: none; border-bottom: solid 0.5pt; border-right: solid 0.5pt;">Job0 – nicht ausführen1 &#8211; ausführen</td>
</tr>
</tbody>
</table>
</div>
<p><br\><br />
Des Weiteren brauchen wir ein Dataset, das zum einen die Informationen, wie vorhandene Abos, Berichtsnamen, etc. ermittelt, um sie im Bericht anzuzeigen, zum anderen aber auch Abos aktiviert und deaktiviert, sowie einzelne Jobs ausführt. Die Steuerung der Ausführung wird durch die einzelnen Parameter vollzogen und einzelne Teile der Abfrage übergangen oder ausgeführt:</p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">if</span> @SetActiv <span style="color: gray;">=</span> 1<br />
</span><span style="color: blue; font-family: Courier New; font-size: 10pt;">BEGIN<br />
</span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">UPDATE</span> Subscriptions <span style="color: blue;">set </span></span><span style="font-family: Courier New; font-size: 10pt;">[InactiveFlags] <span style="color: gray;">=</span> @InactiveFlags<br />
</span><span style="color: blue; font-family: Courier New; font-size: 10pt;">where<br />
    </span><span style="font-family: Courier New; font-size: 10pt;">[SubscriptionID] <span style="color: gray;">=</span> @id<br />
</span><span style="color: blue; font-family: Courier New; font-size: 10pt;">END<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">if</span> @Execute <span style="color: gray;">=</span> 1<br />
</span><span style="color: blue; font-family: Courier New; font-size: 10pt;">BEGIN<br />
</span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">EXEC</span> msdb<span style="color: gray;">.</span>dbo<span style="color: gray;">.<span style="color: maroon;">sp_start_job @JobName<br />
</span></span></span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">WAITFOR</span><br />
<span style="color: blue;">delay </span><span style="color: red;">&#8216;00:00:05&#8242;<br />
</span></span><span style="color: blue; font-family: Courier New; font-size: 10pt;">END<br />
</span></p>
<p><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">SELECT</span> s<span style="color: gray;">.</span>SubscriptionID<span style="color: gray;">,</span> rs<span style="color: gray;">.</span>ScheduleID <span style="color: blue;">AS</span> JobName<span style="color: gray;">,</span> s<span style="color: gray;">.</span>OwnerID<span style="color: gray;">,</span> u<span style="color: gray;">.</span>UserName<span style="color: gray;">,</span> s<span style="color: gray;">.</span>Report_OID<span style="color: gray;">,</span> c<span style="color: gray;">.</span>Name <span style="color: blue;">AS</span> Reportname<span style="color: gray;">,</span> s<span style="color: gray;">.<span style="color: blue;">Description </span><span style="color: blue;">AS</span> SubDesc,</span> s<span style="color: gray;">.</span>InactiveFlags <span style="color: blue;">AS</span> Active<span style="color: gray;">, </span></span><span style="font-family: Courier New; font-size: 10pt;">s<span style="color: gray;">.</span>ExtensionSettings<span style="color: gray;">,</span> s<span style="color: gray;">.</span>Locale<span style="color: gray;">,</span> s<span style="color: gray;">.</span>ModifiedByID<span style="color: gray;">,</span> s<span style="color: gray;">.</span>ModifiedDate<span style="color: gray;">,</span> s<span style="color: gray;">.</span>LastStatus<span style="color: gray;">,</span> s<span style="color: gray;">.</span>EventType<span style="color: gray;">,</span> s<span style="color: gray;">.</span>MatchData<span style="color: gray;">,</span> s<span style="color: gray;">.</span>LastRunTime<span style="color: gray;">,</span> s<span style="color: gray;">.<span style="color: green;">Parameters<span style="color: gray;">,</span> s<span style="color: gray;">.</span>DataSettings<span style="color: gray;">, </span></span></span></span><span style="font-family: Courier New; font-size: 10pt;">s<span style="color: gray;">.</span>DeliveryExtension<span style="color: gray;">,</span> s<span style="color: gray;">.<span style="color: blue;">Version<span style="color: gray;">,</span> s<span style="color: gray;">.</span>ReportZone<br />
</span></span></span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">FROM</span> Subscriptions <span style="color: blue;">AS</span> s<br />
   </span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: gray;">INNER </span><span style="color: gray;">JOIN </span></span><span style="font-family: Courier New; font-size: 10pt;">Users <span style="color: blue;">AS</span> u <span style="color: blue;">ON</span> u<span style="color: gray;">.</span>UserID <span style="color: gray;">=</span> s<span style="color: gray;">.</span>OwnerID<br />
   <span style="color: gray;">INNER </span><span style="color: gray;">JOIN </span></span><span style="font-family: Courier New; font-size: 10pt;"><span style="color: blue;">Catalog </span><span style="color: blue;">AS</span> c <span style="color: blue;">ON</span> s<span style="color: gray;">.</span>Report_OID <span style="color: gray;">=</span> c<span style="color: gray;">.</span>ItemID<br />
   <span style="color: gray;">INNER </span><span style="color: gray;">JOIN </span></span><span style="font-family: Courier New; font-size: 10pt;">ReportSchedule <span style="color: blue;">AS</span> rs <span style="color: blue;">ON</span> s<span style="color: gray;">.</span>SubscriptionID <span style="color: gray;">=</span> rs<span style="color: gray;">.</span>SubscriptionID<br />
</span><br />
<br\><br />
Im unteren Teil der Abfrage werden die Informationen ermittelt, im oberen Teil wird zunächst der Status des Abos aktualisiert oder der ausgewählte Job gestartet. Dadurch, dass das Statusänderungen und Jobausführungen über die Links in der Tabelle gesteuert werden, ist immer nur einer der beiden Parameter @SetActiv und @Execute eins und es wird immer nur eine der beiden Aktionen ausgeführt.<br />
<br\><br />
Um die Daten anzuzeigen erstellen wir eine einfache Tabelle:<br />
<img title="Tabelle" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SB/blog3a.png" alt="" /><br />
<br\><br />
Für das Feld Aktiv wird die folgende Expression: <span style="font-family: Courier New; font-size: 10pt;">=iif(Fields!Active.Value = 0,<span style="color: #a31515;">&#8220;Aktiv&#8221;</span>,<span style="color: #a31515;">&#8220;Deaktiviert&#8221;</span>) </span>verwendet und die folgende Aktion, für die Änderung des Status, definiert:<br />
<img title="Tabelle" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SB/blog4.png" alt="" /><br />
<br\><br />
Zum Schluss muss noch das Ausführen des Jobs ermöglicht werden. Hierfür definieren wir eine Aktion für das Textfeld Execute:<br />
<img title="Tabelle" src="http://blog.ixtoprod.s15244651.onlinehome-server.info/blogbilder/SB/blog5.png" alt="" /><br />
Jetzt ist der Bericht soweit fertig, dass der Status und das Ausführen der Abos verwaltet werden kann, birgt aber noch die ein oder andere Gefahr in sich. So wird z.B. ein Abo erneut ausgeführt, wenn man den Bericht nach einem <em>Execute </em>aktualisiert. Für eine erste Demonstration sollte er aber reichen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2005/reportingservices/deaktivieren-von-reporting-services-abonnements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spaltenreihenfolge in Drillthrough Actions</title>
		<link>http://www.ixto.de/blog/sql-server-2008/spaltenreihenfolge-in-drillthrough-actions/</link>
		<comments>http://www.ixto.de/blog/sql-server-2008/spaltenreihenfolge-in-drillthrough-actions/#comments</comments>
		<pubDate>Fri, 10 Sep 2010 14:05:44 +0000</pubDate>
		<dc:creator>Marcel Ebner</dc:creator>
				<category><![CDATA[Analysis Services 2008]]></category>
		<category><![CDATA[MDX im SQL Server 2008]]></category>
		<category><![CDATA[SQL Server 2008]]></category>

		<guid isPermaLink="false">http://www.ixto.de/blog/?p=142</guid>
		<description><![CDATA[Wer schon einmal Excel Drillthrough-Actions in einem Cube erstellt hat, wird sich mit Sicherheit mindestens zweimal durch das Fenster &#8220;Drillthroughspalten&#8221; geklickt haben, schließlich kann es kaum vorkommen, dass man schon beim ersten Mal exakt die Informationen trifft, die der Kunde nach der Präsentation des Drillthrough-Features für beachtenswert hält. Entweder hat man die falschen Dimensionen und [...]]]></description>
			<content:encoded><![CDATA[<p>Wer schon einmal Excel Drillthrough-Actions in einem Cube erstellt hat, wird sich mit Sicherheit mindestens zweimal durch das Fenster &#8220;Drillthroughspalten&#8221; geklickt haben, schließlich kann es kaum vorkommen, dass man schon beim ersten Mal exakt die Informationen trifft, die der Kunde nach der Präsentation des Drillthrough-Features für beachtenswert hält. Entweder hat man die falschen Dimensionen und Attribute gewählt oder die Reihenfolge ist unglücklich.<br />
 <span id="more-142"></span><br />
<br\><br />
Wer dann, mit Hoffnung im Herzen und einem Mausklick rechts, versucht, im Kontextmenü den Eintrag &#8220;Reihenfolge ändern&#8221; oder &#8220;Dimension auswählen&#8221; zu finden, wird bitter enttäuscht. Zu sehen gibt&#8217;s nur &#8220;Löschen&#8221;.</p>
<p><img src="http://reborn-resistance.com/user/ric/ixto/blog/me/01_Kontextmenue.jpg" alt="" /><br />
<br\><br />
So bleibt der Versuch, <strong><em>zwischen</em></strong> zwei vorhandenen Dimensionen noch eine dritte hinzuzufügen oder allein einen Eintrag zu ändern, von Misserfolg gekrönt und man darf sich die Aktionsspalten nochmal ganz von vorn zusammenklicken. Will man darüber hinaus gar <strong><em>die Reihenfolge der Attribute</em></strong> einer Dimension ändern, ist man (fast) hilflos der von Visual Studio angebotenen Reihenfolge ausgeliefert, deren Sortierungsgrundlage wohl immer ein Geheimnis bleiben wird.<br />
<br\><br />
Zum Glück gibt es noch die Möglichkeit im XMLA Script des Cubes selbst einzugreifen.<br />
<br\><br />
Hierzu sollte man im Reiter &#8220;Aktionen&#8221; im Fenster &#8220;Aktionsplaner&#8221; die eben erstellte Drillthrough-Aktion auswählen, in der Eigenschaft [ID] den entsprechenden Wert auslesen und im Projektmappenexplorer mit Rechtsklick auf den entsprechenden Cube &#8220;Code anzeigen&#8221; wählen. VisualStudio öffnet eine neue Reiterkarte mit der Cubedefinition im XMLA Format, mit Strg+F kann man den Abschnitt mit der Drillthrough-Aktion schnell finden. (Die XML-Elemente &lt;ID&gt;,&lt;Name&gt; und die &lt;Columns&gt; Sequenz müssen vorhanden sein, das Actions-Element ist unterhalb der KPIs zu finden)</p>
<p><img src="http://reborn-resistance.com/user/ric/ixto/blog/me/02_XMLA.jpg" alt="" /><br />
<br\><br />
Nun kann man die Elemente &lt;Column&gt; innerhalb des &lt;Columns&gt;-Element per Cut&amp;Paste verschieben. Leider gibt es (bisher) keine Möglichkeit den Anzeigenamen der Spalten in Excel festzulegen, aber, immerhin, die Reihenfolge der Attribute (Column) ist nun frei wählbar. Speichert man dann die Änderungen ab, verändert sich auch die Anzeige der Dimensionsreihenfolge im Fenster &#8220;Drillthroughspalten&#8221;, zwar erkennt der Designer nur, dass eine <strong><em>Dimension</em></strong> vor den Measures steht und zeigt dementsprechend <strong><em>alle</em></strong> Attribute der Dimension vor dem Measure an, die Reihenfolge der Spalten aber, wie sie im XMLA Script festgelegt ist, bleibt beim Exceldrillthrough erhalten.</p>
<p><img src="http://reborn-resistance.com/user/ric/ixto/blog/me/03_Sorted.jpg" alt="" /><br />
<br\><br />
<span style="font-size: 9pt;">(<em>nur Promotion Name vor SalesSummary, nicht auch End Date und Start Date)</em></span><br />
<br\><br />
<img src="http://reborn-resistance.com/user/ric/ixto/blog/me/04_Excel.jpg" alt="" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ixto.de/blog/sql-server-2008/spaltenreihenfolge-in-drillthrough-actions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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.<br />
<br\><br />
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.<br />
<span id="more-122"></span><br />
<br\><br />
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>.<br />
<br\><br />
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.<br />
<br\><br />
Diese drei Lookup-Funktionen sollen hier demonstriert werden.<br />
<br\></p>
<pre><code><span style="font-family: Calibri; font-size: 12pt;"><strong>

Lookup</strong>

				</span></code></pre>
<p><br\><br />
<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 />
<br\><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 />
<br\><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.<br />
<br\><br />
<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><br />
<br\><br />
<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:<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>
	</channel>
</rss>

