<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><title type="html">James World</title><subtitle type="html">Comments On Code</subtitle><id>http://blogs.msdn.com/james_world/atom.xml</id><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/default.aspx" /><link rel="self" type="application/atom+xml" href="http://blogs.msdn.com/james_world/atom.xml" /><generator uri="http://communityserver.org" version="2.1.61025.2">Community Server</generator><updated>2005-07-07T20:42:00Z</updated><entry><title>Publishing InfoPath Forms: "The following URL is not valid:..."</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2008/07/12/publishing-infoparth-forms-the-following-url-is-not-valid.aspx" /><id>http://blogs.msdn.com/james_world/archive/2008/07/12/publishing-infoparth-forms-the-following-url-is-not-valid.aspx</id><published>2008-07-12T10:27:00Z</published><updated>2008-07-12T10:27:00Z</updated><content type="html">I got the above error when trying to publish an InfoPath form. In my case the "problem" was that I had no SharePoint site at the root of the URL - i.e. I only had sites under the /sites/ folder. Smells like a bug to me... and an ugly one at that. I created a site at the root to get round it.&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8723063" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author></entry><entry><title>More Kerberos in SharePoint: The lifetime of a Kerberos ticket</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2007/08/21/more-kerberos-controlling-the-lifetime-of-the-a-kerberos-ticket.aspx" /><id>http://blogs.msdn.com/james_world/archive/2007/08/21/more-kerberos-controlling-the-lifetime-of-the-a-kerberos-ticket.aspx</id><published>2007-08-21T08:44:00Z</published><updated>2007-08-21T08:44:00Z</updated><content type="html">&lt;P&gt;I had a great follow-up question from my last post on &lt;A class="" href="http://blogs.msdn.com/james_world/archive/2007/08/20/essential-guide-to-kerberos-in-sharepoint.aspx" mce_href="http://blogs.msdn.com/james_world/archive/2007/08/20/essential-guide-to-kerberos-in-sharepoint.aspx"&gt;Kerberos in SharePoint&lt;/A&gt;:&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;"We are using Kerberos for our MOSS based server and there is one page which renders a list based on the current user's membership groups. The issue is that once the user is removed from the group, he should not see the list contents. However if the Kerberos token is obtained prior to the removal from the group, the user continues to see the list until the ticket expires. In other words, the ticket has to be purged in order to get the latest changes from AD."&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;The old adage that for every "yin" there is a "yang" holds true here. The reason why Kerberos performs so much better than NTLM over long-running conversations between a client and server is that NTLM requires the server to ask a DC to validate the client's response to a challenge every time authentication is required, whereas with Kerberos the server &lt;EM&gt;never&lt;/EM&gt; has to contact a DC to validate a client's ticket, which once obtained by a client&amp;nbsp;is valid by default for 10 hours. (This number was chosen as it&amp;nbsp;is slightly longer than&amp;nbsp;a typical&amp;nbsp;working day).&lt;/P&gt;
&lt;P&gt;The trade-off here is that a ticket can't be invalidated by the KDC. Once a client has one, it's good until it's expiry date or until the logon session is terminated (i.e. the client logs off) at which point the ticket cache is cleared. Since group membership information is embedded in a ticket, this means you can't use group membership to quickly grant or deny client access to a resource. With NTLM, group membership information is returned every time the server authenticates the client (although even with NTLM you can run into group membership caching problems if tokens are cached by the server).&lt;/P&gt;
&lt;P&gt;Software&amp;nbsp;solutions&amp;nbsp;sometimes work round this&amp;nbsp;by allowing you to deny access based on a client identity&amp;nbsp;- however this isn't always particularly manageable and isn't an option in SharePoint.&lt;/P&gt;
&lt;P&gt;A more extreme option is to configure the lifetime of a ticket. In Windows this is a policy applied to the whole Kerberos realm (Domain) via group policy. I recommend taking great care changing this setting as it may affect adversely performance in your domain - but it is an option. The specifc location and settings in the GPO are described &lt;A class="" href="http://technet2.microsoft.com/windowsserver/en/library/353f7ad9-b53d-41d0-9867-199f6595a01b1033.mspx#w2k3tr_sepol_accou_set_hpjo" mce_href="http://technet2.microsoft.com/windowsserver/en/library/353f7ad9-b53d-41d0-9867-199f6595a01b1033.mspx#w2k3tr_sepol_accou_set_hpjo"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;In general, I rarely come across situations where it is actually a business necessity to immediately deny a client access to a resource. Since Kerberos is an intranet protocol if you have a situation where a security concern arises with a user then you can do a number of things -&amp;nbsp;remote&amp;nbsp;log-off or shut-down their machine, or send a heavies from security round to see them for example!&lt;/P&gt;
&lt;P&gt;If you absolutely need to do this in SharePoint, then granting and removing access to SharePoint based on&amp;nbsp;SharePoint group membership (rather than Windows group membership) is probably your best bet.&lt;/P&gt;
&lt;P&gt;If you want to&amp;nbsp;know more about Kerberos I suggest starting with &lt;A class="" href="http://www.pluralsight.com/wiki/default.aspx/Keith.GuideBook.HomePage" mce_href="http://www.pluralsight.com/wiki/default.aspx/Keith.GuideBook.HomePage"&gt;Keith Brown's guide&lt;/A&gt;&amp;nbsp;items&amp;nbsp;59-62&amp;nbsp;and if that doesn't satiate you then move on to this monster:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://technet2.microsoft.com/windowsserver/en/library/4a1daa3e-b45c-44ea-a0b6-fe8910f92f281033.mspx?mfr=true"&gt;http://technet2.microsoft.com/windowsserver/en/library/4a1daa3e-b45c-44ea-a0b6-fe8910f92f281033.mspx?mfr=true&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Good luck!&lt;/P&gt;
&lt;P mce_keep="true"&gt;James.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4490073" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author><category term="kerberos SharePoint" scheme="http://blogs.msdn.com/james_world/archive/tags/kerberos+SharePoint/default.aspx" /></entry><entry><title>Essential Tips On Kerberos for SharePoint Deployers</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2007/08/20/essential-guide-to-kerberos-in-sharepoint.aspx" /><id>http://blogs.msdn.com/james_world/archive/2007/08/20/essential-guide-to-kerberos-in-sharepoint.aspx</id><published>2007-08-20T14:41:00Z</published><updated>2007-08-20T14:41:00Z</updated><content type="html">&lt;P&gt;Hi,&lt;/P&gt;
&lt;P&gt;This definitely isn't the first blog post on this topic, and it certainly won't be the last -&amp;nbsp;but hopefully it will bring some peace and understanding to those struggling to get Kerberos working in a live SharePoint deployment.&lt;/P&gt;
&lt;P&gt;First off, I must credit Martin Kearn's excellent posts &lt;A class="" href="http://blogs.msdn.com/martinkearn/archive/2007/04/23/configuring-kerberos-for-sharepoint-2007-part-1-base-configuration-for-sharepoint.aspx" target=_blank mce_href="http://blogs.msdn.com/martinkearn/archive/2007/04/23/configuring-kerberos-for-sharepoint-2007-part-1-base-configuration-for-sharepoint.aspx"&gt;here&lt;/A&gt; that were invaluable in getting me started - and will be invaluable to you too.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Why Use Kerberos?&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;There are a number of good resources that aid understanding Kerberos - the best (imho) being from Keith Brown's .NET security guide, published on the web. If you want to know what Kerberos is, what SPNs are, what delegation is etc. go read items 59-63 of his book here:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.pluralsight.com/wiki/default.aspx/Keith.GuideBook.HomePage"&gt;http://www.pluralsight.com/wiki/default.aspx/Keith.GuideBook.HomePage&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;But to summarise the key points from a SharePoint perspective, if you want better authentication performance than NTLM, use Kerberos. If you want to pass your user's credentials through to back end resources (like for example accessing the database exposed through a Business Data Catalog) - then you'll need Kerberos delegation.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Crucial SPN Knowledge&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Lets just define the parts of an SPN first - an SPN looks something like this ( a typical SPN&amp;nbsp;for a SQL Server in this case ):&lt;/P&gt;
&lt;P&gt;MSSqlSvc/bob.domain.local:1433&lt;/P&gt;
&lt;P&gt;Where "MSSqlSvc" is the &lt;STRONG&gt;service class&lt;/STRONG&gt;, "bob.domain.local" is the &lt;STRONG&gt;host&lt;/STRONG&gt; and 1433 is the &lt;STRONG&gt;port&lt;/STRONG&gt;. The port part (including the colon) is optional.&lt;/P&gt;
&lt;P&gt;SPNs are basically arbitrary strings that applications "know" how to assemble. They are stored in AD&amp;nbsp;in&amp;nbsp;a multi-valued attribute called &lt;STRONG&gt;servicePrincipalName&lt;/STRONG&gt; on&amp;nbsp;user principals. (Multi-valued attributes are what they sound like, attributes that can have none or more values and are&amp;nbsp;typically displayed&amp;nbsp;as a comma-delimited list.)&lt;/P&gt;
&lt;P&gt;SetSPN is the&amp;nbsp;tool you should use to create SPNs. When you use SetSPN -A you are just setting this attribute. It's perfectly valid to do this with adsiedit.msc or any other AD&amp;nbsp;editing tool&amp;nbsp;- I don't recommend you do this because SetSPN does some validation to ensure the SPN follows syntax conventions that a direct edit would bypass -&amp;nbsp;I'm just making the point that there is no magic going on and that SPNs are just strings. To set an SPN (with SetSPN or otherwise)&amp;nbsp;you must have&amp;nbsp;permission to&amp;nbsp;write to&amp;nbsp;ServicePrincipalName attribute on the target principal (and that is your least privilege requirement) - although it's a good idea to be able to read them as well.&lt;/P&gt;
&lt;P&gt;When a client application wishes to authenticate to a server application with Kerberos, the client must acquire a ticket from the KDC ( = Key Distribution Center which is a role played by Domain Controllers in Windows). To do this, it must tell the KDC which SPN it wants a ticket for. The KDC will take this SPN and&amp;nbsp;look for&amp;nbsp;a principal that has a matching string in its servicePrincipalName attribute.&lt;/P&gt;
&lt;P&gt;At the point a couple of things can go wrong: (1) The KDC is unable to find a match in the AD. (2) The KDC finds &lt;EM&gt;more&lt;/EM&gt; &lt;EM&gt;than one&lt;/EM&gt; match in the AD. In either case, you're stuffed&amp;nbsp;and Kerberos authentication will fail. At this point most applications will silently fall back to NTLM authentication and everything will appear to work - unless you need delegation or you have demanded Kerberos authentication. Not many apps demand Kerberos, they usually "Negotiate" an authentication protocol. If you are trying to delegate, then what often happens is that the machine at the end of the second hop&amp;nbsp;gets a NULL identity turning up (see Keith Brown's explanations linked to earlier).&lt;/P&gt;
&lt;P&gt;So remember: you &lt;STRONG&gt;can not have two identical SPNs registed to different accounts in your forest.&lt;EM&gt; &lt;/EM&gt;&lt;/STRONG&gt;If you do this, neither will work.&lt;/P&gt;
&lt;P mce_keep="true"&gt;So how does the client know which SPN to ask for? Well that's very interesting. It turns out the answer is largely&amp;nbsp;"because it does". The service class and host&amp;nbsp;+ port&amp;nbsp;parts of an SPN&amp;nbsp;are completely arbitrary. The client must therefore "know" these things to correctly form an SPN. The one thing it doesn't know (or need to know) is the identity of the principal running the service - the KDC figures this out and passes back a ticket that only the principal against which the SPN is registered will be able to decrypt.&lt;/P&gt;
&lt;P mce_keep="true"&gt;In the case of Internet Explorer, the SPN requested is formed by using&amp;nbsp;a service class of HTTP and a host as specified in the URL, converted to an FQDN (fully qualified domain name) if possible.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Here's the rub: &lt;STRONG&gt;IE&amp;nbsp;never appends&amp;nbsp;the port number&amp;nbsp;to the&amp;nbsp;host name&amp;nbsp;when contacting the KDC for a ticket&amp;nbsp;- even if your server is on a port other than port 80!&lt;/STRONG&gt; So for all those SharePoint sites you have on non-80 ports, if you've been specifying a port number in your setspn command, then you haven't been using Kerberos!&lt;/P&gt;
&lt;P mce_keep="true"&gt;Because of the way IE works, its typical to register two SPNs for every web-site. One with the netbios Host name and one with the FQDN host name - this keeps all the bases covered. Just don't put in the port!&lt;/P&gt;
&lt;P mce_keep="true"&gt;So if I ask for http://moss:10000/sites/test for example, then IE will pass an SPN of "HTTP/moss.sharepoint.local" to the KDC (assuming moss is resolved to a box in my sharepoint.local domain) or just "HTTP/moss" if it can't be resolved.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;EM&gt;UPDATE: Thanks to Brad Turner for his research on this point&amp;nbsp;- it turns out that there was a fix released for IE that enabled a special registry key setting that changes IE's behaviour so the port number IS included. However, I don't recommend you do this because it is a client side fix, and it's probably hard to guarantee all your clients will have this setting. Even if you use Group Policy to enforce a registry setting, I still don't like it.&amp;nbsp;If you really want to know the details, drop me a line; but be aware I will raise my eyebrow at you!&lt;/EM&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;If you are using host-headers on your website, then use those in your SPN. Remember it's whatever is in the address bar that IE will use to request the SPN. A host-header is set on&amp;nbsp;the dialog you get from the "Advanced..." button on the "Web Site" tab of a web site in IIS 6.0 Manager. It allows IIS to have multiple web-sites on the same port and IIS looks at the address (host header) requested by the client to work out which website to direct the request to. For example, in my MOSS installation I have something like:&lt;/P&gt;
&lt;P mce_keep="true"&gt;portal.sharepoint.local, mysite.sharepoint.local, ssp.sharepoint.local etc. all pointing to the same IP address. The host header can be specified in Central Admin when creating web applications.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;You Probably Need Multiple Host Headers&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;This throws up an interesting point that in most cases this means you will &lt;STRONG&gt;need&lt;/STRONG&gt; multiple host-headers in order to be able to use Kerberos in a least privilege environment.&amp;nbsp;Every application pool in a least privilege environment has its own identity. This means that your web applications, which&amp;nbsp;are sitting in different application pools, can't&amp;nbsp;be differentiated by simply using&amp;nbsp;different ports. If&amp;nbsp;you did this, since IE ignores the port when forming&amp;nbsp;its SPN request,&amp;nbsp;the SPNs for each application pool identity&amp;nbsp;would have to be the same - and you can't register the same SPN against multiple accounts! (Oh how I wish this would throw an error!) Thus,&amp;nbsp;a different host header is required to get a Kerberos ticket for each application pool identity in which your SharePoint web applications reside.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;How Do I Know Its Working?&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Good question. The easiest way is to download &lt;A class="" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=4E3A58BE-29F6-49F6-85BE-E866AF8E7A88&amp;amp;displaylang=en" target=_blank mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=4E3A58BE-29F6-49F6-85BE-E866AF8E7A88&amp;amp;displaylang=en"&gt;Kerbtray.exe&lt;/A&gt; (don't worry this says Windows 2000 - it works on all versions). This tool lets you examine the Kerberos tickets for the&amp;nbsp;&lt;STRONG&gt;logon session of the current interactive user only&lt;/STRONG&gt;. This means that you can't do something like "Run As" to see the tickets of a service - because you'll be in a different logon session even though its the same principal. However, you can run this tool in a couple of useful places:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Run it during initial set up of the farm. At this point the setup account connects to SQL server so you should see a ticket for your SQL box - MSSqlSvc/sql.sharepoint.local:1433 for example.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Run it on any client machine connecting to a SharePoint web site. You should see a ticket for the web site in the list - HTTP/portal.sharepoint.local for example.&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;Also, on SQL Server 2005 you can run a query to check how clients are authenticating. You should see "KERBEROS" in the auth_scheme column:&lt;/P&gt;
&lt;P mce_keep="true"&gt;SELECT login_name, program_name, host_name, auth_scheme&lt;BR&gt;FROM sys.dm_exec_connections C INNER JOIN sys.dm_exec_sessions S&lt;BR&gt;ON C.session_id&amp;nbsp; = S.session_id&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Delegation&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;If you want to delegate then you need to do more than just create SPNs. You must allow the services that will delegate right to do so. This is described in Keith Brown's guide again. For SharePoint, the services that&amp;nbsp;are&amp;nbsp;most likely to&amp;nbsp;need&amp;nbsp;rights to delegate are the application pool accounts and the SSP service account. You almost certainly don't need to give the computer accounts delegation rights!&lt;/P&gt;
&lt;P mce_keep="true"&gt;A common scenario is BDC delegation where you want your end-users to authenticate against a database directly when querying a BDC web-part for auditing purposes. In this case you just need the application pool hosting the site hosting the web part to have delegation rights - and that's it!&lt;/P&gt;
&lt;P mce_keep="true"&gt;Hope that helps!&lt;/P&gt;
&lt;P mce_keep="true"&gt;James&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;EM&gt;&amp;nbsp;ADDENDUM:&lt;/EM&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;EM&gt;Since writing this article the infrastructure update has added some new functionality that includes custom SPNs for SSPs. It's covered in a new technet article and you can read all about it here: &lt;SPAN lang=EN-IN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-IN; mso-fareast-language: EN-GB; mso-bidi-language: AR-SA"&gt;&lt;A href="http://technet.microsoft.com/en-us/library/cc263449.aspx#section14"&gt;&lt;FONT color=#0000ff&gt;http://technet.microsoft.com/en-us/library/cc263449.aspx#section14&lt;/FONT&gt;&lt;/A&gt;&lt;/SPAN&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;SPAN lang=EN-IN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-IN; mso-fareast-language: EN-GB; mso-bidi-language: AR-SA"&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4479427" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author><category term="sharepoint spn kerberos moss" scheme="http://blogs.msdn.com/james_world/archive/tags/sharepoint+spn+kerberos+moss/default.aspx" /></entry><entry><title>Passing variable numbers of parameters to sprocs using XML</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2007/02/12/passing-variable-numbers-of-parametes-to-sprocs-using-xml.aspx" /><id>http://blogs.msdn.com/james_world/archive/2007/02/12/passing-variable-numbers-of-parametes-to-sprocs-using-xml.aspx</id><published>2007-02-12T12:28:00Z</published><updated>2007-02-12T12:28:00Z</updated><content type="html">&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;FONT size=3&gt;Passing a variable number of parameters to a stored procedure is a problem that’s been around and solved for a while – in fact there’s a good article on several approaches for passing parameters in a comma-delimited string here:&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;A href="http://www.sommarskog.se/arrays-in-sql.html" mce_href="http://www.sommarskog.se/arrays-in-sql.html"&gt;&lt;FONT size=3&gt;http://www.sommarskog.se/arrays-in-sql.html&lt;/FONT&gt;&lt;/A&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;FONT size=3&gt;Today I’d like to talk about an alternative approach&amp;nbsp;made possible in SQL Server 2005 – passing parameters with the XML data type.&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;FONT size=3&gt;Let’s imagine that we have a table of employees with an EmployeeID. We want to select some arbitrary subset of this table by passing in a list of the EmployeeIDs of the desired employees.&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;FONT size=3&gt;The XML we are going to pass will look something like this:&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;FONT size=3&gt;&amp;lt;employees&amp;gt;&amp;lt;employee id=”1” /&amp;gt;&amp;lt;employee id=”3” /&amp;gt;…..&amp;lt;/employees&amp;gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;FONT size=3&gt;This can be built up quite simply in .NET using an XmlTextWriter as the following code snippet shows:&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: teal; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;StringBuilder&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; xmlEmployeeListBuilder = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;StringBuilder&lt;/SPAN&gt;();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: teal; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;StringWriter&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; stringWriter = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;StringWriter&lt;/SPAN&gt;(xmlEmployeeListBuilder);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: teal; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;XmlTextWriter&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; xmlWriter = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;XmlTextWriter&lt;/SPAN&gt;(stringWriter);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;xmlWriter.WriteStartDocument();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;xmlWriter.WriteStartElement(&lt;SPAN style="COLOR: maroon"&gt;"employees"&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;… other code&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;// add an employee id to xml parameter string&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;// repeat this section as necessary&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;xmlWriter.WriteStartElement(&lt;SPAN style="COLOR: maroon"&gt;"employee"&lt;/SPAN&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;xmlWriter.WriteAttributeString(&lt;SPAN style="COLOR: maroon"&gt;"id"&lt;/SPAN&gt;, &amp;lt;variable containing id&amp;gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;xmlWriter.WriteEndElement();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;… other code&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;xmlWriter.WriteEndElement();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;xmlWriter.WriteEndDocument();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;xmlWriter.Close();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;string&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; xmlEmployeeList = xmlEmployeeListBuilder.ToString();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;FONT size=3&gt;Now let’s look at the stored procedure in full and then break it down:&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;SET&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;QUOTED_IDENTIFIER&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;ON&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;SET&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;ANSI_NULLS&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;ON&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;CREATE&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;PROCEDURE&lt;/SPAN&gt; SelectSpecificEmployees &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;@EmployeeList &lt;SPAN style="COLOR: blue"&gt;xml&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;AS&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;SET&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;NOCOUNT&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;ON&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;CREATE&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;TABLE&lt;/SPAN&gt; #EmployeeList&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;EmployeeId &lt;SPAN style="COLOR: blue"&gt;int&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;INSERT&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; #EmployeeList&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;SELECT&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; employee&lt;SPAN style="COLOR: gray"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;'.'&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;'int'&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;FROM&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; @EmployeeList&lt;SPAN style="COLOR: gray"&gt;.&lt;/SPAN&gt;nodes&lt;SPAN style="COLOR: gray"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;'/employees/employee/@id'&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;)&lt;/SPAN&gt; T&lt;SPAN style="COLOR: gray"&gt;(&lt;/SPAN&gt;employee&lt;SPAN style="COLOR: gray"&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;SELECT&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; Employees&lt;SPAN style="COLOR: gray"&gt;.&lt;/SPAN&gt;EmployeeId&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; FirstName&lt;SPAN style="COLOR: gray"&gt;,&lt;/SPAN&gt; LastName&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;FROM&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; Employees &lt;SPAN style="COLOR: gray"&gt;INNER&lt;/SPAN&gt; &lt;SPAN style="COLOR: gray"&gt;JOIN&lt;/SPAN&gt; #EmployeeList &lt;SPAN style="COLOR: blue"&gt;ON&lt;/SPAN&gt; Employees&lt;SPAN style="COLOR: gray"&gt;.&lt;/SPAN&gt;EmployeeId &lt;SPAN style="COLOR: gray"&gt;=&lt;/SPAN&gt; #EmployeeList&lt;SPAN style="COLOR: gray"&gt;.&lt;/SPAN&gt;EmployeeId&lt;SPAN style="COLOR: gray"&gt;;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;DROP&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;TABLE&lt;/SPAN&gt; #EmployeeList&lt;SPAN style="COLOR: gray"&gt;;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: gray; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-US; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;FONT size=3&gt;The first thing to note is the two SET statements outside the stored procedure declaration. These SET options are different than all other set options in that whenever a stored procedure executes, it uses the settings for QUOTED_IDENTIFIER and ANSI_NULLS that were in place &lt;I style="mso-bidi-font-style: normal"&gt;at the time the stored procedure was created!&lt;/I&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;FONT size=3&gt;Changing these settings inside a stored procedure has no effect and produces no errors, and neither does the setting at the database level have any effect on the stored procedure.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;FONT size=3&gt;If you don’t have these options set as shown, then when you try and run this stored procedure you’ll get an error like:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;FONT size=3&gt;“INSERT failed because the following SET options have incorrect settings: 'QUOTED_IDENTIFIER'. Verify that SET options are correct for use with indexed views and/or indexes on computed columns and/or query notifications and/or xml data type methods.”&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;FONT size=3&gt;You have been warned!&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;FONT size=3&gt;The next step is to create a temporary table to hold the employee ids parsed from the XML.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;FONT size=3&gt;Now we insert the employee ids into the temporary table. To do this, we use the nodes() method of an XML data type. This executes an XQuery expression that returns a nodeset against the xml instance and places the results into a table. The table is scoped to the SQL statement in which it is declared.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;FONT size=3&gt;In the example above, we declare a table called T with a column of employee, and insert the rows from table T into our temporary #EmployeeList table.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;FONT size=3&gt;That’s all the hard work done – now we just join our #EmployeeList to the actual Employees table and return the matching employees.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;o:p&gt;&lt;FONT size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"&gt;&lt;SPAN lang=EN-GB style="mso-bidi-font-family: Arial"&gt;&lt;FONT size=3&gt;Comparing this approach&amp;nbsp;to the amount of code required to deal with comma-delimited strings, I&amp;nbsp;think this is a neater, shorter solution to the problem. How about you?&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1658832" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author></entry><entry><title>Book Review: Essential Windows Workflow Foundation</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2006/12/06/book-review-essential-windows-workflow-foundation.aspx" /><id>http://blogs.msdn.com/james_world/archive/2006/12/06/book-review-essential-windows-workflow-foundation.aspx</id><published>2006-12-06T03:02:00Z</published><updated>2006-12-06T03:02:00Z</updated><content type="html">&lt;P&gt;I've been working with Windows Workflow Foundation for over a year - and was lucky enough to implement a project that ended up being the first world-wide enterprise system in production based on Windows Workflow.&lt;/P&gt;
&lt;P&gt;At the time, I struggled to understand the concepts behind workflow before documentation was publicly available. Even now that the RTM is out there, the SDK documentation remains a reference text that necessarily stops short of a full exploration of the concepts.&lt;/P&gt;
&lt;P&gt;Essential Windows Workflow Foundation by Dharma Shuka and Bob Schmidt carries on in the great tradition of texts like Don Box's Essential COM (the author of the&amp;nbsp;foreword)&amp;nbsp;and is simply a brilliantly concise discourse on the fundamentals of Windows Workflow. I am in awe of Dharma and Bob's ability to explain this technology which represents a paradigm shift in how we will architect our applications from here on out. The more I look, the more I see applications of the Windows Workflow Framework.&lt;/P&gt;
&lt;P&gt;Get this book. Read it. You will not regret it.&lt;/P&gt;
&lt;P&gt;Amazon.com:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.amazon.com/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838/sr=8-1/qid=1165363738/ref=pd_bbs_sr_1/105-2963730-3310866?ie=UTF8&amp;amp;s=books"&gt;http://www.amazon.com/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838/sr=8-1/qid=1165363738/ref=pd_bbs_sr_1/105-2963730-3310866?ie=UTF8&amp;amp;s=books&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Amazon.co.uk:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.amazon.co.uk/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838/sr=8-1/qid=1165363788/ref=pd_ka_1/202-2200016-7087067?ie=UTF8&amp;amp;s=books"&gt;http://www.amazon.co.uk/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838/sr=8-1/qid=1165363788/ref=pd_ka_1/202-2200016-7087067?ie=UTF8&amp;amp;s=books&lt;/A&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1216559" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author><category term="Workflow" scheme="http://blogs.msdn.com/james_world/archive/tags/Workflow/default.aspx" /></entry><entry><title>System.Transactions Article</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2006/11/08/system-transactions-article.aspx" /><id>http://blogs.msdn.com/james_world/archive/2006/11/08/system-transactions-article.aspx</id><published>2006-11-08T16:05:00Z</published><updated>2006-11-08T16:05:00Z</updated><content type="html">System.Transactions in .NET 2.0 provide a fantastic way to manage your transactions in .NET without having to resort to messy code that tracks and passes SqlTransaction objects around. Best of all is it supports lightweight transactions. So as long as your database does as well (SQL 2005 does, SQL 2000 doesn't) then you won't have to enlist the DTC.&amp;nbsp;There's a great article on this &lt;A class="" href="http://msdn.microsoft.com/msdnmag/issues/06/11/DataPoints/default.aspx" mce_href="http://msdn.microsoft.com/msdnmag/issues/06/11/DataPoints/default.aspx"&gt;here&lt;/A&gt;. &lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1034894" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author></entry><entry><title>Read the chapter on Generics from Essential C#</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2006/11/08/read-the-chapter-on-generics-from-essential-c.aspx" /><id>http://blogs.msdn.com/james_world/archive/2006/11/08/read-the-chapter-on-generics-from-essential-c.aspx</id><published>2006-11-08T15:43:00Z</published><updated>2006-11-08T15:43:00Z</updated><content type="html">Mark Michaelis is bringing out a new book called "Essential C#". There is a great chapter on generics which you can read &lt;A class="" href="http://download.microsoft.com/download/c/b/f/cbfbdf30-de37-45a7-a806-20a93f94b7b8/Michaelis_ch11.pdf" target=_blank mce_href="http://download.microsoft.com/download/c/b/f/cbfbdf30-de37-45a7-a806-20a93f94b7b8/Michaelis_ch11.pdf"&gt;here&lt;/A&gt;. Enjoy!&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1034654" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author></entry><entry><title>DataContractSerializer: A better XMLSerializer</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2006/09/27/773852.aspx" /><id>http://blogs.msdn.com/james_world/archive/2006/09/27/773852.aspx</id><published>2006-09-27T17:51:00Z</published><updated>2006-09-27T17:51:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial&gt;XMLSerializer provides a simple means of serializing and deserializing object graphs to and from XML. However, simplicity brings a price, and there are limitations that I have seen people come up against.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;The most common of these is that XMLSerializer&amp;nbsp;will only work on public properties and needs setters to be able to deserialized, and this can create awkward design decisions - such as exposing properties that you really don't want to just to enable serialization. The second common obstacle is that there are no hooks to detect when a class is being constructed during deserialization - this is sometimes necessary when special work needs to be done (or not done) during deserialization.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;It is possible to customize serialization by implementing IXmlSerializable - problematic (and undocumented) in .NET 1.1 but much improved in .NET 2.0. However this can create a lot of extra work and maintenance that is a real pain.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;With the arrival of Windows Communication Foundation in .NET FX 3.0, an alternative is available that you might consider. The DataContractSerializer (DCS - renamed from XmlFormatter in the betas) provides an Xml Serializer than can be used independantly of WCF.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;The key differences are:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face=Arial&gt;Hooks are providing for refining control of (de)serialization - particularly useful for handling versioning issues. By applying any of four special attributes to methods in the target class you can have them called either before or after (de)serialization.&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial&gt;The serializer is "opt-in" rather than "opt-out" - which makes (imho) for much cleaner code. In XmlSerializer you could use XmlIgnore to have the serializer ignore certain properties. With the DCS you explicitly mark what you want to serialize.&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial&gt;Finally, ANY field or property can be serialized - even if they are marked private.&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;Check out DataContractSerializer in the SDK!&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=773852" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author></entry><entry><title>Book Review: Inside Microsoft SQL Server 2005: T-SQL Querying</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2006/06/06/618505.aspx" /><id>http://blogs.msdn.com/james_world/archive/2006/06/06/618505.aspx</id><published>2006-06-06T03:52:00Z</published><updated>2006-06-06T03:52:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial&gt;This &lt;A href="http://www.amazon.co.uk/o/ASIN/0735623139/203-9886954-9743945?%5Fencoding=UTF8&amp;amp;coliid=&amp;amp;colid="&gt;book&lt;/A&gt; is destined to become a classic. Benefiting from the main author's close relationship with the product team, this text provides a distilled insight into the machinations of SQL Server that are hard to garner from elsewhere. Managing to be both a reference text and a step-by-step tutorial, this book will furnish you with all tools you need to effectively author and tune T-SQL to highest standards. I particularly commend the chapter detailing a tuning methodology. &lt;BR&gt;&lt;BR&gt;Having said all this, bewarned that this text is not for the novice or beginner. While it is excellently written, it is an advanced text pitched at those with plenty of prior T-SQL experience, and will require careful study. That being said, for those who put in the effort, the rewards will be plentiful. &lt;BR&gt;&lt;BR&gt;My only criticism is that a book on T-SQL this good didn't come sooner. A fanatastic work I will be returning to again and again.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;I've just picked up the companion sequel (no pun intended!) T-SQL Programming - looks to be just as compelling!&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=618505" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author></entry><entry><title>Common Table Expressions in SQL Server 2005 ROCK!!!</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2005/07/22/441736.aspx" /><id>http://blogs.msdn.com/james_world/archive/2005/07/22/441736.aspx</id><published>2005-07-22T13:56:00Z</published><updated>2005-07-22T13:56:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial&gt;I've been taking a look at a new feature in SQL Server 2005 called "Common Table Expressions" (hereafter CTEs). This is an extra-ordinally powerful extenstion to Transact SQL that removes the need for managing temporary tables in many common scenarios.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;In&amp;nbsp;this example code I will set up a typical Employee table that is self-referencing; each Employee has a manager also in the Employee table. I've tested this code on IDW-15 (June CTP) only, but its been in the builds for a while so should work on the April CTP with no problems.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;Here is the setup code:&lt;/FONT&gt;&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;TABLE bgColor=#dddddd border=1&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT face="Courier New"&gt;USE &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;master&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- Drop the database if it already exists&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;IF &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;EXISTS &lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;(&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;SELECT name &lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;FROM &lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;sys.databases &lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;WHERE name &lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;= N'CTE_Rank_Demo'&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;)&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;DROP DATABASE &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;CTE_Rank_Demo&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;CREATE DATABASE &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;CTE_Rank_Demo&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;USE &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;CTE_Rank_Demo&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=2&gt;&lt;FONT face="Courier New"&gt;-- =========================================&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;-- Create demo table and data&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;-- This is a bunch of employees, each&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;-- having a manager which is a fk back&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;-- to the table.&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;-- =========================================&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;CREATE TABLE &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;Employee&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;(&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;id &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;int IDENTITY CONSTRAINT &lt;/FONT&gt;&lt;FONT size=2&gt;PK_Employee_id &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;PRIMARY KEY CLUSTERED&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;,&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;name &lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;nvarchar(50),&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;mgr_id &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;int CONSTRAINT &lt;/FONT&gt;&lt;FONT size=2&gt;FK_Employee_mgr_id &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FOREIGN KEY REFERENCES &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;Employee(id),&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;country &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;varchar&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;(2),&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;age &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;int&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;,&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;sales &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;int&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;)&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- Create some sample data&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;INSERT &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt;('Steve', &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;NULL&lt;/FONT&gt;&lt;FONT size=2&gt;, 'UK', 50, 200)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;INSERT &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt;('James', 1, 'UK', 30, 500)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;INSERT &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt;('Neil', 1, 'US', 35, 600)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;INSERT &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt;('Blair', 2, 'AU', 41, 250)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;INSERT &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt;('Ken', 1, 'DE', 38, 100)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;INSERT &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt;('Paul', 3, 'FR', 36, 480)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;INSERT &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt;('Adrian', 3, 'FR', 32, 290)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;INSERT &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;FONT size=2&gt;('Ian', 4, 'UK', 27, 120)&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT face="Courier New"&gt;INSERT &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VALUES&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;('Matt', 7, 'DE', 34, 10)&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;
&lt;P&gt;&lt;FONT face=Arial color=#000000&gt;OK, now lets look at a simple CTE.&lt;/FONT&gt; &lt;/P&gt;
&lt;TABLE bgColor=#eeeeee border=1&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P&gt;&lt;/P&gt;&lt;FONT face=Arial color=#000000&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#008000 size=2&gt;-- 1. A really simple and not very useful&lt;BR&gt;-- CTE example to introduce the syntax&lt;BR&gt;-- The WITH clause introduces a CTE and&lt;BR&gt;-- we define an in-memory result table&lt;BR&gt;-- called T&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WITH &lt;/FONT&gt;&lt;FONT size=2&gt;T(id, sales) &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;AS&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;(&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;SELECT &lt;/FONT&gt;&lt;FONT size=2&gt;id, sales &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;Employee&lt;BR&gt;)&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- We can now join to the in-memory result table&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;SELECT&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;E.id, T.sales&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;Employee E &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INNER JOIN &lt;/FONT&gt;&lt;FONT size=2&gt;T &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ON &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;E.id = T.id&lt;BR&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;You get back a list of employees and their sales total.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;Big deal, we could have just done that in one simple query anyway. So lets look at something more interesting... recursive CTEs! Here is a sample that gets back a list of an employee and all employees that reports to him and all employees that report to them... etc. Basically the subtree of the orgtree rooted at a particular employee.&lt;/FONT&gt;&lt;/P&gt;
&lt;TABLE bgColor=#eeeeee border=1&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT face=Arial&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#008000 size=2&gt;-- 2. Use a common table expression&lt;BR&gt;-- with recursion to get Neil and&lt;BR&gt;-- all employees he is responsible for&lt;BR&gt;-- A recusive CTE is denoted by two queries&lt;BR&gt;-- joined by a UNION ALL operator and&lt;BR&gt;-- the second query references the CTE table&lt;BR&gt;-- itself.&lt;BR&gt;-- The WITH clause introduces a CTE and&lt;BR&gt;-- we define an in-memory result table&lt;BR&gt;-- called Manager&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WITH &lt;/FONT&gt;&lt;FONT size=2&gt;Manager(id, &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;name&lt;/FONT&gt;&lt;FONT size=2&gt;, mgr_id) &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;AS&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;(&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- Neil will be the first row in this table &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;SELECT&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;id, &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;name&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;, mgr_id&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WHERE &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;id=3&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- To use recusion we must say UNION ALL&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;UNION ALL&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- Now the following select table will recurse&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- At the first level of recursion it will find Neil's&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- direct reports and insert these into the&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- Manager table. Then it will be called again&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- on each of the the new rows added to the table to find&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- their direct reports and so on...&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;SELECT&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;Employee.id,&lt;BR&gt;Employee.name,&lt;BR&gt;Employee.mgr_id&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INNER JOIN &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Manager&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ON &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;Employee.mgr_id = Manager.id&lt;BR&gt;)&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- Now we can select out all the employees&lt;BR&gt;-- we found from the in-memory table&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;SELECT&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;*&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;FROM&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;Manager&lt;BR&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;Awesome! Now let's look at a really cool example... this query uses aggregates to return the total sales of each employee and all the employees below them...&lt;/FONT&gt;&lt;/P&gt;
&lt;TABLE bgColor=#eeeeee border=1&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT face=Arial&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#008000 size=2&gt;-- 3. Now lets use a recursive CTE to&lt;BR&gt;-- get the total sales of each&lt;BR&gt;-- employee and all their reports!!!&lt;BR&gt;-- This really shows the power of CTEs&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WITH &lt;/FONT&gt;&lt;FONT size=2&gt;Manager(id, &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;name&lt;/FONT&gt;&lt;FONT size=2&gt;, mgr_id, sales) &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;AS&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;(&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- Start by selecting *all* employees rather&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- than just one.&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;SELECT&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;id, &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;name&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;, mgr_id, sales&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;FROM&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;Employee&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;UNION ALL&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- This is almost the same as before,&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- but now we are recording the name&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- of the manager rather than the employee&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- name and copying that name as we&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- recurse so that each row is tied back to&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- the originating Employee in the first query&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- of the CTE.&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;SELECT&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Employee.id,&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;name &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;= Manager.name,&lt;BR&gt;Employee.mgr_id,&lt;BR&gt;Employee.sales&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;Employee &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;INNER JOIN &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Manager&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ON &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;Employee.mgr_id = Manager.id&lt;BR&gt;)&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;-- Now we can use an aggregate expression grouped&lt;BR&gt;-- by the manager name to find their total sales&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;SELECT&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;name&lt;/FONT&gt;&lt;FONT size=2&gt;, &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;SUM&lt;/FONT&gt;&lt;FONT size=2&gt;(sales) &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;as &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;total_sales&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;FROM&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;Manager&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;GROUP BY&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff size=2&gt;name&lt;BR&gt;ORDER BY&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;total_sales &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" color=#0000ff size=2&gt;DESC&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT face="Courier New"&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;I think you'll agree than CTEs are going to be very popular indeed!&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=441736" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author></entry><entry><title>Encrypting Data In SQL Server 2005</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2005/07/20/441033.aspx" /><id>http://blogs.msdn.com/james_world/archive/2005/07/20/441033.aspx</id><published>2005-07-20T20:03:00Z</published><updated>2005-07-20T20:03:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial&gt;I've been looking at the new encryption functionality in SQL Server 2005. Here's some sql that executes on IDW15 - June CTP&amp;nbsp;(most of it should work on IDW14 - April CTP apart from DecryptByKeyAutoCert I think...&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;This sample code sets up a database and a table that will contain some data (national insurance numbers)&amp;nbsp;we want to store encrypted. It shows how to set up a master key, certicate and encryption key and how to use these to insert and select data. It also demonstrates how to set up a view that takes away a lot of the pain.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;It does expose that in IDW15 at least you need to give CONTROL level permission to a certificate to make this work&amp;nbsp; - which I hope gets fixed in the next release... with CONTROL you can do anything to a certificate, including dropping and altering it and removing the private key!!! The last of these works even if the cert is used to decrypt keys in the database - which presents an untenable security problem. What we want is just to require REFERENCES level permission (I think).&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;Other than this little niggle, the functionality is awesome! I have been doing encryption/decryption in the middle tier: it's great to be able to move this to the database - particularly as this makes it much easier to create reports in report server that otherwise had to use a custom assembly to decrypt data.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial color=#000000&gt;Copy the below into management studio and walk through it.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;create database SecurityDemo&lt;BR&gt;go&lt;BR&gt;use SecurityDemo&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- Create a master key - this is used as the root of the encryption&lt;BR&gt;-- hierarchy: all keys and certs are encrypted with this&lt;BR&gt;-- it is scoped to the database&lt;BR&gt;create master key encryption by password = &lt;A href="mailto:'pass@word1'"&gt;'pass@word1'&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;-- Now we will create a simple table with a column that will store&lt;BR&gt;-- national security numbers in encrypted form&lt;/P&gt;
&lt;P&gt;create table people (&lt;BR&gt;&amp;nbsp;id int identity constraint pk_people_id primary key clustered,&lt;BR&gt;&amp;nbsp;firstname nvarchar(50),&lt;BR&gt;&amp;nbsp;lastname nvarchar(50),&lt;BR&gt;&amp;nbsp;encrypted_ninumber varbinary(128) )&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- Now lets create a certicate - we will use this to encrypt a key&lt;BR&gt;-- this will give a warning about an invalid start date, but&lt;BR&gt;-- we can ignore this since sql doesn't care about cert dates&lt;BR&gt;create certificate ni_cert with subject = 'NI Certificate'&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- Now create a symmetric key to encrypt/decrypt the data&lt;BR&gt;create symmetric key ni_key with algorithm = aes_256&lt;BR&gt;encryption by certificate ni_cert&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- Now we will create a procedure to insert and encrypt the data&lt;BR&gt;create procedure dbo.insert_people (&lt;BR&gt;&amp;nbsp;@firstname nvarchar(50),&lt;BR&gt;&amp;nbsp;@lastname nvarchar(50),&lt;BR&gt;&amp;nbsp;@ninumber nchar(9)&lt;BR&gt;) as&lt;/P&gt;
&lt;P&gt;-- open the symmetric key&lt;BR&gt;open symmetric key ni_key decryption by certificate ni_cert&lt;/P&gt;
&lt;P&gt;-- insert and encrypt the data&lt;BR&gt;insert people(firstname, lastname, encrypted_ninumber)&lt;BR&gt;&amp;nbsp;values(&lt;BR&gt;&amp;nbsp;&amp;nbsp;@firstname,&lt;BR&gt;&amp;nbsp;&amp;nbsp;@lastname,&lt;BR&gt;&amp;nbsp;&amp;nbsp;EncryptByKey(Key_GUID('ni_key'), @ninumber)&lt;BR&gt;)&lt;/P&gt;
&lt;P&gt;-- close the key now&lt;BR&gt;close symmetric key ni_key&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- now lets insert some data&lt;BR&gt;insert_people 'James', 'World', 'JZ123488B'&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- looking at this data, you can see its nice and encrypted&lt;BR&gt;select * from people&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- ok, so lets create a procedure to decrypt this&lt;BR&gt;create procedure dbo.select_person (&lt;BR&gt;&amp;nbsp;@id int&lt;BR&gt;) as&lt;/P&gt;
&lt;P&gt;open symmetric key ni_key decryption by certificate ni_cert&lt;/P&gt;
&lt;P&gt;select&lt;BR&gt;&amp;nbsp;id,&lt;BR&gt;&amp;nbsp;firstname,&lt;BR&gt;&amp;nbsp;lastname,&lt;BR&gt;&amp;nbsp;convert(nchar(9),DecryptByKey(encrypted_ninumber)) as ninumber&lt;BR&gt;from&lt;BR&gt;&amp;nbsp;people&lt;/P&gt;
&lt;P&gt;close symmetric key ni_key&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- and try it out&lt;BR&gt;exec select_person 1&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- how about if we want another use to call this spoc?&lt;BR&gt;create login bob with password = &lt;A href="mailto:'pass@word1'"&gt;'pass@word1'&lt;/A&gt;&lt;BR&gt;go&lt;BR&gt;create user bob for login bob&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- this won't work as bob has no permissions&lt;BR&gt;execute as user='bob' -- lets us run in the context of bob&lt;BR&gt;exec select_person 1&lt;BR&gt;revert -- puts us back to our dbo context&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- let's give him some and then the above should work&lt;BR&gt;grant execute on dbo.select_person to bob&lt;BR&gt;grant references on symmetric key::ni_key to bob&lt;BR&gt;-- eek!!! currently need to grant *control* permission to bob&lt;BR&gt;-- in IDW15... hope this improves!&lt;BR&gt;grant control on certificate::ni_cert to bob&lt;/P&gt;
&lt;P&gt;-- now it works&lt;BR&gt;execute as user='bob' -- lets us run in the context of bob&lt;BR&gt;exec select_person 1&lt;BR&gt;revert -- puts us back to our dbo context&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- lets take away bob's permissions&lt;BR&gt;revoke execute on dbo.select_person to bob&lt;BR&gt;revoke references on symmetric key::ni_key to bob&lt;BR&gt;revoke control on certificate::ni_cert to bob&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- a new feature lets us create a view that automatically decrypts&lt;BR&gt;-- the data&lt;BR&gt;create view view_people as&lt;BR&gt;&amp;nbsp;select&lt;BR&gt;&amp;nbsp;&amp;nbsp;id,&lt;BR&gt;&amp;nbsp;&amp;nbsp;firstname,&lt;BR&gt;&amp;nbsp;&amp;nbsp;lastname,&lt;BR&gt;&amp;nbsp;&amp;nbsp;convert(&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;nchar(9),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;DecryptByKeyAutoCert(cert_id('ni_cert'),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;null, encrypted_ninumber)&lt;BR&gt;&amp;nbsp;&amp;nbsp;) AS ninumber&lt;BR&gt;&amp;nbsp;from&lt;BR&gt;&amp;nbsp;&amp;nbsp;people&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;select * from view_people&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- can bob look at this view? clearly he needs permission on the view&lt;BR&gt;grant select on view_people to bob&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- lets try...&lt;BR&gt;execute as user='bob'&lt;BR&gt;select * from view_people&lt;BR&gt;revert&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- hmmm! we got null - this is what anyone gets that doesn't&lt;BR&gt;-- have an open key when they try to read encrypted data&lt;BR&gt;-- lets grant him permissions - control of the cert and references&amp;nbsp;on the key&lt;BR&gt;grant control on certificate::ni_cert to bob&lt;BR&gt;grant references on symmetric key::ni_key to bob&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- lets try again&lt;BR&gt;execute as user='bob'&lt;BR&gt;select * from view_people&lt;BR&gt;revert&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- this works! and best of all we didn't have to manage&lt;BR&gt;-- opening the key&lt;BR&gt;-- if they fix the level of permissions required on the cert&lt;BR&gt;-- then this will be an awesome way to manage encrypted data&lt;/P&gt;
&lt;P&gt;-- current weakness of needing CONTROL permission for bob on the cert:&lt;/P&gt;
&lt;P&gt;-- we can do this and remove the ability to decrypt our data!&lt;BR&gt;execute as user='bob'&lt;BR&gt;alter certificate ni_cert remove private key&lt;BR&gt;revert&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- certs can be backed up and restored, but this still sucks&lt;/P&gt;
&lt;P&gt;-- other than that, this is an awesome feature set!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=441033" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author></entry><entry><title>New InternalsVisibleTo attribute in .NET 2.0</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/james_world/archive/2005/07/07/436574.aspx" /><id>http://blogs.msdn.com/james_world/archive/2005/07/07/436574.aspx</id><published>2005-07-07T22:42:00Z</published><updated>2005-07-07T22:42:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial&gt;I discovered a cool new attribute in .NET 2.0 called "InternalsVisibleTo". This takes an assembly name and public key token and grants it access to the assembly internals.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;One cool application I can think of is that you no longer have to place your unit tests inside the assembly they are testing; instead you can aggregate them into an external assembly and keep the production binaries as small as possible. Of course you can always wrap the tests with compiler directives, but I think that the former approach would be quite useful in many instances.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;Check System.Deployment.dll to see an example of this:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN lang=EN-US style="FONT-SIZE: 8.5pt"&gt;[&lt;FONT color=#1000a0&gt;&lt;SPAN style="COLOR: #1000a0"&gt;assembly:&lt;/SPAN&gt;&lt;/FONT&gt; &lt;A title="http://www.aisto.com/roeder/dotnet/Default.aspx?Object=5&amp;#10;System.Runtime.CompilerServices.InternalsVisibleToAttribute.InternalsVisibleToAttribute(string);" href="http://www.aisto.com/roeder/dotnet/Default.aspx?Object=5"&gt;InternalsVisibleTo&lt;/A&gt;(&lt;FONT color=maroon&gt;&lt;SPAN style="COLOR: maroon"&gt;"dfsvc, PublicKeyToken=b03f5f7f11d50a3a"&lt;/SPAN&gt;&lt;/FONT&gt;)]&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=436574" width="1" height="1"&gt;</content><author><name>James World</name><uri>http://blogs.msdn.com/members/James+World.aspx</uri></author></entry></feed>