<?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/"
	
	xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>tactek data systems</title>
	<atom:link href="http://www.tactek.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.tactek.com</link>
	<description>Business Intelligence and I.T. Service Management</description>
	<lastBuildDate>Thu, 29 Dec 2011 22:45:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Announcing TacTools for SSIS: Null Manager</title>
		<link>http://www.tactek.com/2011/12/announcing-tactools-for-ssis-null-manager/</link>
		<comments>http://www.tactek.com/2011/12/announcing-tactools-for-ssis-null-manager/#comments</comments>
		<pubDate>Thu, 29 Dec 2011 22:29:13 +0000</pubDate>
		<dc:creator>Chris Bianchi</dc:creator>
				<category><![CDATA[Products]]></category>
		<category><![CDATA[SQL Server Integration Services]]></category>

		<guid isPermaLink="false">http://www.tactek.com/?p=286</guid>
		<description><![CDATA[Tactek Data Systems is pleased to announce TacTools for SSIS: Null Manager. This data flow component designed for Microsoft SQL<a href="http://www.tactek.com/2011/12/announcing-tactools-for-ssis-null-manager/" class="searchmore">Read the Rest...</a><div class="clr"></div>]]></description>
			<content:encoded><![CDATA[<p>Tactek Data Systems is pleased to announce <a title="TacTools for SSIS: Null Manager" href="http://www.tactek.com/tactools-for-ssis-null-manager/"><strong>TacTools for SSIS: Null Manager</strong></a>. This data flow component designed for Microsoft SQL Server Integration Services 2008 helps overcome the challenges of dealing with NULL values in various SSIS tasks.</p>
<p><span id="more-286"></span></p>
<p>Null values make conditional splits, derived column calculations, script tasks and other components cumbersome to deal with. This in-place column replacement component makes short work of:</p>
<ul>
<li>Replacing NULL values with empty strings.</li>
<li>Replacing empty strings with NULL values.</li>
<li>Replacing NULL values with a substitute string (e.g. &#8220;Unknown&#8221;).</li>
</ul>
<p>Replacing NULL values can also improve the user-acceptance of your reporting environments as well!</p>
<p>This tool is available now for only $9.95 per computer. TacTools for SSIS are provided as individual components so unlike other SSIS task packages, you only buy what you need. And you&#8217;ll find our prices to be much lower, per component, than virtually all competitors&#8217; products.</p>
<p>Don&#8217;t let NULL field values give you any more headaches in your SSIS packages. Try <a title="TacTools for SSIS: Null Manager" href="http://www.tactek.com/tactools-for-ssis-null-manager/">TacTools for SSIS: Null Manage</a>r.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tactek.com/2011/12/announcing-tactools-for-ssis-null-manager/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
	</item>
		<item>
		<title>Live Table Load with SQL Server Integration Services</title>
		<link>http://www.tactek.com/2011/02/live-table-load-with-sql-server-integration-services/</link>
		<comments>http://www.tactek.com/2011/02/live-table-load-with-sql-server-integration-services/#comments</comments>
		<pubDate>Tue, 01 Mar 2011 04:15:59 +0000</pubDate>
		<dc:creator>Chris Bianchi</dc:creator>
				<category><![CDATA[Microsoft SQL Server]]></category>
		<category><![CDATA[SQL Server Integration Services]]></category>
		<category><![CDATA[Concepts]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[ETL]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.tactek.com/?p=237</guid>
		<description><![CDATA[There are many techniques for doing quick, full loads of data with Microsoft SQL Server Integration Services (SSIS) for a<a href="http://www.tactek.com/2011/02/live-table-load-with-sql-server-integration-services/" class="searchmore">Read the Rest...</a><div class="clr"></div>]]></description>
			<content:encoded><![CDATA[<p>There are many techniques for doing quick, full loads of data with Microsoft SQL Server Integration Services (SSIS) for a reporting environment. This one is the quick change artist of the bunch. Our goal is to create a mechanism for doing a full data table load with little to no interruption to production reports that may rely on that table’s data. We’re going to quick load 30,000 or more records of data in the blink of an eye using a very simple, if commonly overlooked, technique.<span id="more-237"></span></p>
<h2>The Method at a Glance</h2>
<p>The beauty of the technique is simplicity in itself. We will load the data via a quick, three-step process.</p>
<ol>
<li>Create a staging table with the same structure of the destination table.</li>
<li>Load the data into the staging table.</li>
<li>Drop the destination table and rename the staging table to the destination table name.</li>
</ol>
<h2>The Basic SSIS Project</h2>
<p>Launch Microsoft SQL Server Business Intelligence Development Studio (BIDS) and create your SSIS project. Create your package, and configure your source and destination Connection Managers.</p>
<p>Our Control Flow will consist of three steps as outlined above. We’ll first need an Execute SQL Task followed by a Data Flow Task and finally another Execute SQL Task.</p>
<p><a rel="lightbox" href="http://www.tactek.com/wp-content/uploads/2011/02/SSISControlFlow.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="SSISControlFlow" src="http://www.tactek.com/wp-content/uploads/2011/02/SSISControlFlow_thumb.jpg" border="0" alt="SSISControlFlow" width="162" height="230" /></a></p>
<p>The sources for both Execute SQL Tasks will be your destination Connection Manager.</p>
<h2>Create the Staging Table</h2>
<p>You can create the required staging script relatively quickly using SQL Server Management Studio (SSMS) as follows:</p>
<p>1. Connect to the database where the destination table is stored.</p>
<p>2. Locate the destination table in the Object Explorer view.</p>
<p>3. Right-click the destination table and select <strong>Script table as: DROP and CREATE to: New Query Editor Window</strong>. <span style="color: #ff0000;"><strong>Be careful not to execute your script at this point!</strong></span> It is best to be connected as a user with read-only permission to the database to ensure that this script is not accidently executed.</p>
<p>4. Select <strong>Edit: Find and Replace: Quick Replace</strong>.</p>
<p>5. In the <strong>Find what</strong> text box, type <strong>[dbo].[&lt;<em>table name&gt;</em>]</strong>, and in the <strong>Replace with</strong> box, type <strong>[dbo].[STAGE_<em>&lt;tablename&gt;]</em></strong>. For example, if the table is called <strong>History</strong>, enter <strong>[dbo].[History] </strong>and <strong>[dbo].[STAGE_History] </strong>respectively. This will become our load table.</p>
<p>6. Click the <strong>Replace All</strong> button.</p>
<p>7. If you have any indexes or primary key constraints, you will need to rename these as well in the creation script. A SQL Server database may not contain two indexes with the same logical name. In reality, you should keep only the primary key constraint. Other indexes can be removed from the script altogether to potentially improve load performance.</p>
<p>The script that now exists in your Query Editor Window is the T-SQL script for your first Execute SQL Task. It checks for the existence of the STAGE table, performs a DROP if it exists, and then CREATEs a new STAGE table.</p>
<p>Execute the task and ensure that the STAGE table is created in the destination database. It will need to exist for the next step in our process.</p>
<p><a rel="lightbox" href="http://www.tactek.com/wp-content/uploads/2011/02/SSISControlFlow-2.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="SSISControlFlow-2" src="http://www.tactek.com/wp-content/uploads/2011/02/SSISControlFlow-2_thumb.jpg" border="0" alt="SSISControlFlow-2" width="173" height="239" /></a></p>
<h2>Populating the Staging Table</h2>
<p>Next, open the Data Flow Task control. This is where you will load data from the source table to the destination STAGE table. Using the appropriate Data Flow Source, Transformations and Data Flow Destination, build the ETL that you would normally use to populate the destination table. For this example, a very direct load with no transformations is used. You can use any necessary transformation controls for your particular situation.</p>
<p><a rel="lightbox" href="http://www.tactek.com/wp-content/uploads/2011/03/SSISDataFlow.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="SSISDataFlow" src="http://www.tactek.com/wp-content/uploads/2011/03/SSISDataFlow_thumb.jpg" border="0" alt="SSISDataFlow" width="182" height="205" /></a></p>
<p>When the script is executed in sequence, your STAGE table is guaranteed to be empty due to the first Execute SQL Task. In the absence of indexing, this should be a relatively fast load if the data is reasonable. Note that this method may not be the best method for the full load of a table with very wide rows (lots of TEXT or IMAGE type fields).</p>
<p>Return to the Control Flow and execute this task to ensure that the data can load into the STAGE table as expected.</p>
<p>In order to prevent Validation errors prior to the creation of the STAGE table, set the <strong>DelayValidation</strong> property of the Data Flow Task to <strong>True</strong>.</p>
<p><a rel="lightbox" href="http://www.tactek.com/wp-content/uploads/2011/03/SSISDelayValidation.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="SSISDelayValidation" src="http://www.tactek.com/wp-content/uploads/2011/03/SSISDelayValidation_thumb.jpg" border="0" alt="SSISDelayValidation" width="244" height="235" /></a></p>
<h2>The Quick Change</h2>
<p>The last step in the process is the quick change technique. This can be scripted into a single T-SQL script and saved into the final Execute SQL Task.</p>
<p>First, script any indexes from the destination table (with the exception of the primary key destination which was created along with the STAGE table above) as CREATE statements via SQL Server Management Studio (SSMS). Script these to new Query Editor windows.</p>
<p>Second, script the destination table (<em>not </em>the STAGE table) as DROP to a new Query Editor window. The DROP statement includes an existing table check.</p>
<p>Now compose a single T-SQL script as follows:</p>
<p>1. In the DROP statement’s Query Editor window, after the GO following the IF…DROP… statement, enter <strong>EXEC sp_rename ‘STAGE_&lt;tablename&gt;’, ‘&lt;tablename&gt;’</strong> (include the single quotes). Follow this by a <strong>GO </strong>statement. This calls the sp_rename stored procedure which allows you to rename a table or other database object. <strong><em>Example: EXEC sp_rename ‘STAGE_History’, ‘History’</em></strong></p>
<p>2. Next, enter<strong> EXEC sp_rename ‘&lt;name you gave the STAGE primary key&gt;’, ‘&lt;name of the real primary key&gt;’ </strong>and a <strong>GO </strong>command. <strong><em>Example: EXEC sp_rename ‘PK_STAGE_History’, ‘PK_History’</em></strong></p>
<p>3. After this, paste the <strong>CREATE INDEX</strong> scripts from above in sequence.</p>
<p>Basically, you are writing a script that recreates the entire destination table including all indexes. Below is an example script created from the <strong>ReportServer.History</strong> table from a default Microsoft SQL Server Reporting Services (SSRS) database. This example assumes that the STAGE table is named <em>STAGE_History</em> and that the primary key on the STAGE table is called <em>PK_STAGE_History</em>.</p>
<blockquote><p>USE [ReportServer]<br />
GO</p>
<p>/****** Object:  Table [dbo].[History]    Script Date: 02/28/2011 23:34:29 ******/<br />
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N&#8217;[dbo].[History]&#8216;) AND type in (N&#8217;U'))<br />
DROP TABLE [dbo].[History]<br />
GO</p>
<p>EXEC sp_rename &#8216;STAGE_History&#8217;, &#8216;History&#8217;<br />
GO</p>
<p>EXEC sp_rename &#8216;PK_STAGE_History&#8217;, &#8216;PK_History&#8217;<br />
GO</p>
<p>CREATE UNIQUE CLUSTERED INDEX [IX_History] ON [dbo].[History]<br />
(<br />
[ReportID] ASC,<br />
[SnapshotDate] ASC<br />
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]<br />
GO</p>
<p>CREATE NONCLUSTERED INDEX [IX_SnapshotDataID] ON [dbo].[History]<br />
(<br />
[SnapshotDataID] ASC<br />
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]<br />
GO</p></blockquote>
<p>Since we have tested population of the STAGE table step, it should be relatively safe to execute this script for testing purposes. <strong><span style="color: #ff0000;">Please ensure that you have appropriate backups and are using a development environment until you are certain that the script will work properly!</span></strong></p>
<p>If the test was successful, paste this script into the final Execute SQL Task.</p>
<h2>Executing the Package</h2>
<p>When you execute the package, you are building a STAGE table separate from the active reporting/production table and populating it. Only during the final Execute SQL Task – which should execute very quickly – is there any table locking or potential for a failed query. Since the scripts check the existence of tables prior to drops and the STAGE table validation in the Data Flow Task is delayed, the package execution should be relatively bullet-proof.</p>
<p><a rel="lightbox" href="http://www.tactek.com/wp-content/uploads/2011/03/SSISControlFlow-3.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="SSISControlFlow-3" src="http://www.tactek.com/wp-content/uploads/2011/03/SSISControlFlow-3_thumb.jpg" border="0" alt="SSISControlFlow-3" width="158" height="228" /></a></p>
<h2>Conclusion</h2>
<p>Provided you have the data storage to support it, this is a vastly superior alternative to a TRUNCATE and INSERT method. I have multiple tables that utilize this method in various production environments and have not yet experienced any significant issues from using it. If you decide to load multiple tables in the same script in this way, I encourage you to use Sequence Containers if for no other reason than to group each flow together and gain some control over memory utilization.</p>
<p>Before using any full load method, you need to decide how best to load data for your particular table. Do you require periodic refreshes of table data while applications and/or users are executing reports? This method may be a very reliable (and fast) option. This method is very good for master data-type tables but is not well-suited for large, transactional tables that may be very wide. In most production environments, a variety of load methods may be required.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tactek.com/2011/02/live-table-load-with-sql-server-integration-services/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/SSISControlFlow_thumb.jpg" />
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/SSISControlFlow_thumb.jpg" medium="image">
			<media:title type="html">SSISControlFlow</media:title>
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/SSISControlFlow-2_thumb.jpg" medium="image">
			<media:title type="html">SSISControlFlow-2</media:title>
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/03/SSISDataFlow_thumb.jpg" medium="image">
			<media:title type="html">SSISDataFlow</media:title>
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/03/SSISDelayValidation_thumb.jpg" medium="image">
			<media:title type="html">SSISDelayValidation</media:title>
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/03/SSISControlFlow-3_thumb.jpg" medium="image">
			<media:title type="html">SSISControlFlow-3</media:title>
		</media:content>
	</item>
		<item>
		<title>Designing a Reporting Database Environment</title>
		<link>http://www.tactek.com/2011/02/designing-a-reporting-database-environment/</link>
		<comments>http://www.tactek.com/2011/02/designing-a-reporting-database-environment/#comments</comments>
		<pubDate>Sat, 26 Feb 2011 06:01:20 +0000</pubDate>
		<dc:creator>Chris Bianchi</dc:creator>
				<category><![CDATA[Business Intelligence Concepts]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Concepts]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[DataMart]]></category>
		<category><![CDATA[ETL]]></category>
		<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Reporting]]></category>

		<guid isPermaLink="false">http://www.tactek.com/?p=227</guid>
		<description><![CDATA[As your production data grows, you will ultimately discover a need for a reporting database environment &#8211; that is, a<a href="http://www.tactek.com/2011/02/designing-a-reporting-database-environment/" class="searchmore">Read the Rest...</a><div class="clr"></div>]]></description>
			<content:encoded><![CDATA[<p>As your production data grows, you will ultimately discover a need for a reporting database environment &#8211; that is, a database separate from production that allows ad hoc queries and reports to be generated from production data. The benefits of such a database are numerous and should not be overlooked. If your reports are currently sourced directly from a production database, then you should seriously consider this information. This article explores the need for such databases and design considerations for such an environment.</p>
<p><span id="more-227"></span></p>
<h2>What is a Reporting Database?</h2>
<p>Quite simply, a reporting database is a database that is <em>separate</em> from your production environment but contains data from your production environment. It exists for the purpose of ad hoc queries and reporting without the risk of direct production connection and is optimized with reporting needs rather than operational needs in mind. Additionally, a reporting database may contain data from <em>multiple</em> production applications allowing you to create cross-application dashboards and queries that might not otherwise be possible.</p>
<p> <div id="attachment_228" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/ReportDB1.jpg" rel="lightbox[227]"><img class="size-medium wp-image-228" title="Report Database Architecture" src="http://www.tactek.com/wp-content/uploads/2011/02/ReportDB1-300x291.jpg" alt="Report Database Architecture" width="300" height="291" /></a><p class="wp-caption-text">Report Database Architecture</p></div><br />
<h2>Why do I need a Reporting Database?</h2>
<p>There are numerous benefits to using a reporting database. Let&#8217;s explore a few of the largest benefits.</p>
<p><strong>1. Report queries do not execute against the production environment.</strong></p>
<p>While it is sometimes convenient to report data in real time, in almost all cases near real time is more than adequate. Most data simply does not change as rapidly as we&#8217;d like to think and due to the cyclic nature of reports, having data driven by the second is not very beneficial. It is quite possible to update a reporting database from production on frequent intervals &#8211; even every few minutes.</p>
<p>The production environment is also quite busy. It has transactional processing to do, after all. Considering how easy it is to write a <em>bad</em> query (e.g. a full-text search on a non-indexed field with tens of thousands to millions of data rows), and the security considerations needed to prevent damaging queries such as TRUNCATE, DROP, and ALTER statements, executing queries directly against production environments simply isn&#8217;t <em>safe</em>.</p>
<p><strong>2. Reporting database tables can be optimized for reporting.</strong></p>
<p>Your production system is optimized via indexing and constraint mechanisms to support your production application. These indexes may not necessarily be adequate for your reporting needs. Consider a help desk ticketing application, for example. Your production application may frequently search for tickets that are open and the assigned technician is a specific person. Your reports, on the other hand, might be more concerned about how long tickets are open or tickets that are closed within a particular date range. While the source data is the same, the WHERE clauses of these queries are vastly different which reason that the indexing for the tables may also need to be vastly different.</p>
<p>Reporting databases can also contain data stored in a different format than production. Your production application may use proprietary data types or may contain high orders of normalization. If you find yourself constantly running the same data parsing expressions or making the same JOIN expressions over and over again for your reporting needs, then you may find performance improvement in storing that data in a denormalized form.</p>
<p><strong>3. Reporting databases can be clean.</strong></p>
<p>While not quite reaching the cleanliness of a full-fledged data warehouse, the nature of the extract-transform-load (ETL) processes that exist between your production database and reporting database allow you to clean data for reporting purposes. Suppose your application contains a field that contains a logical flag &#8211; typically &#8220;true&#8221; or &#8220;false&#8221; &#8211; as a character expression. If the flag isn&#8217;t set, you may experience a NULL value as well. The ETL can be written to take this into consideration by substituting NULL values for its appropriate default (likely &#8220;false&#8221;). Corrupt data records can be discarded, calculated fields can be inserted, and any other benefit of an ETL intermediary can be realized.</p>
<p><strong>4. Reporting databases can contain data from multiple production applications.</strong></p>
<p>This may well be one of the largest benefits to using a reporting database. Data from multiple sources can be combined into a &#8220;one-stop-shop&#8221; for reporting. This allows some of the benefits of application integration &#8211; such as multi-application dashboards &#8211; without the need for full application integration. <strong>Example:</strong> Data loaded from our help desk ticketing application is stored in the same database as data loaded from our call accounting system (CAS). Associate John was on the phone for 4 hours yesterday and opened 27 service tickets for an average of 9 minutes per call. Associate Jane was on the phone for 3 hours and opened 12 service tickets for an average of 15 minutes per call. Perhaps Jane dealt with more demanding customers or could use some additional training.</p>
<h2>Designing the Reporting Database</h2>
<p>Too often, a developer&#8217;s first inclination when configuring a reporting database is to simply copy the production database to another location and start pointing reports to it. Unless the production database is very small, this is generally a very poor approach to a reporting database environment.</p>
<p><strong>What data do you <em>really</em> need?</strong></p>
<p>First, consider the source data. If none of your reports consider transactional data over a year or two years old, there is no need to waste time, resources, and storage moving three year old transactions into the reporting database. Performance is key. If you don&#8217;t need to query a million rows to execute your reports adequately, then don&#8217;t store a million rows.</p>
<p>Another consideration along this same line is field selection. Most production applications, especially packaged applications, contain some level of legacy data structure. There are fields that exist purely for backwards compatibility to previous versions. There may also be fields necessary to the production application that you may never have a need to report on, as well.</p>
<p>With careful analysis, you may find that reports only require a small percentage of production data to be kept &#8220;fresh&#8221; in your reporting database and still ensure adequate, meaningful reporting.</p>
<p><strong>Should data be denormalized?</strong></p>
<p>If you are constantly joining two or more tables to generate reports, denormalization might be in order. An example might be one in which you join an <strong>orders</strong> table to a <strong>customer</strong> table just to get the customer&#8217;s name or zip code. Denormalizing this data would allow you to store the name or zip code within the <strong>orders</strong> table in your reporting database so that the join can be eliminated. While the benefit may appear negligible, this is only a single example and, in the case of millions of orders, may in itself be significant. While you may not want to store denormalized or redundant data within your production database, these should be considered just fine in a reporting database.</p>
<p><strong>Should you pre-calculate?</strong></p>
<p>Like denormalization, storing calculated values is traditionally frowned upon&#8230; for <em>production</em> databases. While you wouldn&#8217;t typically store simple, quick calculated fields in a reporting database, tables that could be generated via ETL or stored procedures that allow particular reports to retrieve their results quickly can benefit greatly from pre-calculation. A pivot query result, for example, could be loaded into a table and referenced directly into a report without the need for complicated report logic or long rendering time.</p>
<p><strong>Will data be identifiable?</strong></p>
<p>Production databases, particularly packaged applications or legacy home-grown applications, often contain unrecognizable data. A database field used for one purpose in a past version is now used for a different purpose. You&#8217;re looking for field called &#8220;lastName&#8221; and find the data in a field called &#8220;userSur.&#8221; Guess what? Your ETL process can <em>rename</em> the field to something more logical in your reporting database. Your reporting database can be structured so that it can be understood by real people and not just by application procedures. Ad hoc reporting has never been easier.</p>
<p><strong>What are your indexing needs?</strong></p>
<p>Reports have different indexing requirements than production applications. Your application requires indexing such that transactional data &#8211; usually single records &#8211; can be retrieved quickly while reports tend to need to aggregate data together. The queries that service the production application and the reports are seldom even similar. In our earlier example, the production help desk application needed to be able to identify open tickets assigned to particular technicians. The report, on the other hand, needed to identify tickets closed within a particular date range. The index on the <strong>status</strong> and <strong>technician</strong> fields turns out to have no use to the report query while an index added to the <strong>status</strong> and <strong>closeDate</strong> fields might be extremely useful and improve report performance.</p>
<p>Explore the queries that drive your reports and determine where real indexing benefit will be. Don&#8217;t be tempted to simply mirror your production indexes into your report environment.</p>
<p><strong>Will data be sourced from multiple systems?</strong></p>
<p>If so, then you may need to derive a naming convention for the tables within your reporting database. A prefix or suffix added to the table name is a good place to start. This reduces risk of table name collisions, and it facilitates fast identification of the source data. You&#8217;ll know just by looking what production application provided the data for a particular table.</p>
<p><strong>How frequently does data need to be updated?</strong></p>
<p>Most report databases do not need data to be as &#8220;fresh&#8221; as production data. Data that is minutes, hours, and sometimes even days old is sufficient enough to derive meaningful reports. Some data simply doesn&#8217;t change very often. Use multiple ETL scenarios if tables and applications have different needs. It might be of great interest for an <strong>orders</strong> table to be kept fresh for counting purposes but our <strong>employees</strong> table doesn&#8217;t really change very often. We might refresh <strong>orders</strong> every 30 minutes while we only refresh <strong>employees</strong> daily.</p>
<p>Note that you may need to derive a &#8220;delta&#8221; update mechanism for data that refreshes rapidly. If a table needs to be refreshed quickly and frequently, you must be able to identify and query only the recently updated records from your production system. Otherwise, querying the entire production table every time that the refresh scenario executes could have a negative impact on the performance of the production database. There are many methods to doing this kind of action. One common approach is to examine a modification timestamp field in the production source data. Only query records where that value is greater than the last refresh time.</p>
<p>For some data, it may simply be easier and almost as fast to simply snapshot the production table. Truncate the reporting database table and reload it from scratch from production. This method is not recommended for rapid refresh data and should not be used during peak usage of the production application, however. An overnight snapshot of associate records from the payroll system or other relatively static data can benefit from this mechanism.</p>
<h2>Conclusion</h2>
<p>This article was written to advocate for and demonstrate the use of a reporting database. While we only scratch the surface in this article, the concepts presented here should show you some of the greater benefits and thoughts that need to be considered prior to implementation. Your environment is unique to your organization, as are your reporting needs. There is no &#8220;one-size-fits-all&#8221; reporting solution, and a dedicated report environment allows you to tailor your application data to best fit your organization. I encourage you to consider exploring a dedicated reporting environment simply for the fact that it&#8217;s <em>safer</em> and more robust than reporting directly from production data, and it allows greater flexibility and creativity for report designers as well. Plus, it&#8217;s simply more &#8220;fun&#8221; when you can play with and manipulate the data without the risk of impacting a production application.</p>
<p>In future posts, we will explore various reporting environment solutions and examples that will hopefully open entirely new doors to your organization in terms of valuable data analysis opportunities.</p>
<p>Happy reporting!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tactek.com/2011/02/designing-a-reporting-database-environment/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/ReportDB1-150x150.jpg" />
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/ReportDB1.jpg" medium="image">
			<media:title type="html">Report Database Architecture</media:title>
			<media:description type="html">Report Database Architecture</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/ReportDB1-150x150.jpg" />
		</media:content>
	</item>
		<item>
		<title>Improved fnSplit Function for SQL Server</title>
		<link>http://www.tactek.com/2011/02/improved-fnsplit-function-for-sql-server/</link>
		<comments>http://www.tactek.com/2011/02/improved-fnsplit-function-for-sql-server/#comments</comments>
		<pubDate>Tue, 22 Feb 2011 04:40:42 +0000</pubDate>
		<dc:creator>Chris Bianchi</dc:creator>
				<category><![CDATA[Microsoft SQL Server]]></category>
		<category><![CDATA[Arrays]]></category>
		<category><![CDATA[CROSS APPLY]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[fnSplit]]></category>
		<category><![CDATA[Functions]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.tactek.com/?p=178</guid>
		<description><![CDATA[Yesterday, I posted a relatively well-known table-value function called fnSplit() for Microsoft SQL Server that splits delimited data from a<a href="http://www.tactek.com/2011/02/improved-fnsplit-function-for-sql-server/" class="searchmore">Read the Rest...</a><div class="clr"></div>]]></description>
			<content:encoded><![CDATA[<p>Yesterday, I posted a relatively <a href="http://www.tactek.com/2011/02/query-hp-service-manager-arrays-in-sql-server/" target="_self">well-known table-value function</a> called <strong>fnSplit()</strong> for Microsoft SQL Server that splits delimited data from a single field into multiple data rows. Today, we will improve on that function by including an index number column and retaining null entries within the array.<span id="more-178"></span></p>
<h2>Our Example</h2>
<p>First, let&#8217;s take a look at the data that we&#8217;re going to split. Our <strong>CUSTOMERS </strong>table contains two arrays &#8211; <strong>FIRST_NAMES</strong> and <strong>LAST_NAMES</strong> &#8211; that are &#8220;position specific.&#8221; Basically, the first FIRST_NAME value needs to be matched to the first LAST_NAME value and so forth.</p>
<table style="height: 66px;" width="438">
<thead>
<tr>
<th>ID</th>
<th>FIRST_NAMES</th>
<th>LAST_NAMES</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Bill,David,James</td>
<td>Albertson,Jones,Smythe</td>
</tr>
<tr>
<td>2</td>
<td>Cyndi,Sarah,Vanessa,Jessica</td>
<td>Blanchard,Howards,,Williamson</td>
</tr>
</tbody>
</table>
<p>Looking at the table, we see that Vanessa&#8217;s last name is missing. We will need to be able to manage &#8220;missing&#8221; values as indexes. Neither index-positioning nor missing values can be appropriately handled with the function that we explored yesterday, so we&#8217;ll make some modifications.</p>
<h2>The Original fnSplit() Function</h2>
<p>Let&#8217;s look at the original <strong>fnSplit()</strong> function.</p>

<div class="wp_syntax"><div class="code"><pre class="t-sql" style="font-family:monospace;">CREATE FUNCTION [dbo].[fnSplit](
    @sInputList VARCHAR(MAX) -- List of delimited items
  , @sDelimiter VARCHAR(MAX) = ',' -- delimiter that separates items
) RETURNS @List TABLE (item VARCHAR(MAX))
&nbsp;
BEGIN
	DECLARE @sItem VARCHAR(MAX)
	WHILE CHARINDEX(@sDelimiter,@sInputList,0) &amp;lt;&amp;gt; 0
	BEGIN
		SELECT
		@sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,
			CHARINDEX(@sDelimiter,@sInputList,0)-1))),
		@sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,
			CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),
			LEN(@sInputList))))
&nbsp;
		IF LEN(@sItem) &amp;gt; 0
		INSERT INTO @List SELECT @sItem
	END
&nbsp;
	IF LEN(@sInputList) &amp;gt; 0
	INSERT INTO @List SELECT @sInputList -- Put the last item in
	RETURN
END</pre></div></div>

<p>We can then CROSS APPLY our fnSplit() function within a SELECT query of our CUSTOMERS table, but we can only reference one field at a time this way.</p>

<div class="wp_syntax"><div class="code"><pre class="t-sql" style="font-family:monospace;">SELECT C.ID, F.ITEM
FROM CUSTOMERS C
CROSS APPLY dbo.fnSplit(FIRST_NAMES, ',') F</pre></div></div>

<p>Our result looks like the following:</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>ITEM</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Bill</td>
</tr>
<tr>
<td>1</td>
<td>David</td>
</tr>
<tr>
<td>1</td>
<td>James</td>
</tr>
<tr>
<td>2</td>
<td>Cyndi</td>
</tr>
<tr>
<td>2</td>
<td>Sarah</td>
</tr>
<tr>
<td>2</td>
<td>Vanessa</td>
</tr>
<tr>
<td>2</td>
<td>Jessica</td>
</tr>
</tbody>
</table>
<p>If we run the same query and substitute the LAST_NAMES fields, the problem becomes apparent.</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>ITEM</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Albertson</td>
</tr>
<tr>
<td>1</td>
<td>Jones</td>
</tr>
<tr>
<td>1</td>
<td>Smythe</td>
</tr>
<tr>
<td>2</td>
<td>Blanchard</td>
</tr>
<tr>
<td>2</td>
<td>Howards</td>
</tr>
<tr>
<td>2</td>
<td>Williamson</td>
</tr>
</tbody>
</table>
<p>Whereas seven rows were returned in the FIRST_NAMES query, only six are returned in the LAST_NAMES query. We can surmise that the &#8220;missing&#8221; name is from the second row since only three rows were returned from that row. But which first name is missing a last name? With our existing function, there is no systematic way to tell, and there is no way to join the two queries reliably.</p>
<h2>The Enhanced fnSplit() Function</h2>
<p>To fix this problem, we need only make some revision to our fnSplit() function. We need to ensure that null entries are retained, and we need a position index number that we can use in joins.</p>

<div class="wp_syntax"><div class="code"><pre class="t-sql" style="font-family:monospace;">ALTER FUNCTION [dbo].[fnSplit](
    @sInputList NVARCHAR(MAX) -- List of delimited items
  , @sDelimiter NVARCHAR(MAX) = ',' -- delimiter that separates items
) RETURNS @List TABLE (ARRAY_IDX INT, ITEM NVARCHAR(MAX))
&nbsp;
BEGIN
	DECLARE @sItem NVARCHAR(MAX)
	DECLARE @sIndex INT
	SET @sIndex = 1
	IF CHARINDEX(@sDelimiter,@sInputList,0) &amp;gt; 0
	BEGIN
		WHILE CHARINDEX(@sDelimiter,@sInputList,0) &amp;gt; 0
		BEGIN
			SELECT
			@sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,
				CHARINDEX(@sDelimiter,@sInputList,0)-1))),
			@sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,
				CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),
				LEN(@sInputList))))
&nbsp;
			IF LEN(@sItem) &amp;gt; 0
				INSERT INTO @List SELECT @sIndex, @sItem
			ELSE
				INSERT INTO @List SELECT @sIndex, NULL
&nbsp;
			SET @sIndex = @sIndex + 1
		END
&nbsp;
		IF LEN(@sInputList) &amp;gt; 0
			INSERT INTO @List SELECT @sIndex, @sInputList
	END
	ELSE
		INSERT INTO @List SELECT 1, NULL
&nbsp;
	RETURN
END</pre></div></div>

<p>Here, we have made three changes. First, we modified the IF condition that checks for string length and added an ELSE clause to inject a NULL value if the string length is equal to zero. Second, we added an integer counter variable called @sIndex that increases with each iteration of the WHILE loop block. This index will be returned as a column called <strong>ARRAY_IDX</strong>. Finally, if there are no valid entries at all, we create a NULL table with a single row. This ensures that we will always get an index of at least 1, even if the value is NULL.</p>
<p>Now, we execute the following query:</p>

<div class="wp_syntax"><div class="code"><pre class="t-sql" style="font-family:monospace;">SELECT C.ID, F.ARRAY_IDX, F.ITEM
FROM CUSTOMERS C
CROSS APPLY dbo.fnSplit(FIRST_NAMES, ',') F</pre></div></div>

<p>And our result should look like this:</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>ARRAY_IDX</th>
<th>ITEM</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
<td>Bill</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>David</td>
</tr>
<tr>
<td>1</td>
<td>3</td>
<td>James</td>
</tr>
<tr>
<td>2</td>
<td>1</td>
<td>Cyndi</td>
</tr>
<tr>
<td>2</td>
<td>2</td>
<td>Sarah</td>
</tr>
<tr>
<td>2</td>
<td>3</td>
<td>Vanessa</td>
</tr>
<tr>
<td>2</td>
<td>4</td>
<td>Jessica</td>
</tr>
</tbody>
</table>
<p>And, when we substitute the LAST_NAMES field, the result appears like this:</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>ARRAY_IDX</th>
<th>ITEM</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
<td>Albertson</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>Jones</td>
</tr>
<tr>
<td>1</td>
<td>3</td>
<td>Smythe</td>
</tr>
<tr>
<td>2</td>
<td>1</td>
<td>Blanchard</td>
</tr>
<tr>
<td>2</td>
<td>2</td>
<td>Howards</td>
</tr>
<tr>
<td>2</td>
<td>3</td>
<td>NULL</td>
</tr>
<tr>
<td>2</td>
<td>4</td>
<td>Williamson</td>
</tr>
</tbody>
</table>
<p>We now have a retained NULL value in the third position of the second array. We also have an array index field (position identifier) that we can use to build a join.</p>

<div class="wp_syntax"><div class="code"><pre class="t-sql" style="font-family:monospace;">SELECT C.ID, F.ITEM AS FIRST_NAME, L.ITEM AS LAST_NAME
FROM CUSTOMERS C
CROSS APPLY dbo.fnSplit(C.FIRST_NAMES, ',') F
CROSS APPLY dbo.fnSplit(C.LAST_NAMES, ',') L
WHERE F.ARRAY_IDX = L.ARRAY_IDX</pre></div></div>

<p>And achieve the following result:</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>FIRST_NAME</th>
<th>LAST_NAME</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Bill</td>
<td>Albertson</td>
</tr>
<tr>
<td>1</td>
<td>David</td>
<td>Jones</td>
</tr>
<tr>
<td>1</td>
<td>James</td>
<td>Smythe</td>
</tr>
<tr>
<td>2</td>
<td>Cyndi</td>
<td>Blanchard</td>
</tr>
<tr>
<td>2</td>
<td>Sarah</td>
<td>Howards</td>
</tr>
<tr>
<td>2</td>
<td>Vanessa</td>
<td>NULL</td>
</tr>
<tr>
<td>2</td>
<td>Jessica</td>
<td>Williamson</td>
</tr>
</tbody>
</table>
<p>It is now apparent that someone (or some process) neglected to record Vanessa&#8217;s last name. Additionally, we have joined two array fields based on their index positions.</p>
<h2>Some Thoughts and Challenges</h2>
<p>This technique works well if both arrays are ensured to contain the same number of elements. If you are faced with joining arrays that contain different numbers of elements but still wish to retain correlation between indexes, you could contain each CROSS APPLY clause into a sub-SELECT and use a LEFT OUTER JOIN to accomplish this. It may also be beneficial to place common CROSS APPLY queries into a VIEW so you aren&#8217;t burdened with remembering the syntax and wish to avoid a potential for multiple, nested sub-SELECT statements.</p>
<h2>Conclusion</h2>
<p>In adding position indexing to the fnSplit() function, you have a powerful function that can be used to manage all sorts of delimited data types. I have replaced fnSplit() on virtually every SQL Server database that I manage primarily for the added functionality. The additional field can always be left out of the SELECT statement when it&#8217;s not needed. I hope that you will experience similar benefits to this function as I have.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tactek.com/2011/02/improved-fnsplit-function-for-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
	</item>
		<item>
		<title>Improve HP Service Manager Performance with Array Tables</title>
		<link>http://www.tactek.com/2011/02/improve-hp-service-manager-performance-with-array-tables/</link>
		<comments>http://www.tactek.com/2011/02/improve-hp-service-manager-performance-with-array-tables/#comments</comments>
		<pubDate>Mon, 21 Feb 2011 05:17:10 +0000</pubDate>
		<dc:creator>Chris Bianchi</dc:creator>
				<category><![CDATA[HP Service Manager]]></category>
		<category><![CDATA[Arrays]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.tactek.com/?p=170</guid>
		<description><![CDATA[One of the biggest issues with HP Service Manager is the format and storage of arrays as large data types<a href="http://www.tactek.com/2011/02/improve-hp-service-manager-performance-with-array-tables/" class="searchmore">Read the Rest...</a><div class="clr"></div>]]></description>
			<content:encoded><![CDATA[<p>One of the biggest issues with HP Service Manager is the format and storage of arrays as large data types such as CLOB (Oracle) or TEXT (SQL Server) fields. These data types are not indexed and are slow to query. If you want, for example, to locate all records where Frank Jones is a pending change approver, the application needs to examine every pending change request, parse apart the <em>current.pending.groups</em> field, and search for Frank Jones. It might not take a long time to do it once or twice, but your system may contain thousands or more of such requests per day. Configuration Item relationships and the default Approval Inbox data are stored this way.  [<strong>Note: </strong>These last two are resolved in a fresh installation of HP Service Manager 9.20.]</p>
<p>Fortunately for us, this data can easily be relocated out of large data fields and moved into a real, relational table in a form that can be indexed for rapid query. This article explains how.</p>
<p><span id="more-170"></span>Fixing this issue is relatively easy but does make changes to the underlying database. This is something important to take into consideration when planning upgrades. While converting your data as this article describes does create some upgrade conflict, the differences are not difficult to work through.</p>
<h2>Updating the Database Dictionary Record</h2>
<p>First, make a backup of your existing database tables as well as the database dictionary (dbdict) records that you are planning to change. Preferably, backup the entire database just in case something goes wrong. Of course, we’re not planning that it will, but it’s better to be safe than sorry!</p>
<p>For our conversion, we’ll be updating the “approvers” field of the “ocmgroups” file.</p>
<p>1.       Open the “ocmgroups” dbdict record via the Tailoring-&gt;Database Dictionary menu option.</p>
<p>2.       Select the “SQL Tables” tab.</p>
<p>3.       Look for an alias that begins with the letter “a” (e.g. a1). There may be zero or more of these listed. We want to know the “next available” alias number. If “a1” exists, then the next available is “a2” and so forth. On a fresh installation of HPSM 9.20, “a2” is the next available alias for the “ocmgroups” file.</p>
<p>4.       Select the “Fields” tab.</p>
<p>5.       Locate the field that we want to change. For our example, this is the “approvers” field.</p>
<p>6.       Array fields get two line entries in the dbdict record – one for the array and one for the actual database field. Open the first of the two (the array).</p>
<p>7.       In the “SQL Table” field, enter the next available alias from Step #3. We will enter “a2” (minus the quotes).</p>
<p>8.       Select “OK” and open the second array line (the database field).</p>
<p>9.       Change the “SQL Type” to the appropriate type for your RDBMS. I’m using Microsoft SQL Server, and this field stores operator names. A look at the operator table shows me that the names are stored as VARCHAR(60) in the database. I change “TEXT” to “VARCHAR(60).”</p>
<p>10.   Change the “SQL Table” field to the same alias as the array. We enter “a2” into this field as well.</p>
<p>11.   Click “OK” and allow HP Service Manager to update the database tables.</p>
<h2>Conclusion</h2>
<p>That’s all there is to it. You now have a new table in your database called OCMGROUPSA2 that stores the array values as VARCHAR(60) fields instead of in a TEXT field. These can be indexed by the RDBMS. You can add keys to improve query performance, and simply making this change will improve the performance of queries that use the field whether or not indexing is used. HPSM does not have to store large fields in memory and parse them apart to find values.</p>
<p>I believe that this technique works in all versions of HPSM that use an RDBMS. I’ve had success implementing such relationships on 6.14, 6.2, 7.01, 7.11, and 9.20.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tactek.com/2011/02/improve-hp-service-manager-performance-with-array-tables/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
	</item>
		<item>
		<title>Query HP Service Manager Arrays in SQL Server</title>
		<link>http://www.tactek.com/2011/02/query-hp-service-manager-arrays-in-sql-server/</link>
		<comments>http://www.tactek.com/2011/02/query-hp-service-manager-arrays-in-sql-server/#comments</comments>
		<pubDate>Sun, 20 Feb 2011 15:35:49 +0000</pubDate>
		<dc:creator>Chris Bianchi</dc:creator>
				<category><![CDATA[HP Service Manager]]></category>
		<category><![CDATA[Microsoft SQL Server]]></category>
		<category><![CDATA[Arrays]]></category>
		<category><![CDATA[CROSS APPLY]]></category>
		<category><![CDATA[fnSplit]]></category>
		<category><![CDATA[Functions]]></category>
		<category><![CDATA[Request Management]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.tactek.com/?p=154</guid>
		<description><![CDATA[While the HP Service Manager client is a great tool, sometimes you still need to run a direct SQL query<a href="http://www.tactek.com/2011/02/query-hp-service-manager-arrays-in-sql-server/" class="searchmore">Read the Rest...</a><div class="clr"></div>]]></description>
			<content:encoded><![CDATA[<p>While the HP Service Manager client is a great tool, sometimes you still need to run a direct SQL query on the data. You may want the data to appear on some external report or you just need some “quick and dirty” numbers to send on to management. If you manage HPSM environments long enough, you will invariably find yourself connecting to the database to run queries from time to time. And that’s when you’ll discover that HPSM has been storing the data you need in a difficult-to-query array.</p>
<p>Although the example in this article applies to HP Service Manager, the method can be used whenever delimited data needs to be split and joined to another table in Microsoft SQL Server.</p>
<p><strong><span id="more-154"></span></strong>In HP Service Manager, lists of data associated to a particular record are often stored in a proprietary data type called an “array” rather than a relational, foreign-key table. If you’re using Microsoft SQL Server as your backend database, you will find array data stored in TEXT or NTEXT type fields as a list (Oracle databases use CLOB types). It would be much more beneficial if this data could be represented as relational data so that it could be reported on or joined to another table for more information.</p>
<h2>Our Example</h2>
<p>Bill, our CFO, would like to send an e-mail to everyone listed as a Request Management approver in HP Service Manager reminding them of a budget freeze. He asks us for a list of approvers and their e-mail addresses so that he can target the e-mail rather than send a company-wide communication.</p>
<p><strong>Special Note: </strong>Our example uses an out-of-box installation of HP Service Manager 9.20 and sample data.</p>
<h2>The Data</h2>
<p>Request Management groups (both members and approvers) are located in the <strong>ocmgroups</strong> file in HP Service Manager. A quick look at a Request Management group record in HPSM shows us members and approvers as lists. Approvers are displayed as operator names. Additionally, we need e-mail addresses. Both contact names that Bill would recognize and e-mail addresses can be found in the <strong>operator</strong> file.</p>
<div id="attachment_159" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/HPSM-Request-Mgmt-Group.jpg" rel="lightbox[154]"><img class="size-medium wp-image-159" title="HPSM Request Mgmt Group" src="http://www.tactek.com/wp-content/uploads/2011/02/HPSM-Request-Mgmt-Group-300x165.jpg" alt="HPSM Request Mgmt Group" width="300" height="165" /></a><p class="wp-caption-text">HPSM Request Mgmt Group</p></div>
<p>A glance at the <strong>dbdict</strong> record for the <strong>ocmgroups</strong> and <strong>operator</strong> files shows us that the fields we want are stored in the <strong>OCMGROUPSM1 </strong>and <strong>OPERATORM1</strong> tables within SQL Server.</p>
<p>We should be able to simply query the <strong>OCMGROUPSM1</strong>, join to <strong>OPERATORM1</strong> and get the names and e-mail addresses, right? Unfortunately, it’s not quite that easy.</p>
<h2>The Problem</h2>
<p>The OCMGROUPSM1 table contains a TEXT type field called APPROVERS that can’t be directly joined to the OPERATORM1 table. The entire list of approvers is stored in a single field with a non-printable character delimiter. The character (both SQL Server and Oracle) is a new-line character (ASCII decimal value of 10). A simple join query will not work for our situation.</p>
<div id="attachment_161" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/OCMGROUPSM1.jpg" rel="lightbox[154]"><img class="size-medium wp-image-161" title="OCMGROUPSM1" src="http://www.tactek.com/wp-content/uploads/2011/02/OCMGROUPSM1-300x239.jpg" alt="OCMGROUPSM1" width="300" height="239" /></a><p class="wp-caption-text">OCMGROUPSM1</p></div>
<p>We need to be able to represent the array data in a way that can be joined to another table.</p>
<h2>SQL Server Array Splitting Function &#8211; fnSplit</h2>
<p>For the first part of our solution, we will build a function that splits array data into something more understandable. We will actually go one step further and build a function that can split data on any delimiter, not just the new-line character.</p>
<p>In tackling this for the first time, I started with a simple SQL Server function that I found via an Internet search. The source code is as shown below:</p>
<pre>CREATE FUNCTION [dbo].[fnSplit](
    @sInputList VARCHAR(MAX) -- List of delimited items
  , @sDelimiter VARCHAR(MAX) = ',' -- delimiter that separates items
) RETURNS @List TABLE (item VARCHAR(MAX))

BEGIN
	DECLARE @sItem VARCHAR(MAX)
	WHILE CHARINDEX(@sDelimiter,@sInputList,0) &lt;&gt; 0
	BEGIN
		SELECT
		@sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,
			CHARINDEX(@sDelimiter,@sInputList,0)-1))),
		@sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,
			CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),
			LEN(@sInputList))))

		IF LEN(@sItem) &gt; 0
		INSERT INTO @List SELECT @sItem
	END

	IF LEN(@sInputList) &gt; 0
	INSERT INTO @List SELECT @sInputList -- Put the last item in
	RETURN
END</pre>
<p>To see how this function works, create it and execute the following query:</p>
<p><code>SELECT * FROM dbo.fnSplit('Bill,Janet,Sarah,Tiffany,Vanessa,William,Xander', ',')</code></p>
<p>The data is split by comma-separated values and returned as a list.</p>
<p>In our example, the character delimiter is a non-printable new-line character. We can use SQL Server’s CHAR() function to manage this. CHAR() accepts a decimal value and returns the corresponding ASCII character. The new-line character has a decimal value of 10 and can be represented in a SQL Server query as CHAR(10). You will see how this is used in the next section.</p>
<h2>Using fnSplit in a SQL Server Query using CROSS APPLY</h2>
<p>Our goal is to get the data into a relational format that we can join to another table. We can use SQL Server’s CROSS APPLY syntax to accomplish this. CROSS APPLY allows us to join a table to a table-value function (TVF) result set within SQL Server.</p>
<p><code>SELECT M1.NAME, S.ITEM<br />
FROM OCMGROUPSM1 M1<br />
CROSS APPLY fnSplit(M1.APPROVERS, CHAR(10)) S</code></p>
<p>Our result should now be something that we can much more easily join to another table as shown in the screen shot.</p>
<div id="attachment_160" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/SELECT-CROSS-APPLY.jpg" rel="lightbox[154]"><img class="size-medium wp-image-160" title="SELECT CROSS APPLY" src="http://www.tactek.com/wp-content/uploads/2011/02/SELECT-CROSS-APPLY-300x191.jpg" alt="SELECT CROSS APPLY" width="300" height="191" /></a><p class="wp-caption-text">SELECT CROSS APPLY</p></div>
<p>We need only join this result to the OPERATORM1 table to get our extra information – the CONTACT_NAME and EMAIL fields.</p>
<p><code>SELECT M1.NAME, S.ITEM, O.CONTACT_NAME, O.EMAIL<br />
FROM OCMGROUPSM1 M1<br />
CROSS APPLY fnSplit(M1.APPROVERS, CHAR(10)) S<br />
JOIN OPERATORM1 O ON O.NAME = S.ITEM</code></p>
<h2>Cleaning up the Result</h2>
<p>Just for polish, we can clean this data up to provide our CFO, Bill, with the result of his specific request. We currently show duplicate names and e-mail addresses when the same person might approve on behalf of multiple Request Management groups.</p>
<p>We’ll just limit the result set to the columns we need, use a SELECT DISTINCT and an ORDER BY clause to get Bill the answer in a format that he wants.</p>
<p><code>SELECT DISTINCT O.CONTACT_NAME, O.EMAIL<br />
FROM OCMGROUPSM1 M1<br />
CROSS APPLY fnSplit(M1.APPROVERS, CHAR(10)) S<br />
JOIN OPERATORM1 O ON O.NAME = S.ITEM<br />
ORDER BY CONTACT_NAME</code></p>
<h2>Conclusion</h2>
<p>Array data can be difficult to work with especially when attempting to access it through database queries. Breaking components out of the model file, generating pending approver lists from the Approval file, and many other challenges can be solved by adopting the technique laid out in this article. The best part is that the fnSplit function is added to your SQL Server database and used whenever you need it.</p>
<p>While the example that was used in this article is specific to the HP Service Manager application, I have encountered numerous other databases where data is stored as delimited lists rather than as relational data. The method of using the fnSplit function and CROSS APPLY is universal.</p>
<p>In a future post, we will modify the fnSplit function to include NULL values (an empty value between delimiters) as well as an index column identifying the position of the item in the list.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tactek.com/2011/02/query-hp-service-manager-arrays-in-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/HPSM-Request-Mgmt-Group-150x150.jpg" />
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/HPSM-Request-Mgmt-Group.jpg" medium="image">
			<media:title type="html">HPSM Request Mgmt Group</media:title>
			<media:description type="html">HPSM Request Mgmt Group</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/HPSM-Request-Mgmt-Group-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/OCMGROUPSM1.jpg" medium="image">
			<media:title type="html">OCMGROUPSM1</media:title>
			<media:description type="html">OCMGROUPSM1</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/OCMGROUPSM1-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/SELECT-CROSS-APPLY.jpg" medium="image">
			<media:title type="html">SELECT CROSS APPLY</media:title>
			<media:description type="html">SELECT CROSS APPLY</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/SELECT-CROSS-APPLY-150x150.jpg" />
		</media:content>
	</item>
		<item>
		<title>Local HP Service Manager 9.20 on Windows 7</title>
		<link>http://www.tactek.com/2011/02/local-hp-service-manager-9-20-on-windows-7/</link>
		<comments>http://www.tactek.com/2011/02/local-hp-service-manager-9-20-on-windows-7/#comments</comments>
		<pubDate>Sun, 13 Feb 2011 23:11:50 +0000</pubDate>
		<dc:creator>Chris Bianchi</dc:creator>
				<category><![CDATA[HP Service Manager]]></category>
		<category><![CDATA[Microsoft SQL Server]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[Windows 7]]></category>

		<guid isPermaLink="false">http://www.tactek.com/?p=56</guid>
		<description><![CDATA[Any HP Service Manager developer will undoubtedly see the value in a local installation of the software. However, even with<a href="http://www.tactek.com/2011/02/local-hp-service-manager-9-20-on-windows-7/" class="searchmore">Read the Rest...</a><div class="clr"></div>]]></description>
			<content:encoded><![CDATA[<p>Any HP Service Manager developer will undoubtedly see the value in a local installation of the software. However, even with the release of HPSM 9.20, Windows 7 continues to present challenges. The Windows 7 Aero theme creates visual issues with the installer, the supplied Java 1.5 lags behind most local java installations, and known issues with SQL Server 2005 Express edition are all good reasons to avoid tackling a local instance altogether. This guide will walk you through setting up your local installation complete with database, application, and Windows client.<span id="more-56"></span></p>
<h2>Pre-Installation Requirements</h2>
<p>Before setting up your local HPSM installation, you will need to download some software packages.</p>
<ul>
<li><a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=7522a683-4cb2-454e-b908-e805e9bd4e28" target="_blank">Microsoft SQL Server 2008 Express with Tools</a> &#8211; The SQL Server 2005 edition bundled with the HP E-Media is not fully compatible with Windows 7 and may not even install properly. Microsoft offers SQL Server Express both with and without the client tools. You will need the edition with the client tools in order to configure your database. Select either the 32-bit or 64-bit edition as required by your operating system.</li>
<li><a href="http://support.openview.hp.com/downloads.jsp" target="_blank">HP Service Manager 9.20 English SW E-Media</a> &#8211; The core application is available from HP&#8217;s Software Support Website. You will need your Support Authorization ID (SAID) number from your HP order.</li>
</ul>
<h2>Installing and Configuring the Database</h2>
<p>The database should be installed before the other components. The HPSM configuration process will require an configured, empty database to be available. This section assumes that you do <em>not</em> currently have a SQL Server instance installed on your local system.</p>
<p>1. Launch the <em>Microsoft SQL Server 2008 Express with Tools</em> installer. You may be prompted with a compatibility warning which is safe to ignore at this time. We will reconcile that later.</p>
<p>&nbsp;</p>
<div id="attachment_65" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerInstallationCenter.jpg" rel="lightbox[56]"><img class="size-medium wp-image-65" title="SQL Server Installation Center" src="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerInstallationCenter-300x225.jpg" alt="SQL Server Installation Center" width="300" height="225" /></a><p class="wp-caption-text">SQL Server Installation Center</p></div>
<p>2. From the <em>SQL Server Installation Center</em>, select the <strong>Installation</strong> menu.</p>
<p>3. Select the <strong>New SQL Server stand-alone installation</strong>&#8230; option.</p>
<p>4. On the <em>Feature Selection</em> screen, click the <strong>Select All</strong> button.</p>
<p>&nbsp;</p>
<div id="attachment_67" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerFeatureSelection.jpg" rel="lightbox[56]"><img class="size-medium wp-image-67" title="SQL Server Feature Selection" src="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerFeatureSelection-300x225.jpg" alt="SQL Server Feature Selection" width="300" height="225" /></a><p class="wp-caption-text">SQL Server Feature Selection</p></div>
<p>5. On the <em>Instance Configuration</em> screen, select <strong>Default Instance</strong>.</p>
<p>6. On the <em>Server Configuration</em> screen, click the button labeled <strong>Use the same account for all SQL Server services</strong>.</p>
<p>7. In the <em>Account Name</em> drop-down, select <strong>NT AUTHORITY\NETWORK SERVICE</strong>.</p>
<p>&nbsp;</p>
<div id="attachment_68" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerServerConfiguration.jpg" rel="lightbox[56]"><img class="size-medium wp-image-68" title="SQL Server Server Configuration" src="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerServerConfiguration-300x95.jpg" alt="SQL Server Server Configuration" width="300" height="95" /></a><p class="wp-caption-text">SQL Server Configuration</p></div>
<p>8. Leave the <em>Password</em> field blank and click <strong>OK.</strong></p>
<p>9. On the <em>Database Engine Configuration</em> screen, select <strong>Mixed Mode</strong> authentication and select a password for your system administrator (<strong>sa</strong>) user. Also, click the <strong>Add Current User</strong> button at the bottom to ensure that you will be able to configure the SQL Server via your Windows account later.</p>
<p>&nbsp;</p>
<div id="attachment_69" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerDatabaseEngine.jpg" rel="lightbox[56]"><img class="size-medium wp-image-69" title="SQL Server Database Engine" src="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerDatabaseEngine-300x225.jpg" alt="SQL Server Database Engine" width="300" height="225" /></a><p class="wp-caption-text">SQL Server Database Engine</p></div>
<p>10. Complete the installation wizard.</p>
<p>11. Once the installation wizard completes, run your <em>Windows Update</em> service to download the latest SQL Server 2008 Service Pack. This fixes the compatibility warning you may have been presented with in Step #1.</p>
<p><span style="color: #ff0000;"><strong>Note</strong>: At the time of this writing, <a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=66ab3dbb-bf3e-4f46-9559-ccc6a4f9dc19&amp;displaylang=en" target="_blank">SQL Server 2008 Service Pack 1</a> is available directly from Microsoft&#8217;s website and can be installed alone without Windows Update.</span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">12. Launch the <strong>SQL Server Configuration Manager</strong> (Start-&gt;All Programs-&gt;Microsoft SQL Server 2008-&gt;Configuration Tools).</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">13. Under <em>SQL Server Network Configuration</em>, select <strong>Protocols for SQLEXPRESS</strong>.</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">14. Right-click the <em>TCP/IP</em> protocol option and select <strong>Enable</strong>.</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;"> </span></span></p>
<p>&nbsp;</p>
<div id="attachment_73" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerConfigManager.jpg" rel="lightbox[56]"><img class="size-medium wp-image-73" title="SQL Server Configuration Manager" src="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerConfigManager-300x145.jpg" alt="SQL Server Configuration Manager" width="300" height="145" /></a><p class="wp-caption-text">SQL Server Configuration Manager</p></div>
<p><span style="color: #000000;">15. Select <em>SQL Server Services</em>.</span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">16. Right-click the <em>SQL Server (SQLEXPRESS) </em>service and select <strong>Restart</strong>.</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">17. Launch the <strong>SQL Server Management Studio</strong> (Start-&gt;All Programs-&gt;Microsoft SQL Server 2008).</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;"> </span></span></p>
<p>&nbsp;</p>
<div id="attachment_75" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerMSConnect.jpg" rel="lightbox[56]"><img class="size-medium wp-image-75" title="SQL Server MS Connect" src="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerMSConnect-300x225.jpg" alt="SQL Server MS Connect" width="300" height="225" /></a><p class="wp-caption-text">SQL Server MS Connect</p></div>
<p><span style="color: #000000;">18. In the <em>Server Name</em> field, enter <strong>localhost\SQLEXPRESS</strong>.</span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">19. Select <strong>SQL Server Authentication</strong>.</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">20. In the <em>Login</em> field, enter <strong>sa</strong>, and enter the password specified in Step #9.</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">21. Once connected, right-click the <em>Databases</em> folder in the <em>Object Explorer<strong> </strong></em>and select <strong>New Database&#8230;</strong></span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;"><strong> </strong></span></span></p>
<p>&nbsp;</p>
<div id="attachment_76" class="wp-caption aligncenter" style="width: 310px"><strong><strong><a href="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerNewDatabase.jpg" rel="lightbox[56]"><img class="size-medium wp-image-76" title="SQL Server New Database" src="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerNewDatabase-300x269.jpg" alt="SQL Server New Database" width="300" height="269" /></a></strong></strong><p class="wp-caption-text">SQL Server New Database</p></div>
<p><strong> </strong><span style="color: #000000;">22. In the <em>Database Name</em> field, enter a name for the Service Manager 9.20 database (e.g. <strong>sm920</strong>).</span></p>
<h2><span style="color: #ff0000;"><span style="color: #000000;">Configuring ODBC Data Source</span></span></h2>
<p><span style="color: #ff0000;"><span style="color: #000000;">HP Service Manager connects to the database via an ODBC Data Source Name (DSN). Next, we will configure a DSN that will be used to connect your HPSM application to the database you just created.</span></span></p>
<p><span style="color: #ff0000;"><strong>Note:</strong> Instructions for this are different for 32-bit and 64-bit Windows. You will need a 32-bit DSN for HP Service Manager.</span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;"><strong>32-bit Windows</strong></span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">Launch the ODBC Manager by selecting Start-&gt;Control Panel. Then Administrative Tools-&gt;Data Sources (ODBC).</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;"><strong>64-bit Windows</strong></span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">Click the Start button and, in the <em>Search programs and files</em> box, enter </span></span><strong>c:\windows\sysWOW64\odbcad32.exe</strong>. You should see <strong>odbcad32</strong> in the program list. Click the icon.</p>
<p>From this point on, directions are the same.</p>
<p>23. Select the <em>System DSN</em> tab and click the <strong>Add&#8230;</strong> button.</p>
<p>&nbsp;</p>
<div id="attachment_78" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/ODBCCreate.jpg" rel="lightbox[56]"><img class="size-medium wp-image-78" title="ODBC Create" src="http://www.tactek.com/wp-content/uploads/2011/02/ODBCCreate-300x226.jpg" alt="Create ODBC Data Source" width="300" height="226" /></a><p class="wp-caption-text">Create ODBC Data Source</p></div>
<p>24. Select the <strong>SQL Server</strong> driver and click <strong>Finish</strong>.</p>
<p>25. Enter a name for the data source (e.g. <strong>sm920</strong>) and <strong>localhost\SQLEXPRESS</strong> as the <em>Server</em> and click <strong>Next</strong>.</p>
<p>26. Select the <em>With SQL Server authentication&#8230;</em> option. Enter <strong>sa</strong> as the <em>Login ID</em> and the password specified in Step #9 and click <strong>Next</strong>.</p>
<p>27. Check the <strong>Change the default database to</strong> check box and select the database you created in Step #22.</p>
<p>28. Click <strong>Next</strong> then <strong>Finish</strong>.</p>
<p>&nbsp;</p>
<div id="attachment_79" class="wp-caption aligncenter" style="width: 299px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/ODBCTest.jpg" rel="lightbox[56]"><img class="size-medium wp-image-79" title="ODBC Test" src="http://www.tactek.com/wp-content/uploads/2011/02/ODBCTest-289x300.jpg" alt="ODBC Test" width="289" height="300" /></a><p class="wp-caption-text">ODBC Test</p></div>
<p>29. Make sure that your DSN is going to work correctly by clicking the <strong>Test Data Source&#8230;</strong> button.</p>
<h2>Installing the HP Service Manager 9.20 Server</h2>
<p>Once the database and data sources are both set up properly and you&#8217;ve been able to establish an ODBC connection via the test, you are ready to install and configure the HP Service Manager server.</p>
<p>30. Open the HP Service Manager 9.20 English SW E-Media and browse to the <em>Server\Windows</em> folder.</p>
<p>31. Right-click the <em>setupserver</em> application and click <strong>Properties</strong>.</p>
<p>&nbsp;</p>
<div id="attachment_81" class="wp-caption aligncenter" style="width: 246px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/HPSMServerCompatibility.jpg" rel="lightbox[56]"><img class="size-medium wp-image-81" title="HPSM Server Compatibility" src="http://www.tactek.com/wp-content/uploads/2011/02/HPSMServerCompatibility-236x300.jpg" alt="HPSM Server Compatibility" width="236" height="300" /></a><p class="wp-caption-text">HPSM Server Compatibility</p></div>
<p>32. On the <em>Compatibility</em> tab, check the <strong>Run this program in compatibility mode for&#8230;</strong> check box and select <em>Windows Vista (Service Pack 2)</em>. Also, check the <strong>Run this program as an administrator</strong> check box.</p>
<p>33. Click <strong>Apply</strong> and <strong>OK</strong>.</p>
<p>34. Double-click the <em>setupserver</em> application to launch the HPSM server installation wizard.</p>
<p>&nbsp;</p>
<div id="attachment_82" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/HPSMServerInstall.jpg" rel="lightbox[56]"><img class="size-medium wp-image-82" title="HPSM Server Install" src="http://www.tactek.com/wp-content/uploads/2011/02/HPSMServerInstall-300x199.jpg" alt="HPSM Server Install" width="300" height="199" /></a><p class="wp-caption-text">HPSM Server Install</p></div>
<p>35. Select the default options through the wizard, and on the final screen, select the <strong>Run the configuration program after install</strong> check box and click the <strong>Finish</strong> button.</p>
<h2>Configure the HP Service Manager 9.20 Server</h2>
<p>The HP Service Manager Configuration appears, and we are ready to configure the server settings as well as install the core application structure and data into the database.</p>
<p>&nbsp;</p>
<div id="attachment_83" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/HPSMconfiguration.jpg" rel="lightbox[56]"><img class="size-medium wp-image-83" title="HPSM Configuration" src="http://www.tactek.com/wp-content/uploads/2011/02/HPSMconfiguration-300x220.jpg" alt="HPSM Configuration" width="300" height="220" /></a><p class="wp-caption-text">HPSM Configuration</p></div>
<p>36. Select the default HTTP Port (13080). You may select a different port if necessary for your installation (i.e. if you already have another service or application running on port 13080).</p>
<p>&nbsp;</p>
<div id="attachment_84" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tactek.com/wp-content/uploads/2011/02/HPSMConfigDB.jpg" rel="lightbox[56]"><img class="size-medium wp-image-84" title="HPSM Config DB" src="http://www.tactek.com/wp-content/uploads/2011/02/HPSMConfigDB-300x220.jpg" alt="HPSM Config DB" width="300" height="220" /></a><p class="wp-caption-text">HPSM Config DB</p></div>
<p>37. On the <em>Database Type and Connection Information</em> screen, enter the name of the DSN that you specified in Step #25. The <em>User</em> is <strong>sa</strong> and the <em>Password</em> is the password that you specified in Step #9.</p>
<p>38. On the next screen, click the <strong>Verify Connection</strong> button to ensure that the database link is working properly. If the connection cannot be made and you are sure that the service is running, ensure that you used the correct method (32-bit or 64-bit) for creating the ODBC DSN as specified previously.</p>
<p>39. The next screen is the <em>HP Service Manager Application and Demo data upload</em> screen. Click the <strong>Upload Data</strong> button to populate the database. This process may take several minutes to complete.</p>
<p>40. Complete the configuration wizard, and your HP Service Manager 9.20 server is ready to launch.</p>
<p>41. Start the <strong>HP Service Manager 9.20 Server</strong> service via the Windows Service console.</p>
<h2>Install the HP Service Manager 9.20 Windows Client</h2>
<p>Now that your HP Service Manager 9.20 Server is ready to use, you&#8217;ll need a client to connect to it.</p>
<p>42. Open the HP Service Manager 9.20 English SW E-Media and browse to the <em>Client</em> folder.</p>
<p>43. Right-click the <strong>setupclient</strong> application and select <strong>Properties</strong>.</p>
<p>44. On the <em>Compatibility</em> tab, select to run the program in compatibility mode for Windows Vista (Service Pack 2). Otherwise, visual problems with Windows 7 Aero and the installer will prevent controls like buttons and check boxes to display properly.</p>
<p>45. Launch the <strong>setupclient</strong> application and select the default values for the wizard.</p>
<p>46. Once the installation is complete, launch the HP Service Manager client.</p>
<p>47. In the <em>Connections </em>dialog, click the <strong>New launch configuration</strong> button.</p>
<p>48. Enter the information to connect to your local installation. The <em>Server host name</em> is <strong>localhost</strong>, and the port is <strong>13080</strong> (unless you specified a different value in Step #36). Initially, use the user name <strong>falcon</strong> with a blank password to make your initial connection.</p>
<p>49. Click <strong>Connect</strong>.</p>
<h2>Conclusion</h2>
<p>You now have a functional, local installation of HP Service Manager 9.20 server and client on Windows 7. These instructions should work for both 32-bit and 64-bit editions of Windows. I ran through this tutorial on Windows 7 Professional, but the instructions should be the same for other Windows 7 editions as well.</p>
<p>In a future post, I will discuss setting up the web tier on Apache Tomcat locally as well so that complete development can be managed on the local PC.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tactek.com/2011/02/local-hp-service-manager-9-20-on-windows-7/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerInstallationCenter-150x150.jpg" />
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerInstallationCenter.jpg" medium="image">
			<media:title type="html">SQL Server Installation Center</media:title>
			<media:description type="html">SQL Server Installation Center</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerInstallationCenter-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerFeatureSelection.jpg" medium="image">
			<media:title type="html">SQL Server Feature Selection</media:title>
			<media:description type="html">SQL Server Feature Selection</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerFeatureSelection-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerServerConfiguration.jpg" medium="image">
			<media:title type="html">SQL Server Server Configuration</media:title>
			<media:description type="html">SQL Server Configuration</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerServerConfiguration-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerDatabaseEngine.jpg" medium="image">
			<media:title type="html">SQL Server Database Engine</media:title>
			<media:description type="html">SQL Server Database Engine</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerDatabaseEngine-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerConfigManager.jpg" medium="image">
			<media:title type="html">SQL Server Configuration Manager</media:title>
			<media:description type="html">SQL Server Configuration Manager</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerConfigManager-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerMSConnect.jpg" medium="image">
			<media:title type="html">SQL Server MS Connect</media:title>
			<media:description type="html">SQL Server MS Connect</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerMSConnect-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerNewDatabase.jpg" medium="image">
			<media:title type="html">SQL Server New Database</media:title>
			<media:description type="html">SQL Server New Database</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/SQLServerNewDatabase-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/ODBCCreate.jpg" medium="image">
			<media:title type="html">ODBC Create</media:title>
			<media:description type="html">Create ODBC Data Source</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/ODBCCreate-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/ODBCTest.jpg" medium="image">
			<media:title type="html">ODBC Test</media:title>
			<media:description type="html">ODBC Test</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/ODBCTest-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/HPSMServerCompatibility.jpg" medium="image">
			<media:title type="html">HPSM Server Compatibility</media:title>
			<media:description type="html">HPSM Server Compatibility</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/HPSMServerCompatibility-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/HPSMServerInstall.jpg" medium="image">
			<media:title type="html">HPSM Server Install</media:title>
			<media:description type="html">HPSM Server Install</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/HPSMServerInstall-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/HPSMconfiguration.jpg" medium="image">
			<media:title type="html">HPSM Configuration</media:title>
			<media:description type="html">HPSM Configuration</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/HPSMconfiguration-150x150.jpg" />
		</media:content>
		<media:content url="http://www.tactek.com/wp-content/uploads/2011/02/HPSMConfigDB.jpg" medium="image">
			<media:title type="html">HPSM Config DB</media:title>
			<media:description type="html">HPSM Config DB</media:description>
			<media:thumbnail url="http://www.tactek.com/wp-content/uploads/2011/02/HPSMConfigDB-150x150.jpg" />
		</media:content>
	</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic (Feed is rejected)
Page Caching using disk: enhanced

Served from: www.tactek.com @ 2012-02-22 19:38:54 -->
