﻿<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>My SQL Server Blog</title>
	<updated>2009-01-08T04:13:03Z</updated>
	<id>http://mysqlserverblog.com/atom.aspx</id>
	<link rel="self" href="http://mysqlserverblog.com/atom.aspx" />
	<link rel="alternate" href="http://mysqlserverblog.com" />
	<generator uri="http://app.onlinequickblog.com/" version="2.0">Quick Blogcast</generator>
	<entry>
		<title>RAISERROR Percent % Sign usage</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2008/01/28/raiserror-percent--sign-usage.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2008-01-28:f2dfeecf-9646-4b16-b369-c19ca281cf5d</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Queries" />
		<updated>2008-01-28T21:58:37Z</updated>
		<published>2008-01-28T21:40:00Z</published>
		<content type="html">Have you ever wondered how to build a string with values for an error message?&amp;nbsp; One would think that RASIERROR could simply take a string that was concatenated together with variables.&amp;nbsp; &lt;br&gt;&lt;br&gt;Something like RAISERROR ('My Error' + @myErrorString, 16,1)&lt;br&gt;&lt;br&gt;Unfortunately, RAISERROR is not as intuitive as this.&amp;nbsp; &lt;br&gt;&lt;br&gt;The syntax for RAISERROR is:&lt;br&gt;&lt;br&gt;RAISERROR &lt;b&gt;(&lt;/b&gt;{&lt;i&gt;msg_id&lt;/i&gt; | &lt;i&gt;msg_str&lt;/i&gt;}{&lt;b&gt;,&lt;/b&gt; &lt;i&gt;severity&lt;/i&gt;&lt;b&gt;,&lt;/b&gt; &lt;i&gt;state&lt;/i&gt;}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&lt;b&gt;,&lt;/b&gt; &lt;i&gt;argument&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/i&gt;[&lt;b&gt;,&lt;/b&gt;...&lt;i&gt;n&lt;/i&gt;]] &lt;b&gt;)&lt;/b&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[WITH &lt;i&gt;option&lt;/i&gt;[&lt;b&gt;,&lt;/b&gt;...&lt;i&gt;n&lt;/i&gt;]]&lt;br&gt;&lt;br&gt;Maybe you have seen the arguments passed into the error message string with percent sign. &lt;br&gt;&lt;br&gt;RAISERROR ('My Error %s', 16,1, @myErrorString)&lt;br&gt;&lt;br&gt;The % sign indicates the use of a parameter.&amp;nbsp; &lt;br&gt;&lt;table cellspacing="0" cols="2" width="420"&gt;&lt;tbody&gt;&lt;tr valign="top"&gt;&lt;td width="28%"&gt;d or i&lt;/td&gt;
&lt;td width="72%"&gt;Signed integer&lt;/td&gt;
&lt;/tr&gt;

&lt;tr valign="top"&gt;
&lt;td width="28%"&gt;o&lt;/td&gt;
&lt;td width="72%"&gt;Unsigned octal&lt;/td&gt;
&lt;/tr&gt;

&lt;tr valign="top"&gt;
&lt;td width="28%"&gt;p&lt;/td&gt;
&lt;td width="72%"&gt;Pointer&lt;/td&gt;
&lt;/tr&gt;

&lt;tr valign="top"&gt;
&lt;td width="28%"&gt;s&lt;/td&gt;
&lt;td width="72%"&gt;String&lt;/td&gt;
&lt;/tr&gt;

&lt;tr valign="top"&gt;
&lt;td width="28%"&gt;u&lt;/td&gt;
&lt;td width="72%"&gt;Unsigned integer&lt;/td&gt;
&lt;/tr&gt;

&lt;tr valign="top"&gt;
&lt;td width="28%"&gt;x or X&lt;/td&gt;
&lt;td width="72%"&gt;Unsigned hexadecimal&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br&gt;To pad some space a number must be placed infront of the type. &lt;br&gt;&lt;br&gt;RAISERROR ('My Error %10s', 16,1, @myErrorString,@myErrorString2)&lt;br&gt;
&lt;br&gt;To justify simply use the + or - sign after the % sign.&amp;nbsp; To pad with a space, use `` (next to the 1 key)&lt;br&gt;&lt;br&gt;If you pass more than one argument then you must use the percent signs in order.&amp;nbsp; &lt;br&gt;&lt;br&gt;RAISERROR ('My Error %10s is not cool %10s', 16,1, @myErrorString,@myErrorString2)&lt;br&gt;</content>
		<summary>Have you ever wondered how to build a string with values for an error message?  One would think that RASIERROR could simply take a string that was concatenated together with variables. 

Something like RAISERROR ('My Error' + @myErrorString, 16,1)</summary>
	</entry>
	<entry>
		<title>Changing Export Options for Reporting Services</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2008/01/03/changing-export-options-for-reporting-services.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2008-01-03:455b6360-9cb8-41c2-aa5a-162600afc0bb</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="SQL Server Reporting Services - SSRS" />
		<updated>2008-01-05T12:15:11Z</updated>
		<published>2008-01-03T21:36:00Z</published>
		<content type="html">Have you ever wanted to change the export options for Reporting Services?&amp;nbsp; Have you seen issues with report page headers being exported to Excel as non headers? Other times displaying all export options on the web is not the best idea.&amp;nbsp; An end user trying to figure out what a TIF is can be a more user support time then is desired.&amp;nbsp; In other cases the export might need to be renamed, instead of TIF call it Image.&amp;nbsp; &lt;br&gt;&lt;br&gt;To make these changes, you will have to open up the RSReportServer.config file.&amp;nbsp; It is located in the report directory of SQL server (normally something like C:\Program Files\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportServer).&amp;nbsp; This is a an XML file that can be opened in Notepad.&amp;nbsp; In the XML file, about half way through it you will see a tag called &amp;lt;RENDER&amp;gt;.&amp;nbsp; To remove options from the drop down export, delete each extension tag that you do not want.&amp;nbsp; &lt;br&gt;&lt;br&gt;&amp;lt;Render&amp;gt;&lt;br&gt;... &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &lt;br&gt;&lt;div id="1epl" class="ArwC7c ckChnd"&gt;&lt;wbr&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Extension Name="EXCEL"&amp;nbsp;&amp;nbsp;  Type="Microsoft.ReportingServices.Rendering.ExcelRenderer.ExcelRenderer,Microsoft.ReportingServices.ExcelRendering"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;OverrideNames&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Name Language="en-US"&amp;gt;EXCEL AMR&amp;lt;/Name&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/OverrideNames&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Configuration&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;DeviceInfo&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;RemoveSpace&amp;gt;0.25in&amp;lt;/RemoveSpace&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;SimplePageHeaders&amp;gt;true&amp;lt;&lt;wbr&gt;/SimplePageHeaders&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/DeviceInfo&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/Configuration&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/Extension&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/Render&amp;gt;&lt;br&gt;&lt;br&gt;To rename the options, add the tag &amp;lt;OverrideNames&amp;gt;&amp;nbsp; then the sub element tag &amp;lt;Name Language="lang"&amp;gt;(New Name)&amp;lt;/Name&amp;gt;&amp;lt;/OverrideNames&amp;gt;&lt;br&gt;&lt;br&gt;&lt;img src="http://images.quickblogcast.com/90812-79275/ssrsmenu.jpg" border="0" width="280"&gt;&lt;br&gt;&lt;br&gt;Other changes can also be configured.&amp;nbsp; In the case above I am removing any blank columns and rows that are 1/4 of an inch or less.&amp;nbsp; I am also forcing simple page headers to ensure that when exporting to Excel the headers are in Excel headers not in the first few rows of the document with a freeze pane.&amp;nbsp; This is a common problem with exporting to Excel with page headers from Reporting Services.&lt;br&gt;&lt;br&gt;&lt;img alt=""&gt;
&lt;/div&gt;To find out more about what tags are available for each option, check out &lt;a href="http://technet.microsoft.com/en-us/library/ms156281(SQL.100).aspx"&gt; MS's Technet page&lt;/a&gt;.&lt;br&gt;</content>
		<summary>Have you ever wanted to change the export options for Reporting Services?  Have you seen issues with report page headers being exported to Excel as non headers? Other times displaying all export options on the web is not the best idea.  An end user trying to figure out what a TIF is can be a more user support time then is desired.  In other cases the export might need to be renamed, instead of TIF call it Image. </summary>
	</entry>
	<entry>
		<title>SSRS Fit to Table to Page</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/12/04/ssrs-fit-to-table-to-page.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-12-04:0993228f-a09c-450a-8435-03bcb6f1c07a</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="SQL Server Reporting Services - SSRS" />
		<updated>2007-12-06T20:58:35Z</updated>
		<published>2007-12-04T21:20:00Z</published>
		<content type="html">&lt;div&gt;&lt;/div&gt;Have you ever noticed that if a Total or Sub-Total line floats until to the last page by itself?&amp;nbsp; Worse, table headers do not copy over when only a Sub-Total or Total is all by itself on the last page.&amp;nbsp; To remedy this situation there is a table option that can be set called &lt;span style="font-weight: bold;"&gt;Fit table ton one page if possible&lt;/span&gt;. &lt;br&gt;&lt;br&gt;&lt;img src="http://mysqlserverblog.com/images/90812-79275/fittopage.png" border="0" width="448"&gt;&lt;br&gt;</content>
		<summary>Have you ever noticed that if a Total or Sub-Total line floats until to the last page by itself?  Worse, table headers do not copy over when only a Sub-Total or Total is all by itself on the last page.  To remedy this situation there is a table option that can be set called Fit to Page. </summary>
	</entry>
	<entry>
		<title>TSQL ROW_NUMBER Function</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/12/03/tsql-row_number_function.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-12-03:421ad7e6-6f3f-405e-b324-4a614be85b88</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Queries" />
		<updated>2007-12-03T22:55:08Z</updated>
		<published>2007-12-03T20:42:00Z</published>
		<content type="html">&lt;div&gt;&lt;/div&gt;A great new feature of SQL Server 2005 is the ROW_NUMBER function.&amp;nbsp; In previous versions of SQL to get a numbered row would pretty much require moving the data into a temp table with an identity column, placing an identity column on the original table, or looping through data with a cursor.&lt;br&gt;&lt;br&gt;SQL Server 2005 makes adding a row number to a query a very simple task with the ROW_NUMBER function.&amp;nbsp; To use this, simply write the query like normal, say Sales Orders by Customer.&amp;nbsp; As one of the columns include the ROW_NUMBER() function with th&lt;span style="font-family: Courier New;"&gt;e &lt;span style="font-family: Verdana;"&gt;OVER clause. &lt;/span&gt;&lt;br style="font-family: Verdana;"&gt;&lt;br&gt;SELECT C.AccountNumber, C.CustomerID, SO.OrderDate,&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ROW_NUMBER() OVER (ORDER BY SO.OrderDate) AS OrderNumber&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;FROM Sales.Customer C &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN Sales.SalesOrderHeader SO ON C.CustomerID = SO.CustomerID&lt;/span&gt;&lt;br&gt;&lt;br&gt;The ORDER BY clause sorts the data, in this case by the OrderDate. The results will now return a sequential number based on the OrderDate along with the CustomerID, OrderDate, and AccountNumber.&amp;nbsp; &lt;br&gt;&lt;br&gt;Another question that might come up is if we wanted to number each row by customer and then start over at the next customer.&amp;nbsp; To do this, the partition attribute must be used as well.&lt;br&gt;&lt;br&gt;&lt;span style="font-family: Courier New;"&gt;SELECT C.AccountNumber, C.CustomerID, SO.OrderDate,&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ROW_NUMBER() OVER (PARTITION BY SO.CustomerID ORDER BY SO.OrderDate) AS OrderNumber&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;FROM Sales.Customer C &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN Sales.SalesOrderHeader SO ON C.CustomerID = SO.CustomerID&lt;/span&gt;&lt;br&gt;&lt;br&gt;Now the data contains a rownumber (OrderNumber) that resets for each customer.&lt;br&gt;&lt;br&gt;The results of the two queries are seen below:&lt;br&gt;&lt;br&gt;&amp;nbsp; &lt;img src="http://mysqlserverblog.com/images/90812-79275/row_number.gif" border="0" width="439"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;</content>
		<summary>A great new feature of SQL Server 2005 is the ROW_NUMBER function.  In previous versions of SQL to get a numbered row would pretty much require moving the data into a temp table with an identity column, placing an identity column on the original table, or looping through data with a cursor.

SQL Server 2005 makes adding a row number to a query a very simple task with the ROW_NUMBER function.</summary>
	</entry>
	<entry>
		<title>Subreports within table/matrix cells are ignored</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/11/27/subreports-within-tablematrix-cells-are-ignored.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-11-27:94315eb8-40e9-41f4-aeb1-5e2368f070d1</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="SQL Server Reporting Services - SSRS" />
		<updated>2007-11-28T21:27:51Z</updated>
		<published>2007-11-27T18:25:00Z</published>
		<content type="html">&lt;div&gt;&lt;/div&gt;Unfortunately, subreports within a table or matrix cannot be exported to Excel.&amp;nbsp; I am not sure why MS did not allow this with Reporting Services.&amp;nbsp; This came into play recently when I wanted to make a report that displayed detail data next to the header data.&amp;nbsp; This would be like displaying customer information and then orders and dollars next to the customer's information.&amp;nbsp; I wanted to display the data side by side with a running list of customer information on the left and a listing of orders on the right.&amp;nbsp; Unfortunately, lack of a vertical cell merge forced me into a subreport within a matrix.&amp;nbsp; This is not very efficient but worked.&lt;br&gt;&lt;br&gt;The work around was to change out the table and go with a table of orders inside a list of customers.&amp;nbsp; Unfortunately, the table is easier when modifying 30 rows of data.&amp;nbsp; In a list, each field is a text box not a row and column.&amp;nbsp; Now imagine moving and resizing all of them at once, can someone say Crystal Reports :O(&amp;nbsp; Placing the table next to these text boxes also created interesting issues.&amp;nbsp; When there was multiple orders, the text boxes would slide down on the print preview leaving a gap in the customer information.&amp;nbsp; To remedy this, I had to place the table in a box.&amp;nbsp; I expanded the box to the bottom of the page.&amp;nbsp; &lt;br&gt;&lt;br&gt;The last weird issue I had was how the table is treated in a list box.&amp;nbsp; I wanted to filter the table to only display that customer's orders.&amp;nbsp; Instead of calling my customer dataset for the list and order dataset for the table and filter orders based on customer; I had to make one dataset to return both customer and order information. I grouped the list by customer data, then I had to filter the table that was the same dataset by the customer number.&amp;nbsp; &lt;br&gt;&lt;br&gt;In all, this was a very time consuming and annoying process just to display the data.&amp;nbsp; I am not sure why a table in a table does not work, why there is no vertical cell merge, and why subreports don't export to excel; but I encourage MS to fix these issues.&lt;br&gt;</content>
		<summary>Unfortunately, subreports within a table or matrix cannot be exported to Excel.  I am not sure why MS did not allow this with Reporting Services. </summary>
	</entry>
	<entry>
		<title>SSRS Query Data in Header or Footer Not Exporting to Excel</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/11/16/ssrs-query-data-in-header-or-footer-not-exporting-to-excel.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-11-16:bb4db632-2579-44fe-bd91-610e1f716910</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="SQL Server Reporting Services - SSRS" />
		<updated>2007-11-16T20:00:37Z</updated>
		<published>2007-11-16T19:47:00Z</published>
		<content type="html">&lt;div&gt;&lt;/div&gt;One issue that I have noticed with SSRS is that headers and footers do not contain query data that is derived from a hidden text field.&amp;nbsp; &lt;br&gt;&lt;br&gt;The work around is to assign the data to a global parameter that is hidden.&amp;nbsp; Then reference the global parameter in the footer or header.&amp;nbsp; The data will now be available in Excel headers and footers.&amp;nbsp; &lt;br&gt;&lt;br&gt;If you are not seeing a header or footer this is because by default Excel hides the headers and footers.&amp;nbsp; In Excel 2007, click the Insert menu then the Headers &amp;amp; Footers button.&amp;nbsp; In Excel 2003, click the View menu, then Headers &amp;amp; Footers.&amp;nbsp; &lt;br&gt;</content>
		<summary>One issue that I have noticed with SSRS is that headers and footers do not contain query data that is derived from a hidden text field. </summary>
	</entry>
	<entry>
		<title>DELETE Top TSQL Statement</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/11/04/delete-top-tsql-statement.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-11-04:32de0d9c-ad2b-433f-a826-f0433f9186d6</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Queries" />
		<updated>2007-11-04T10:04:40Z</updated>
		<published>2007-11-04T09:32:00Z</published>
		<content type="html">&lt;div&gt;&lt;/div&gt;A new addition to the DELETE command in SQL Server 2005 is the TOP statement.&amp;nbsp; The DELETE TOP does the same thing as a SELECT TOP WHERE only the TOP number of rows are deleted.&amp;nbsp; &lt;br&gt;&lt;br&gt;This can be very helpful when there are duplicate rows of data present.&amp;nbsp; &lt;br&gt;&lt;br&gt;DELETE TOP (1) &lt;br&gt;FROM Sales.Customer&lt;br&gt;WHERE CustomerID = 1&lt;br&gt;&lt;br&gt;This would delete one of the duplicate rows for Customer number 1&lt;br&gt;&lt;br&gt;Suppose somehow the whole customer table got duplicated.&amp;nbsp; I duplicated the Sales.Customer table into a tmpCustomer table.&lt;br&gt;&lt;br&gt;&lt;span style="font-family: Courier New;"&gt;SELECT Top 1 CustomerID, COUNT(CustomerID) AS Cnt&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;FROM tmpCustomer &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;GROUP BY CustomerID&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;HAVING COUNT(CustomerID) &amp;gt; 1&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;WHILE @@RowCount &amp;gt; 0&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;BEGIN&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DELETE Top (1)&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM tmpCustomer&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; WHERE CustomerID = (SELECT Top (1) CustomerID&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; FROM tmpCustomer &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; GROUP BY CustomerID&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; HAVING COUNT(CustomerID) &amp;gt; 1)&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;END &lt;/span&gt;&lt;br&gt;&lt;br&gt;While this worked just fine, it ran about 4 minutes for 38K rows.&amp;nbsp; Let's try the dreaded CURSOR.&amp;nbsp;&amp;nbsp; Notice I can stick a variable in where the TOP () statement is.&amp;nbsp; I subtracted -1 because we don't want to delete every row.&lt;br&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;DECLARE @cnt int, @custID as int&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;DECLARE dupCursor CURSOR FAST_FORWARD&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;FOR SELECT CustomerID, COUNT(CustomerID) AS Cnt&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM tmpCustomer &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GROUP BY CustomerID&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; HAVING COUNT(CustomerID) &amp;gt; 1&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;OPEN dupCursor &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;FETCH NEXT FROM dupCursor &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;INTO @custID, @cnt&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;WHILE @@FETCH_STATUS = 0&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;BEGIN&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DELETE Top (@cnt-1)&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM tmpCustomer&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; WHERE CustomerID = @custID&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; FETCH NEXT FROM dupCursor &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; INTO @custID, @cnt&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;END&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;CLOSE dupCursor&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;DEALLOCATE dupCursor&lt;/span&gt;&lt;br&gt;&lt;br&gt;This ran much better at 18 seconds.&lt;br&gt;</content>
		<summary>A new addition to the DELETE command in SQL Server 2005 is the TOP statement.  The DELETE TOP does the same thing as a SELECT TOP WHERE only the TOP number of rows are deleted. </summary>
	</entry>
	<entry>
		<title>Writing JOINs vs Nested Select Queries</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/11/01/writing-joins-vs-nested-queries.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-11-01:f08b3358-c8fb-4a42-bf7e-4681ae6ca2c8</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Queries" />
		<updated>2007-11-01T20:45:00Z</updated>
		<published>2007-11-01T19:51:00Z</published>
		<content type="html">&lt;div&gt;&lt;/div&gt;I have seen a lot of is queries written without using the JOIN syntax.&amp;nbsp; Instead the developer chose to write the query using an IN clause in the WHERE clause with a SELECT statement; a Nested Query. While many people blame nested queries on developers that don't understand joins, they can actually be beneficial.&amp;nbsp; Let's take a query out of the AdventureWorks DB.&lt;br&gt;&lt;br&gt;An example would be:&lt;br&gt;&lt;br&gt;&lt;span style="font-family: Courier New;"&gt;SELECT Distinct C.AccountNumber&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;FROM Sales.Customer C&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN Sales.SalesOrderHeader O ON O.CustomerID = C.CustomerID&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN Sales.SalesPerson SP ON SP.SalesPersonID = O.SalesPersonID&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;WHERE SP.CommissionPct &amp;gt;= .015&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br&gt;this can also written as&lt;br&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;SELECT AccountNumber &lt;br&gt;FROM Sales.Customer &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;WHERE CustomerID IN (SELECT CustomerID &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; FROM Sales.SalesOrderHeader &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; WHERE SalesPersonID IN (SELECT SalesPersonID &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; FROM Sales.SalesPerson &lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; WHERE CommissionPct &amp;gt;= .015))&lt;/span&gt;&lt;br&gt;&lt;br&gt;The second query is very messy to read and I personally hate looking at queries like this, but it is faster.&amp;nbsp; To note I have an index on the SalesOrderHeader table with columns SalesPersonID, CustomerID. A distinct has to be used because multiple orders exist for a SalesPerson and Multiple Orders belong to multiple customers.&lt;br&gt;&lt;br&gt;The following are the two execution plans.&amp;nbsp; &lt;br&gt;&lt;br&gt;&lt;img style="width: 788px; height: 259px;" src="http://mysqlserverblog.com/images/90812-79275/JoinQuery.gif" border="0"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;img src="http://mysqlserverblog.com/images/90812-79275/nestedQuery.gif" border="0" width="700"&gt;&lt;br&gt;&lt;br&gt;Basically, the point is to not throw out a query because it looks messy.&amp;nbsp; Every query must be analyzed for performance and different approaches should be looked at.&lt;br&gt;</content>
		<summary>I have seen a lot of is queries written without using the JOIN syntax.  Instead the developer chose to write the query using an IN clause in the WHERE clause with a SELECT statement; a Nested Query. While many people blame nested queries on developers that don't understand joins, they can actually be beneficial. </summary>
	</entry>
	<entry>
		<title>Reseed an Identity Column</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/10/26/reseed-an-identity-column.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-10-26:63f36b45-75a7-4f9c-8c5c-c2fa8f81ea74</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="SQL Administration" />
		<updated>2007-10-26T19:29:40Z</updated>
		<published>2007-10-26T19:12:00Z</published>
		<content type="html">&lt;div&gt;&lt;/div&gt;Sometimes identity columns must be reseeded.&amp;nbsp; A good example is when merging data from a couple of different&amp;nbsp; data sources.&amp;nbsp; There is a DBCC command that makes this task easy.&lt;br&gt;&lt;br&gt;&lt;a name="syntaxToggle"&gt;&lt;span style="font-family: Courier New;"&gt;DBCC CHECKIDENT (&amp;lt;table name&amp;gt;, RESEED, &amp;lt;new value&amp;gt&lt;img src="http://mysqlserverblog.com/emoticons/wink.png" border="0" /&gt;&lt;/span&gt;&lt;br&gt;&lt;/a&gt;&lt;br&gt;To find what existing identity column values are, a simple query can be written off the sys.identity_columns system view.&lt;br&gt;&lt;pre style="font-family: Courier New;" class="code" id="ctl00_LibFrame_ctl08other" space="preserve"&gt;&lt;code style="font-size: 12px;"&gt;&lt;span style="color: blue;"&gt;&lt;/span&gt;&lt;/code&gt;&lt;code style="font-size: 12px;"&gt;&lt;span style="color: black;"&gt;&lt;/span&gt;&lt;/code&gt;SELECT   OBJECT_NAME(object_id) AS [Table],&lt;br&gt;         [name] AS [column],&lt;br&gt;         seed_value,&lt;br&gt;         last_value&lt;br&gt;FROM     sys.identity_columns&lt;br&gt;ORDER BY 1&lt;br&gt;&lt;/pre&gt;&lt;a style="font-family: Courier New;" name="syntaxToggle"&gt;&lt;/a&gt;&lt;br&gt;&lt;a name="syntaxToggle"&gt;&lt;span style="font-family: Verdana;"&gt;&lt;/span&gt;&lt;/a&gt;</content>
		<summary>Sometimes identity columns must be reseeded.  A good example is when merging data from a couple of different  data sources.  There is a DBCC command that makes this task easy.

DBCC CHECKIDENT (&lt;table name&gt;, RESEED, &lt;new value&gt;)</summary>
	</entry>
	<entry>
		<title>Selecting a Comma Delimited List with TSQL</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/09/25/selecting-a-comma-delimited-list-with-tsql.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-09-25:aa52af8a-6e39-4158-98b7-71f233a81e4b</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Queries" />
		<updated>2007-09-25T17:24:22Z</updated>
		<published>2007-09-25T17:09:00Z</published>
		<content type="html">Sometimes instead of bringing back a table set of information, a query needs to return a comma delimited list.&amp;nbsp; I have seen some crazy stuff to do this like UDFs and Cursors.&amp;nbsp; There is a really simple way to do this in a select statement though. &lt;br&gt;&lt;br&gt;&lt;span style="font-family: Courier New;"&gt;--declare a variable first&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;DECLARE @Orders varchar(MAX)&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;--varchar max is nice because there won't be overflow if the table is large&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;SET @Orders = '' --we can't concatenate NULLs so make empty string&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;SELECT @Orders = @Orders + Convert(varchar(10),Orders) + ','&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;FROM dbo.Orders&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;PRINT Left(@Orders,Len(@Orders)-1) --remove last comma&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;div&gt;&lt;/div&gt;</content>
		<summary>Sometimes instead of bringing back a table set of information, a query needs to return a comma delimited list.  I have seen some crazy stuff to do this like UDFs and Cursors.  There is a really simple way to do this in a select statement though.</summary>
	</entry>
	<entry>
		<title>Snapshot Transaction</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/09/20/snapshot-transaction.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-09-20:cca95d78-7411-462d-9f4c-f29b34a24163</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Queries" />
		<updated>2007-09-20T22:11:34Z</updated>
		<published>2007-09-20T21:54:00Z</published>
		<content type="html">A new transaction level included in SQL Server 2005 is the snapshot transaction level.&amp;nbsp; Snapshot transactions allow for data consistency without blocking.&amp;nbsp; A Snapshot transaction fits between a dirty read, Read Uncommitted, and the Read Committed level.&lt;br&gt;&lt;br&gt;Read Committed will only read data that is committed to the database.&amp;nbsp; If a process is in the middle of changing data, then the Read Committed transaction will wait for that update to be complete causing some blocking.&amp;nbsp; A Snapshot transaction will read previously committed data.&amp;nbsp; Therefore it reads a version of the data that was consistent when it was started, but does not cause blocking because it does not wait for data to be updated.&amp;nbsp; &lt;br&gt;&lt;br&gt;Snapshot transactions must be enabled in the database.&amp;nbsp; &lt;a name="sectionToggle0"&gt;The ALLOW_SNAPSHOT_ISOLATION database option must be set to ON for Snapshot transactions to work.&amp;nbsp; Also, if a transaction was started with another level then it cannot be changed to snapshot.&amp;nbsp;&amp;nbsp; You can move from Snapshot to another form though.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;/a&gt;&lt;div&gt;&lt;/div&gt;</content>
		<summary>A new transaction level included in SQL Server 2005 is the snapshot transaction level.  Snapshot transactions allow for data consistency without blocking.  A Snapshot transaction fits between a dirty read, Read Uncommitted, and the Read Committed level.</summary>
	</entry>
	<entry>
		<title>Formatting SubTotal Columns in an SSRS Matrix View</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/09/15/formatting-subtotal-columns-in-an-ssrs-matrix-view.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-09-15:ca0b9693-a358-4eff-8918-0990b0c049e2</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="SQL Server Reporting Services - SSRS" />
		<updated>2007-09-15T10:30:44Z</updated>
		<published>2007-09-15T10:16:00Z</published>
		<content type="html">Developers that are new to SSRS might be frustrated with formatting Matrix subtotal columns. Once the data in the Matrix is setup the developer might choose a sub-total for one of the column groups.&amp;nbsp; This makes a gray empty box on the row level which cannot be formatted.&amp;nbsp; Logically, this would be where the formatting would take place.&lt;br&gt;&lt;br&gt;&lt;img src="http://mysqlserverblog.com/images/90812-79275/matrixviewcellformacellst.jpg" border="0" width="253"&gt;&lt;br&gt;&lt;br&gt;One of my first projects with a Matrix report involved adding a double line border above the total
field of a Matrix report.&amp;nbsp; I struggled with this for a bit, then I
realized the green triangle in the corner is for formatting the group. Right clicking this green corner will display its properties in the properties dialog.&amp;nbsp; Clicking on the cell will only bring up the properties for the row group cell (Total in this example).&lt;br&gt;
&lt;div&gt;&lt;/div&gt;</content>
		<summary>Developers that are new to SSRS might be frustrated with formatting Matrix subtotal columns. Once the data in the Matrix is setup the developer might choose a sub-total for one of the column groups.  This makes a gray empty box on the row level which cannot be formatted.  Logically, this would be where the formatting would take place.</summary>
	</entry>
	<entry>
		<title>SQL Server Dynamic Management Views</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/08/28/sql-server-dynamic-management-views.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-08-28:a88a99d8-07aa-4f3a-baa9-323cb3aa0540</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Performance" />
		<category term="SQL Administration" />
		<updated>2007-08-29T21:20:38Z</updated>
		<published>2007-08-28T17:43:00Z</published>
		<content type="html">One of the greatest features, and in my opinion the one that makes SQL Server a top tier enterprise database, is dynamic management views.&amp;nbsp; Before SQL Server 2005, lots of time was wasted trying to analyze and solve problems using Profiler, Query Analyzer, PerfMon and other tools.&amp;nbsp; With the introduction of Dynamic Management Views (DMVs) and Dynamic Management Functions (DMFs) , administrators have a place to query recorded data to analyze issues.&amp;nbsp; DMVs provide vital information, such as index usage stats.&amp;nbsp; Since the information is already recorded by the DBMS lot's of time is saved. Also, performance tuning and other management activities can be done proactive.&lt;br&gt;&lt;br&gt;I want to briefly discuss a couple of these views.&lt;br&gt;&lt;br&gt;The&amp;nbsp; sys.dm_exec_requests view is quite useful to show processes running on the database.&amp;nbsp; &lt;br&gt;&lt;br&gt;The
sys.dm_exec_sessions will tell the sessions that are logged in.&amp;nbsp; More
information is contained here than using sp_who2.&amp;nbsp;&amp;nbsp; Join this view with
the sys.dm_exec_requests view and a lot of information will be returned
allowing a DBA to find out who is running what on the server. &lt;br&gt;&lt;br&gt;sys.dm_db_index_usage_stats&amp;nbsp; view will explain how much an index is used.&amp;nbsp; It makes a great place for finding indexes that aren't needed.&amp;nbsp; &lt;br&gt;&lt;br&gt;The missing index views (sys.dm_db_missing_index_details, sys.dm_db_missing_index_group_stats, sys.dm_db_missing_index_groups), can help to identify indexes that are needed on tables.&amp;nbsp;&amp;nbsp; The DBMS logs entries into these views when a table is scanned and an index could have been used. index_group_stats is helpful because it identifies how many times the index could have been used. &lt;br&gt;&lt;br&gt;To find out information relating to cached query plans, look in the sys.dm_exec_cached_plans view.&amp;nbsp;&amp;nbsp; While this won't tell you a lot of meaningful information, the plan handle can be gotten and used with the sys.dm_exec_sql_text and sys.dm_exec_query_plans functions to get the XML showplan and text of the query.&lt;br&gt;&lt;br&gt;If you are using a service broker application the following views are of interest:&lt;br&gt;sys.dm_broker_activated_tasks, sys.dm_broker_connections, sys.dm_broker_activated_tasks, sys.dm_broker_forwarded_messages, sys.dm_broker_queue_monitors.&amp;nbsp; These views can help monitor message volume.&lt;br&gt;&lt;br&gt;What about hardware information relating to the database?&amp;nbsp; The sys.dm_os_wait_stats view will explain the length of time processes had to wait for resources.&amp;nbsp; &lt;br&gt;&lt;br&gt;Another important hardware view is sys.dm_os_performance_counters.&amp;nbsp; I like this view.&amp;nbsp; It is basically all the counters that are pulled in PerfMon for the SQL Server category.&amp;nbsp; While it is better to pull this information in PerfMon, it is easier to manipulate by querying it here.&lt;br&gt;&lt;br&gt;&lt;div&gt;&lt;/div&gt;</content>
		<summary>One of the greatest features, and in my opinion the one that makes SQL Server a top tier enterprise database, is dynamic management views.</summary>
	</entry>
	<entry>
		<title>Correlating PerfMon with Profiler</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/08/26/correlating-perfmon-with-profiler.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-08-26:5a9504c6-ed83-4dcf-9291-dc592c21d75b</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Performance" />
		<updated>2007-08-29T21:21:38Z</updated>
		<published>2007-08-26T20:03:00Z</published>
		<content type="html">System monitor or PerfMon is a tool that most DBAs need to become
familiar with.&amp;nbsp; Many times Profiler will give information regarding to
what is running on the database but can't pinpoint the problem.&amp;nbsp; A new feature of SQL Server 2005 is the ability to correlate Profiler data with PerfMon (System Monitor).&amp;nbsp; &lt;br&gt;&lt;br&gt;To correlate the two logs:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Create a trace log in SQL Server Profiler.&lt;/li&gt;&lt;li&gt;At the same time create a PerfMon log.&amp;nbsp; &lt;br&gt;&lt;/li&gt;&lt;li&gt;Once the Profiler trace is done, stop it. &lt;br&gt;&lt;/li&gt;&lt;li&gt;In Profiler Select File -&amp;gt; Import Performance Data&lt;/li&gt;&lt;li&gt;Select the counters to correlate.&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;What is great about this is that performance problems become more apparent.&amp;nbsp; For instance, maybe the average disk queue spikes when a certain query is run.&amp;nbsp; There might be a table scan going on and the solution might be to separate the tables unto different disk arrays.&lt;br&gt;&lt;div&gt;&lt;/div&gt;</content>
		<summary>System monitor or PerfMon is a tool that most DBAs need to become familiar with.  Many times Profiler will give information regarding to what is running on the database but can't pinpoint the problem.  A new feature of SQL Server 2005 is the ability to correlate Profiler data with PerfMon (System Monitor). </summary>
	</entry>
	<entry>
		<title>Partitioning Tables part 2</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/08/22/partitioning-tables-part-2.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-08-22:a34de6a8-c0ac-41f7-93d2-2ec5f455b2d1</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Performance" />
		<updated>2007-08-22T19:16:13Z</updated>
		<published>2007-08-22T17:55:00Z</published>
		<content type="html">A few days ago, I explained how to partition a table in SQL Server 2005.&amp;nbsp; I also mentioned how moving data is very fast when using partitions.&amp;nbsp; This is because you can swap partitions to other tables without having to move data.&amp;nbsp; All that happens is a pointer to the data is changed.&amp;nbsp; This makes a file partition move great for archiving data.&lt;br&gt;&lt;br&gt;For instance, say that we have two invoice tables, one that should contain the last two years of current invoices and an archival invoice data table.&amp;nbsp; Each year is partitioned into its own filegroup.&amp;nbsp; Suppose that our production table has the year 2005 in it. This has to be moved over to our archive table.&amp;nbsp; On the archival data table we have to make a partition to contain 2005.&amp;nbsp; &lt;br&gt;&lt;br&gt;First, we need to add a filegroup for the data to be put into.&lt;br&gt;&lt;br&gt;ALTER PARTITION SCHEME myscheme&lt;br&gt;NEXT USED [filearch2005]&lt;br&gt;&lt;br&gt;To add a partition, we must split them.&amp;nbsp; Therefore, let's use the following function:&lt;br&gt;&lt;br&gt;ALTER PARTITION FUNCTION mypartfunc ()&lt;br&gt;SPLIT ('1/1/2005')&lt;br&gt;&lt;br&gt;Now everything after 2005 is in its own partition and we just need to SWITCH from our Invoice table to our InvoiceArch table.&lt;br&gt;&lt;br&gt;ALTER TABLE dbo.Invoice&lt;br&gt;SWITCH PARTITION 1 TO dbo.InvoiceArch PARTITION 5&lt;br&gt;&lt;br&gt;After the PARTITION word we need to specify the number of the partition.&amp;nbsp; Now we have moved all the 2005 data from Invoice table to the InvoiceArch table in no time without locks. &lt;br&gt;&lt;div&gt;&lt;/div&gt;</content>
		<summary>A few days ago, I explained how to partition a table in SQL Server 2005.  I also mentioned how moving data is very fast when using partitions.  This is because you can swap partitions to other tables without having to move data.  All that happens is a pointer to the data is moved.  A file partition move is great for archiving data.</summary>
	</entry>
	<entry>
		<title>Partitioning Tables</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/08/20/partitioning-tables.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-08-20:6be1ccdd-04ee-4188-9a8a-c3a8047e1ef9</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Performance" />
		<updated>2007-08-22T17:56:35Z</updated>
		<published>2007-08-20T18:18:00Z</published>
		<content type="html">SQL Server 2005 introduced a new feature to improve performance for accessing tables.&amp;nbsp; This feature is the ability to partition a table across many disk arrays.&amp;nbsp; In SQL Server 2000 a table can be placed into a file group, but there is not a way to divide up a table.&amp;nbsp; A DBA could make an indexed view that combines multiple tables via a UNION.&amp;nbsp; Each of those tables could then be put in a file group.&amp;nbsp; This takes a lot of work maintaining the code and tables.&amp;nbsp; Partitioning the data also allows for data to be moved from table to table with minimal overhead.&lt;br&gt;&lt;br&gt;To partition a table a Partition Function must be created first.&amp;nbsp; To create this use the following command.&amp;nbsp; &lt;br&gt;&lt;font face="Courier New"&gt;&lt;br&gt;CREATE PARTITION FUNCTION mypartfunc (datetime) AS&lt;br&gt;RANGE RIGHT FOR VALUES ('1/1/2005','1/1/2006','1/1/2007')&lt;/font&gt;&lt;br&gt;&lt;br&gt;Mypartfunc is the name of the function where datetime is of course the data type to divide on.&amp;nbsp; The last piece is range or the values that the data is split on.&amp;nbsp; Everything before 1/1/2005 is in the first file partition, 1/1/2005 - 12/31/2006 is the second, 1/1/2006 - 12/31/2006 is in a third file group and everything 1/1/2007 and greater is in the last file group. RANGE RIGHT means that the boundary point is included in the file group to the right.&lt;br&gt;&lt;br&gt;Once a function is created, a scheme must then be created.&amp;nbsp;&amp;nbsp; A function could be used for many different schemes; therefore, a function is really the business logic.&amp;nbsp; The scheme will tie the function to actual file groups.&amp;nbsp; These file groups can be place on separate disk arrays.&lt;br&gt;&lt;br&gt;&lt;font face="Courier New"&gt;CREATE PARTITION SCHEME myscheme AS &lt;br&gt;PARTITION mypartfunc TO&lt;br&gt;(filegroup1, filegroup2, filegroup3, filegroup4)&lt;br&gt;&lt;/font&gt;&lt;br&gt;Myscheme is the name of the scheme and the file groups are defined. &lt;br&gt;&lt;br&gt;So there is a function and a scheme.&amp;nbsp; The last piece of the puzzle is to tie these to a table or index.&amp;nbsp; You can easily do this with a CREATE TABLE or INDEX statement.&lt;br&gt;&lt;font face="Courier New"&gt;&lt;br&gt;CREATE TABLE myTable (mydate datetime, othervalue varchar(10))&lt;br&gt;ON myscheme(mydate)&lt;/font&gt;&lt;br&gt;&lt;br&gt;Myscheme is the scheme that was defined, where there the value of the scheme is the column in the table to partition on.&lt;br&gt;&lt;br&gt;In my next blog, I will discuss how using partitions can really increase performance in copying tables.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;div&gt;&lt;/div&gt;</content>
		<summary>SQL Server 2005 introduced a new feature to improve performance for accessing tables.  This feature is the ability to partition a table across many disk arrays. </summary>
	</entry>
	<entry>
		<title>Technorati</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/08/14/technorati.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-08-14:361d9780-73cf-4d27-902b-c1e200806485</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Blogging Stuff" />
		<updated>2007-08-14T20:21:38Z</updated>
		<published>2007-08-14T20:20:00Z</published>
		<content type="html">&lt;a href="http://technorati.com/claim/cskrranshs" rel="me"&gt;Technorati Profile&lt;/a&gt;</content>
	</entry>
	<entry>
		<title>Find and Replace with Wildcards and Regular Expressions in Visual Studio</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/08/14/find-and-replace-with-wildcards-and-regular-expressions-in-visual-studio.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-08-14:5899d3b3-257a-43dc-895d-7141e4834a80</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Tools" />
		<updated>2007-08-22T17:57:00Z</updated>
		<published>2007-08-14T16:58:00Z</published>
		<content type="html">Working in Reporting Services has led me to quest for a better way of doing search and replace.&amp;nbsp; Some of the reports I work on have over 100 fields.&amp;nbsp; These fields are sometimes formated with functions like FormatNumber.&amp;nbsp; When the project managers come together and decide to change things from 2 decimals to 0, a lot of time is wasted.&amp;nbsp; Each cell must be opened up and the expression in the cell changed. By using Visual Studio's advanced find and replace, this dreadful task can be done in a matter of seconds.&amp;nbsp; &lt;br&gt;&lt;br&gt;To take advantage of the find and replace:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Right click the report in the solution explorer window.&amp;nbsp; &lt;br&gt;&lt;/li&gt;&lt;li&gt;Select view code.&amp;nbsp; This will show the XML version of the RDL file instead of the designer view.&lt;/li&gt;&lt;li&gt;Select Find and Replace from the Edit Menu.&lt;/li&gt;&lt;li&gt;Click the + symbol to expand the &lt;b&gt;Find Options&lt;/b&gt; at the bottom of the dialog.&lt;/li&gt;&lt;li&gt;Check the use box.&lt;/li&gt;&lt;li&gt;Select either regular expressions or wildcards.&lt;/li&gt;&lt;/ul&gt;&lt;font face="Arial" size="2"&gt;&lt;span style="font-size: 10pt; font-family: Arial;"&gt;&lt;img src="images/90812-79275/findregexp.jpg" border="0" width="346"&gt;&lt;/span&gt;&lt;/font&gt;&lt;br&gt;&lt;br&gt;Let's take my example.&amp;nbsp; Using RegEx formula for the find, we can pickup all FormatNumber(*) in the &amp;lt; value &amp;gt; tags.&amp;nbsp; To match this case use: &lt;font face="Arial" size="2"&gt;&lt;span style="font-size: 10pt; font-family: Arial;"&gt;{=FormatNumber\(([a-zA-Z0-9_!.&lt;wbr&gt;]*)}{\)\&amp;lt;/Value\&amp;gt;}&lt;/span&gt;&lt;/font&gt;&lt;br&gt;&lt;br&gt;To explain the regex we will start with the &lt;font face="Arial" size="2"&gt;&lt;span style="font-size: 10pt; font-family: Arial;"&gt;[a-zA-Z0-9_!.&lt;wbr&gt;]* This says match all numbers, letters, _, !, and . The ! is needed because of the way you reference fields.&amp;nbsp; Of course, if you have + or - signs you will need to escape them with a backslash \&lt;br&gt;&lt;br&gt;Using {} allows a container to be used in the replace statement.&amp;nbsp; &lt;br&gt;&lt;br&gt;So in our replace we need to simply put \1,0\2&amp;nbsp; This is basically saying "=FormatNumber(&amp;lt;whatever field was here&amp;gt;" &amp;amp; ",0" &amp;amp; ")&amp;lt;/Value&amp;gt;"&lt;br&gt;&lt;br&gt;For more information, check out &lt;a href="http://msdn2.microsoft.com/en-us/library/2k3te2cs%28VS.80%29.aspx"&gt; Microsoft's MSDN page&lt;/a&gt;.&amp;nbsp; &lt;br&gt;&lt;/span&gt;&lt;/font&gt;&lt;br&gt;&lt;div&gt;&lt;/div&gt;</content>
		<summary>Working in Reporting Services has led me to quest for a better way of doing search and replace.  Some of the reports I work on have over 100 fields.  These fields are sometimes formated with functions like FormatNumber.  When the project managers come together and decide to change things from 2 decimals to 0, a lot of time is wasted.  Each cell must be opened up and the expression in the cell changed. By using Visual Studio's advanced find and replace, this dreadful task can be done in a matter of seconds. </summary>
	</entry>
	<entry>
		<title>Truncate Table Instead of Delete</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/08/13/truncate-table-instead-of-delete.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-08-13:68356705-2245-4abb-ada3-9df9b3e4b897</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Performance" />
		<category term="Queries" />
		<updated>2007-08-13T20:30:52Z</updated>
		<published>2007-08-13T19:44:00Z</published>
		<content type="html">Some procedures or queries may require a table to be emptied, like a DTS/SSIS job.&amp;nbsp; If the table deletion does not need to be rolled back, consider using a TRUNCATE TABLE instead of DELETE table.&amp;nbsp; &lt;br&gt;&lt;br&gt;The truncate is faster than a delete statement for several reasons. It does not require logging to the transaction log.&amp;nbsp; A DELETE statement removes a single row at a time whereas a truncate will only deallocate the pages.&amp;nbsp; Finally, a TRUNCATE will place a table lock instead of row or page locks on the table.&lt;br&gt;&lt;br&gt;A TRUNCATE TABLE statement requires more permissions then a simple delete.&amp;nbsp; The person executing a TRUNCATE must be the table owner, sysadmin, database owner or a db_ddladmin.&amp;nbsp; Although, if the TRUNCATE is in a stored procedure, the permissions can easily be elevated for that proc by using the EXECUTE AS clause.&lt;br&gt;&lt;div&gt;&lt;/div&gt;</content>
		<summary>Some procedures or queries may require a table to be emptied, like a DTS/SSIS job.  If the table deletion does not need to be rolled back, consider using a TRUNCATE TABLE instead of DELETE table. </summary>
	</entry>
	<entry>
		<title>Performance degradation because of views part 2</title>
		<link rel="alternate" href="http://mysqlserverblog.com/2007/08/08/performance-degradation-because-of-views-part-2.aspx?ref=rss" />
		<id>tag:mysqlserverblog.com,2007-08-08:d048b810-3fd3-4618-825e-a6681122aaf1</id>
		<author>
			<name>Adam Rink</name>
		</author>
		<category term="Performance" />
		<category term="Queries" />
		<updated>2007-09-15T10:34:50Z</updated>
		<published>2007-08-08T17:23:00Z</published>
		<content type="html">A few days ago, I explained why a catch all type view used by some developers is horrible for performance.&amp;nbsp; The issues with views does not stop with lazy coding.&amp;nbsp; Another issue with views are ones that perform calculations or use UNIONs.&amp;nbsp; A problem with calculations or even UNIONS, is that the view must bring back all the rows to do a calculation or some other logic.&amp;nbsp; It then filters those rows by your query.&lt;br&gt;&lt;br&gt;For an example, let's take a query in the Adventure Works database and make a query with it. &lt;br&gt;&lt;br&gt;&lt;font face="Courier New"&gt;SELECT Product.productID, Product.[Name], Product.ModifiedDate, I.Quantity&lt;br&gt;FROM&lt;br&gt;(&amp;nbsp;&amp;nbsp;&amp;nbsp; --this is a inline view&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT ProductID = &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; CASE &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; WHEN p.ProductID &amp;lt; 100 THEN 0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ELSE p.ProductID&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; END, &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; p.Name, ph.ModifiedDate&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Production.Product p&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; LEFT JOIN Production.ProductCostHistory ph ON ph.ProductID = p.ProductID&lt;br&gt;) AS Product&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN Production.ProductInventory I ON I.ProductID = Product.ProductID&lt;br&gt;WHERE I.Quantity &amp;gt; 0 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; AND Product.ProductID = '707'&lt;/font&gt;&lt;br&gt;&lt;br&gt;Not a great query but the execution plan will show the tale with an index scan retrieving all the product information.&lt;br&gt;&lt;br&gt;&lt;img src="images/90812-79275/sqlserverviewperformance3.gif" border="0" width="700"&gt;&lt;font face="Courier New"&gt;SELECT&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ProductID = &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; CASE &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; WHEN product.ProductID &amp;lt; 100 THEN 0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ELSE product.ProductID&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; END,&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; [Name],Product.ModifiedDate, I.Quantity&lt;br&gt;FROM&lt;br&gt;(&amp;nbsp;&amp;nbsp;&amp;nbsp; --this is a inline view, with out the case statement&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT p.ProductID, p.Name, ph.ModifiedDate&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Production.Product p&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; LEFT JOIN Production.ProductCostHistory ph ON ph.ProductID = p.ProductID&lt;br&gt;) AS Product&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN Production.ProductInventory I ON I.ProductID = Product.ProductID&lt;br&gt;WHERE I.Quantity &amp;gt; 0 &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; AND Product.ProductID = '707'&lt;br&gt;&lt;br&gt;&lt;img src="http://app.quickblogcast.com/images/90812-79275/sqlserverviewperformance4.gif" border="0" width="700"&gt;&lt;br&gt;&lt;/font&gt;&lt;br&gt;All we did was move the CASE statement out of the view and into the query.&amp;nbsp; Notice the index seeks now. In the Adventure Works DB this barely makes a difference, but if we had a few million rows, this would make a big difference.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;div&gt;&lt;/div&gt;</content>
		<summary>A few days ago, I explained why a catch all type view used by some developers is horrible for performance.  The issues with views does not stop with lazy coding.  Another issue with views are ones that perform calculations or use UNIONs.  A problem with calculations or even UNIONS, is that the view must bring back all the rows to do a calculation or some other logic.  It then filters those rows by your query.</summary>
	</entry>
</feed>