﻿<?xml version="1.0" encoding="utf-8"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><ttl>60</ttl><title>My SQL Server Blog</title><link>http://mysqlserverblog.com</link><language>en</language><copyright /><itunes:subtitle> </itunes:subtitle><itunes:author>Adam Rink</itunes:author><itunes:summary /><description /><itunes:owner><itunes:name>Adam Rink</itunes:name><itunes:email>gryphonsclaw@gmail.com</itunes:email></itunes:owner><itunes:explicit>no</itunes:explicit><itunes:category text="Arts" /><item><title>RAISERROR Percent % Sign usage</title><link>http://mysqlserverblog.com/2008/01/28/raiserror-percent--sign-usage.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>Queries</category><comments>http://mysqlserverblog.com/2008/01/28/raiserror-percent--sign-usage.aspx#Comments</comments><guid isPermaLink="false">f2dfeecf-9646-4b16-b369-c19ca281cf5d</guid><pubDate>Mon, 28 Jan 2008 21:58:37 GMT</pubDate></item><item><title>Changing Export Options for Reporting Services</title><link>http://mysqlserverblog.com/2008/01/03/changing-export-options-for-reporting-services.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>SQL Server Reporting Services - SSRS</category><comments>http://mysqlserverblog.com/2008/01/03/changing-export-options-for-reporting-services.aspx#Comments</comments><guid isPermaLink="false">455b6360-9cb8-41c2-aa5a-162600afc0bb</guid><pubDate>Sat, 05 Jan 2008 12:15:11 GMT</pubDate></item><item><title>SSRS Fit to Table to Page</title><link>http://mysqlserverblog.com/2007/12/04/ssrs-fit-to-table-to-page.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>&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;</description><category>SQL Server Reporting Services - SSRS</category><comments>http://mysqlserverblog.com/2007/12/04/ssrs-fit-to-table-to-page.aspx#Comments</comments><guid isPermaLink="false">0993228f-a09c-450a-8435-03bcb6f1c07a</guid><pubDate>Thu, 06 Dec 2007 20:58:35 GMT</pubDate></item><item><title>TSQL ROW_NUMBER Function</title><link>http://mysqlserverblog.com/2007/12/03/tsql-row_number_function.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>&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;</description><category>Queries</category><comments>http://mysqlserverblog.com/2007/12/03/tsql-row_number_function.aspx#Comments</comments><guid isPermaLink="false">421ad7e6-6f3f-405e-b324-4a614be85b88</guid><pubDate>Mon, 03 Dec 2007 22:55:08 GMT</pubDate></item><item><title>Subreports within table/matrix cells are ignored</title><link>http://mysqlserverblog.com/2007/11/27/subreports-within-tablematrix-cells-are-ignored.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>&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;</description><category>SQL Server Reporting Services - SSRS</category><comments>http://mysqlserverblog.com/2007/11/27/subreports-within-tablematrix-cells-are-ignored.aspx#Comments</comments><guid isPermaLink="false">94315eb8-40e9-41f4-aeb1-5e2368f070d1</guid><pubDate>Wed, 28 Nov 2007 21:27:51 GMT</pubDate></item><item><title>SSRS Query Data in Header or Footer Not Exporting to Excel</title><link>http://mysqlserverblog.com/2007/11/16/ssrs-query-data-in-header-or-footer-not-exporting-to-excel.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>&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;</description><category>SQL Server Reporting Services - SSRS</category><comments>http://mysqlserverblog.com/2007/11/16/ssrs-query-data-in-header-or-footer-not-exporting-to-excel.aspx#Comments</comments><guid isPermaLink="false">bb4db632-2579-44fe-bd91-610e1f716910</guid><pubDate>Fri, 16 Nov 2007 20:00:37 GMT</pubDate></item><item><title>DELETE Top TSQL Statement</title><link>http://mysqlserverblog.com/2007/11/04/delete-top-tsql-statement.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>&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;</description><category>Queries</category><comments>http://mysqlserverblog.com/2007/11/04/delete-top-tsql-statement.aspx#Comments</comments><guid isPermaLink="false">32de0d9c-ad2b-433f-a826-f0433f9186d6</guid><pubDate>Sun, 04 Nov 2007 10:04:40 GMT</pubDate></item><item><title>Writing JOINs vs Nested Select Queries</title><link>http://mysqlserverblog.com/2007/11/01/writing-joins-vs-nested-queries.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>&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;</description><category>Queries</category><comments>http://mysqlserverblog.com/2007/11/01/writing-joins-vs-nested-queries.aspx#Comments</comments><guid isPermaLink="false">f08b3358-c8fb-4a42-bf7e-4681ae6ca2c8</guid><pubDate>Thu, 01 Nov 2007 20:45:00 GMT</pubDate></item><item><title>Reseed an Identity Column</title><link>http://mysqlserverblog.com/2007/10/26/reseed-an-identity-column.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>&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;</description><category>SQL Administration</category><comments>http://mysqlserverblog.com/2007/10/26/reseed-an-identity-column.aspx#Comments</comments><guid isPermaLink="false">63f36b45-75a7-4f9c-8c5c-c2fa8f81ea74</guid><pubDate>Fri, 26 Oct 2007 19:29:40 GMT</pubDate></item><item><title>Selecting a Comma Delimited List with TSQL</title><link>http://mysqlserverblog.com/2007/09/25/selecting-a-comma-delimited-list-with-tsql.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>Queries</category><comments>http://mysqlserverblog.com/2007/09/25/selecting-a-comma-delimited-list-with-tsql.aspx#Comments</comments><guid isPermaLink="false">aa52af8a-6e39-4158-98b7-71f233a81e4b</guid><pubDate>Tue, 25 Sep 2007 17:24:22 GMT</pubDate></item><item><title>Snapshot Transaction</title><link>http://mysqlserverblog.com/2007/09/20/snapshot-transaction.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>Queries</category><comments>http://mysqlserverblog.com/2007/09/20/snapshot-transaction.aspx#Comments</comments><guid isPermaLink="false">cca95d78-7411-462d-9f4c-f29b34a24163</guid><pubDate>Thu, 20 Sep 2007 22:11:34 GMT</pubDate></item><item><title>Formatting SubTotal Columns in an SSRS Matrix View</title><link>http://mysqlserverblog.com/2007/09/15/formatting-subtotal-columns-in-an-ssrs-matrix-view.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>SQL Server Reporting Services - SSRS</category><comments>http://mysqlserverblog.com/2007/09/15/formatting-subtotal-columns-in-an-ssrs-matrix-view.aspx#Comments</comments><guid isPermaLink="false">ca0b9693-a358-4eff-8918-0990b0c049e2</guid><pubDate>Sat, 15 Sep 2007 10:30:44 GMT</pubDate></item><item><title>SQL Server Dynamic Management Views</title><link>http://mysqlserverblog.com/2007/08/28/sql-server-dynamic-management-views.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>Performance</category><category>SQL Administration</category><comments>http://mysqlserverblog.com/2007/08/28/sql-server-dynamic-management-views.aspx#Comments</comments><guid isPermaLink="false">a88a99d8-07aa-4f3a-baa9-323cb3aa0540</guid><pubDate>Wed, 29 Aug 2007 21:20:38 GMT</pubDate></item><item><title>Correlating PerfMon with Profiler</title><link>http://mysqlserverblog.com/2007/08/26/correlating-perfmon-with-profiler.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>Performance</category><comments>http://mysqlserverblog.com/2007/08/26/correlating-perfmon-with-profiler.aspx#Comments</comments><guid isPermaLink="false">5a9504c6-ed83-4dcf-9291-dc592c21d75b</guid><pubDate>Wed, 29 Aug 2007 21:21:38 GMT</pubDate></item><item><title>Partitioning Tables part 2</title><link>http://mysqlserverblog.com/2007/08/22/partitioning-tables-part-2.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>Performance</category><comments>http://mysqlserverblog.com/2007/08/22/partitioning-tables-part-2.aspx#Comments</comments><guid isPermaLink="false">a34de6a8-c0ac-41f7-93d2-2ec5f455b2d1</guid><pubDate>Wed, 22 Aug 2007 19:16:13 GMT</pubDate></item><item><title>Partitioning Tables</title><link>http://mysqlserverblog.com/2007/08/20/partitioning-tables.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>Performance</category><comments>http://mysqlserverblog.com/2007/08/20/partitioning-tables.aspx#Comments</comments><guid isPermaLink="false">6be1ccdd-04ee-4188-9a8a-c3a8047e1ef9</guid><pubDate>Wed, 22 Aug 2007 17:56:35 GMT</pubDate></item><item><title>Technorati</title><link>http://mysqlserverblog.com/2007/08/14/technorati.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>&lt;a href="http://technorati.com/claim/cskrranshs" rel="me"&gt;Technorati Profile&lt;/a&gt;</description><category>Blogging Stuff</category><comments>http://mysqlserverblog.com/2007/08/14/technorati.aspx#Comments</comments><guid isPermaLink="false">361d9780-73cf-4d27-902b-c1e200806485</guid><pubDate>Tue, 14 Aug 2007 20:21:38 GMT</pubDate></item><item><title>Find and Replace with Wildcards and Regular Expressions in Visual Studio</title><link>http://mysqlserverblog.com/2007/08/14/find-and-replace-with-wildcards-and-regular-expressions-in-visual-studio.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>Tools</category><comments>http://mysqlserverblog.com/2007/08/14/find-and-replace-with-wildcards-and-regular-expressions-in-visual-studio.aspx#Comments</comments><guid isPermaLink="false">5899d3b3-257a-43dc-895d-7141e4834a80</guid><pubDate>Wed, 22 Aug 2007 17:57:00 GMT</pubDate></item><item><title>Truncate Table Instead of Delete</title><link>http://mysqlserverblog.com/2007/08/13/truncate-table-instead-of-delete.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>Performance</category><category>Queries</category><comments>http://mysqlserverblog.com/2007/08/13/truncate-table-instead-of-delete.aspx#Comments</comments><guid isPermaLink="false">68356705-2245-4abb-ada3-9df9b3e4b897</guid><pubDate>Mon, 13 Aug 2007 20:30:52 GMT</pubDate></item><item><title>Performance degradation because of views part 2</title><link>http://mysqlserverblog.com/2007/08/08/performance-degradation-because-of-views-part-2.aspx?ref=rss</link><dc:creator>Adam Rink</dc:creator><description>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;</description><category>Performance</category><category>Queries</category><comments>http://mysqlserverblog.com/2007/08/08/performance-degradation-because-of-views-part-2.aspx#Comments</comments><guid isPermaLink="false">d048b810-3fd3-4618-825e-a6681122aaf1</guid><pubDate>Sat, 15 Sep 2007 10:34:50 GMT</pubDate></item></channel></rss>