<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7354546</id><updated>2011-12-31T13:21:34.407+05:30</updated><title type='text'>TOP 1 WITH TIES</title><subtitle type='html'>Roji's SQL BLOG</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>47</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7354546.post-7736539821941162210</id><published>2007-04-13T17:36:00.000+05:30</published><updated>2007-04-13T17:39:40.172+05:30</updated><title type='text'>Ten Ways To Lose Your DBA Job</title><content type='html'>Its always good to know how you can find your way out. &lt;a href="http://www.sqlservercentral.com/columnists/sjones/"&gt;Steve Jones&lt;/a&gt; has this interesting &lt;a href="http://www.sqlservercentral.com/columnists/sjones/2744.asp"&gt;article&lt;/a&gt; in &lt;a href="http://www.sqlservercentral.com/"&gt;SQLServerCentral.com&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-7736539821941162210?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/7736539821941162210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=7736539821941162210&amp;isPopup=true' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/7736539821941162210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/7736539821941162210'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2007/04/ten-ways-to-lose-your-dba-job.html' title='Ten Ways To Lose Your DBA Job'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-1546067636351306718</id><published>2007-04-02T23:01:00.000+05:30</published><updated>2007-04-02T23:08:20.917+05:30</updated><title type='text'>Two Minute SQL Server Stumpers Vol. 3</title><content type='html'>Third volume of Two Minute SQL Server Stumpers from &lt;a href="http://www.SQLServerCentral.com/"&gt;SQLServerCentral&lt;/a&gt; is available for download from &lt;a href="https://www.red-gate.com/Dynamic/Downloads/DownloadForm.aspx?download=ebook2&amp;utm_source=ssp&amp;amp;utm_medium=email&amp;amp;utm_campaign=sqlserverstumpers"&gt;here&lt;/a&gt;. Thanks to &lt;a href="https://www.red-gate.com/"&gt;RedGate&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-1546067636351306718?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/1546067636351306718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=1546067636351306718&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/1546067636351306718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/1546067636351306718'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2007/04/two-minute-sql-server-stumpers-vol-3.html' title='Two Minute SQL Server Stumpers Vol. 3'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-117060986322070761</id><published>2007-02-04T22:53:00.000+05:30</published><updated>2007-02-04T22:54:25.070+05:30</updated><title type='text'>How you can help in the search for Jim Gray</title><content type='html'>&lt;a href="http://blogs.msdn.com/dtjones/archive/2007/02/03/how-you-can-help-in-the-search-for-jim-gray.aspx"&gt;http://blogs.msdn.com/dtjones/archive/2007/02/03/how-you-can-help-in-the-search-for-jim-gray.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-117060986322070761?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/117060986322070761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=117060986322070761&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/117060986322070761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/117060986322070761'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2007/02/how-you-can-help-in-search-for-jim.html' title='How you can help in the search for Jim Gray'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-116427023070772020</id><published>2006-11-23T13:52:00.000+05:30</published><updated>2006-11-23T15:12:02.356+05:30</updated><title type='text'>Which database is more secure? Oracle vs. Microsoft</title><content type='html'>Today, SQL Server MVP &lt;a href="http://insidesql.de/"&gt;Frank Kalis&lt;/a&gt; pointed to this interesting comparison by &lt;a href="http://www.ngssoftware.com/"&gt;NGSSoftware &lt;/a&gt;. As per the study, the reported number of security flaws in Microsoft SQL server is near to zero for the period 0f 2005-2006, whereas the Oracle figures are going higher.&lt;br /&gt;&lt;br /&gt;Here is the link.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;a href="http://www.databasesecurity.com/dbsec/comparison.pdf"&gt;Which database is more secure?Oracle vs. Microsoft&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Update: There is another study emphasizing the fact at the &lt;a href="http://www.enterprisestrategygroup.com/Default.asp?PAName=information"&gt;Enterprize Strategy Group&lt;/a&gt;  website.&lt;br /&gt;Also see this &lt;a href="http://download.microsoft.com/download/d/0/e/d0ee6c0a-ffa8-4fa2-9397-0e237d46d728/SQL2005andOracle10gSecurity.doc"&gt;comparison&lt;/a&gt; from Microsoft.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-116427023070772020?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/116427023070772020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=116427023070772020&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/116427023070772020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/116427023070772020'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2006/11/which-database-is-more-secure-oracle.html' title='Which database is more secure? Oracle vs. Microsoft'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-116301050865613884</id><published>2006-11-08T23:57:00.000+05:30</published><updated>2006-11-08T23:58:29.710+05:30</updated><title type='text'>SQL Server 2005 November CTP</title><content type='html'>SQL Server 2005 November CTP is available for download at&lt;br /&gt;&lt;span style="font-family:Verdana, Arial, Helvetica;font-size:85%;color:midnightblue;"&gt;&lt;span class="spnMessageText" id="msg"&gt;&lt;a href="http://www.microsoft.com/sql/ctp.mspx#E2" target="_blank"&gt;http://www.microsoft.com/sql/ctp.mspx#E2&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-116301050865613884?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/116301050865613884/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=116301050865613884&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/116301050865613884'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/116301050865613884'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2006/11/sql-server-2005-november-ctp.html' title='SQL Server 2005 November CTP'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-115468322575551181</id><published>2006-08-04T14:50:00.000+05:30</published><updated>2006-08-04T16:57:21.166+05:30</updated><title type='text'>T-SQL Drawing</title><content type='html'>Here is a humble attempt to draw a landscape using T-SQL ! &lt;br&gt;&lt;br&gt;NOTE: Before running this query, you should set the dispaly mode to text and Results font to a fixed width Font (Mine is Courier new)  in Query Analyzer&lt;br&gt;&lt;br&gt;SET NOCOUNT ON &lt;br&gt;&lt;br&gt;DECLARE @ TABLE(id int IDENTITY(1,1), pic CHAR(120))&lt;br&gt;&lt;br&gt;INSERT INTO @ &lt;br&gt;SELECT REPLICATE(CHAR(126),120) &lt;br&gt;FROM (SELECT 1 AS N UNION ALL SELECT 2)  A, &lt;br&gt;(SELECT 1 AS N UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) B, &lt;br&gt;(SELECT 1 AS N UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) C&lt;br&gt;&lt;br&gt;--Tree 1&lt;br&gt;UPDATE @&lt;br&gt;SET pic = STUFF(pic, (50 - (-3+ id)) , ((-3+ id) * 2), REPLICATE(CHAR(47),(-3+ id))+  REPLICATE(CHAR(92),(-3+ id)))&lt;br&gt;WHERE id BETWEEN 4 AND 26&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic,49, 2, CHAR(43)+CHAR(43))&lt;br&gt;WHERE id &gt;=6&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic,48, 4, REPLICATE(CHAR(124),4))&lt;br&gt;WHERE id &gt;=26&lt;br&gt;&lt;br&gt;--Tree 2&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 100 - ((id - 6)*3), 6 + (((id -6) * 6)), REPLICATE(CHAR(37),  6 + (((id -6) * 6))))&lt;br&gt;WHERE ID BETWEEN 6 AND 10&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 89 + ((id -11)*2), 28 - ((id -11)*4), REPLICATE(CHAR(37),  28 - ((id-11)*4)))&lt;br&gt;WHERE ID BETWEEN 11 AND 14&lt;br&gt;&lt;br&gt;UPDATE @ SET Pic = STUFF(Pic, 102,2,CHAR(64)+CHAR(64))&lt;br&gt;WHERE Id &gt;= 14 AND ID &lt;= 25&lt;br&gt;&lt;br&gt;--Add a branch&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 90,12,REPLICATE(CHAR(61),12))&lt;br&gt;WHERE Id = 19&lt;br&gt;&lt;br&gt;UPDATE @  &lt;br&gt;SET Pic = STUFF(Pic, CASE WHEN  id % 2 = 0 THEN 88 ELSE 87 END, 3, REPLICATE(CHAR(37), 3))&lt;br&gt;WHERE ID IN(18,19,20)&lt;br&gt;&lt;br&gt;--Add a Bird too :)&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 94, 3 , CONVERT(VARCHAR, 0x2F5E5C))&lt;br&gt;WHERE ID = 20&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 94, 3 , CHAR(43) +  CHAR(32) + CHAR(43))&lt;br&gt;WHERE ID = 19&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 91, 9 , CONVERT(VARCHAR, 0x205C5C2022202F2F20))&lt;br&gt;WHERE ID = 18&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 91, 9 , CONVERT(VARCHAR, 0x205F7B2A762A7D5F20))&lt;br&gt;WHERE ID = 17&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 92, 7 , CONVERT(VARCHAR, 0x2020205F202020))&lt;br&gt;WHERE ID = 16&lt;br&gt;&lt;br&gt;--Add a house in the hills&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 66, 12 , CONVERT(VARCHAR, 0x7C5F5F5F5F5F5F7C5F7C5F7C))WHERE ID = 11&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 66, 12 , CONVERT(VARCHAR, 0x7C5B5D205B5D207C207C207C))&lt;br&gt;WHERE ID = 10&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 66, 12 , CONVERT(VARCHAR, 0x2F2F2F2F2F2F2F2F5F5F5F5C))&lt;br&gt;WHERE ID = 9&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 67, 11 , CONVERT(VARCHAR, 0x2F2F2F2F2F2F2F2F635C))&lt;br&gt;WHERE ID = 8&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 68, 8 , CONVERT(VARCHAR, 0x5F5F5F5F5F5F5F50))&lt;br&gt;WHERE ID = 7&lt;br&gt;&lt;br&gt;--Add fruits to the first tree in random locations.&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, ((50 - (id - 4))+ (CAST(RAND() * (id -4)  AS INT))), 2, CHAR(123) + CHAR(125))&lt;br&gt;WHERE id BETWEEN 10 AND 26&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 50 +  CAST(RAND() * (id -4)  AS INT), 2, CHAR(123) + CHAR(125))&lt;br&gt;WHERE id BETWEEN 10 AND 26&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, ((50 - (id - 4))+ (CAST(RAND() * (id -4)  AS INT))), 2, CHAR(123) + CHAR(125))&lt;br&gt;WHERE id BETWEEN 10 AND 26&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 50 +  CAST(RAND() * (id -4)  AS INT), 2, CHAR(123) + CHAR(125))&lt;br&gt;WHERE id BETWEEN 10 AND 26&lt;br&gt;&lt;br&gt;--Sun&lt;br&gt;UPDATE @  &lt;br&gt;SET pic = STUFF(Pic,10,6, REPLICATE(CHAR(32),6))&lt;br&gt;WHERE id IN(2,5)&lt;br&gt;&lt;br&gt;UPDATE @  SET pic = STUFF(Pic,9,8, REPLICATE(CHAR(32),8))&lt;br&gt;WHERE id IN(3,4)&lt;br&gt;&lt;br&gt;--Add the superCool SQL Guy&lt;br&gt;UPDATE @ SET Pic = STUFF(Pic, 10,7, CONVERT(VARCHAR, 0x285F5F5B5F5F29))&lt;br&gt;WHERE ID = 28&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 12,5, CONVERT(VARCHAR, 0x5F2F5F5F2F))&lt;br&gt;WHERE ID = 27&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 12,6, CONVERT(VARCHAR, 0x207C2F20202F))&lt;br&gt;WHERE ID = 26&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 12,6, CONVERT(VARCHAR, 0x207C5C20205C))&lt;br&gt;WHERE ID = 25&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 12,6, CONVERT(VARCHAR, 0x5F5F5F285F2F))&lt;br&gt;WHERE ID = 24&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 16,3, CONVERT(VARCHAR, 0x2F5F2F))&lt;br&gt;WHERE ID = 23&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 16,3, CONVERT(VARCHAR, 0x5C205C))&lt;br&gt;WHERE ID = 22&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 10,8, CONVERT(VARCHAR, 0x2F20205C2F20205C))&lt;br&gt;WHERE ID = 21&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 11,6, CONVERT(VARCHAR, 0x5F5C206F2F5F))&lt;br&gt;WHERE ID = 20&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 11,6, CONVERT(VARCHAR, 0x5C287E6F6F20))&lt;br&gt;WHERE ID = 19&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 11,6, CONVERT(VARCHAR, 0x2F20205F5F29))&lt;br&gt;WHERE ID = 18&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 12,4, REPLICATE(CHAR(95),4))&lt;br&gt;WHERE ID = 17&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 9,3,CONVERT(VARCHAR, 0x2F202F))&lt;br&gt;WHERE ID = 22&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 9+ (id -23),2, CONVERT(VARCHAR, 0x5C20))&lt;br&gt;WHERE ID IN(23,24)&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 11,1, CHAR(124))&lt;br&gt;WHERE ID BETWEEN 23 AND 27&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 12,4, CASE WHEN id % 2 = 1 THEN CONVERT(VARCHAR, 0x20475559) ELSE CONVERT(VARCHAR, 0x2053514C) END)&lt;br&gt;WHERE ID IN(22,23)&lt;br&gt;&lt;br&gt;--Some Bush&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = REPLICATE(CHAR(92)+CHAR(124)+ CHAR(47),40)&lt;br&gt;WHERE id = 31&lt;br&gt;&lt;br&gt;--River (for Veer :)&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(pic, (78 + ((31 - id)*5)), (40 -((31 - id)*5)+2),    LEFT(CHAR(63) + REPLICATE(CONVERT(VARCHAR, 0x2D205F207E5E7E2D205F7E207E20),4), (40 -((31 - id)*5)+2) ))&lt;br&gt;WHERE ID BETWEEN 23 AND 31&lt;br&gt;&lt;br&gt;--And a couple of Fish too&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic,CASE WHEN ID &lt; 30 THEN 108 ELSE 95 END , 7, CONVERT(VARCHAR, 0x3E3C2828282A3E))&lt;br&gt;WHERE ID IN(27,30)&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic,105 , 5, CONVERT(VARCHAR, 0x3C275F3E3C))&lt;br&gt;WHERE ID IN(28,31)&lt;br&gt;&lt;br&gt;--Border&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = REPLICATE(CHAR(95),120)&lt;br&gt;WHERE ID IN(1,32)&lt;br&gt;&lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(STUFF(Pic,1,1,CHAR(124)),120,1,CHAR(124))&lt;br&gt;WHERE id &gt; 1&lt;br&gt;&lt;br&gt;--Signature &lt;br&gt;UPDATE @ &lt;br&gt;SET Pic = STUFF(Pic, 112,6, CONVERT(VARCHAR,0x526F6A697074))&lt;br&gt;WHERE ID = 31&lt;br&gt;&lt;br&gt;SELECT Pic [ ] FROM @ ORDER By Id&lt;br&gt; &lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-115468322575551181?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/115468322575551181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=115468322575551181&amp;isPopup=true' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/115468322575551181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/115468322575551181'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2006/08/t-sql-drawing.html' title='T-SQL Drawing'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-114475086234001142</id><published>2006-04-11T15:47:00.000+05:30</published><updated>2006-04-11T15:51:02.690+05:30</updated><title type='text'>The future of SQL Server</title><content type='html'>Paul Flessner, Senior VP of Server Applications at Microsoft,  shares his vision about the future of SQL Server in his latest letter &lt;a href="http://www.microsoft.com/sql/letter.mspx"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-114475086234001142?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/114475086234001142/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=114475086234001142&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/114475086234001142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/114475086234001142'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2006/04/future-of-sql-server.html' title='The future of SQL Server'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-114432224332426661</id><published>2006-04-06T16:47:00.000+05:30</published><updated>2006-04-06T16:56:06.136+05:30</updated><title type='text'>How do you get current Job Name?</title><content type='html'>Today a colleague asked me this question.&lt;br /&gt;How do you get current Job Name from a job step?&lt;br /&gt;&lt;br /&gt;Well, I did'nt know the answer :(&lt;br /&gt;&lt;br /&gt;It should be simple. If we want to know the current procedure name from inside the procedure, we can use something like OBJECT_NAME(@@PROCID)&lt;br /&gt;Do we have something like @@JOBID? Well, NO.&lt;br /&gt;&lt;br /&gt;I turned to google and learned about SQL Agent Tokens. That was news to me.&lt;br /&gt;&lt;br /&gt;So SQL Agent Tokens are placeholders that are automatically replaced by the subsystem during runtime.&lt;br /&gt;In SQL Server 2000, you can refer to an SQL Agent token like [TOKENNAME]. Token names are case sensitive.&lt;br /&gt;&lt;br /&gt;Here is an example.&lt;br /&gt;&lt;br /&gt;SELECT output_file_name&lt;br /&gt;FROM msdb..sysjobsteps&lt;br /&gt;WHERE job_id = [JOBID]&lt;br /&gt;AND step_id = [STEPID]&lt;br /&gt;&lt;br /&gt;SQL Server Agent in SQL Server 2005 has changed the syntax used in tokens from "[X]" to "$(X)" where X is the token name&lt;br /&gt;&lt;br /&gt;Here are some relevant links.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/technet/prodtechnol/sql/2005/newsqlagent.mspx"&gt;http://www.microsoft.com/technet/prodtechnol/sql/2005/newsqlagent.mspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://sqldev.net/sqlagent/SQLAgentStepTokens.htm"&gt;http://sqldev.net/sqlagent/SQLAgentStepTokens.htm&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-114432224332426661?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/114432224332426661/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=114432224332426661&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/114432224332426661'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/114432224332426661'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2006/04/how-do-you-get-current-job-name.html' title='How do you get current Job Name?'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-114371041489865902</id><published>2006-03-30T14:50:00.000+05:30</published><updated>2006-03-30T14:51:11.353+05:30</updated><title type='text'>Responsibilities of a Development DBA</title><content type='html'>Recently, I was asked to define the responsibilities of a Development DBA.&lt;br /&gt;&lt;br /&gt;The following is the list of items that came to my mind. Feel free to add items you feel appropriate in the comments section.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Database design and implementation&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Design and implement the database. Normalize and denormalize the database as necessary. This includes the creation of tables, views , common functions and procedures&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. Design, Implement and monitor back end jobs&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Define standard notification for all back end jobs. Take corrective action when a job fails. Schedule the job to execute on non-peek hours. Verify job level and step level status on a daily basis.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. Do database tuning and performance monitoring&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Monitor the performance of individual programs and based on the performance results tune/reorganize the tables and indexes.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. Optimize badly performing queries and procedures&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Optimize badly performing programs by modifying/rewriting the programs in statement level.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;5. Do application tuning and performance monitoring&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Assess the performance of the applications and the load and impact on the database caused by applications. Provide suggestions to concerned developers where database access mechanisms can be optimized.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;6. Perform troubleshooting on DB related issues&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Help developers to troubleshoot database related issues. Provide trace files containing database access details for a specific database/program/time interval to the developers when required.&lt;br /&gt;&lt;br /&gt;Make the developers aware about the known issues/bugs in the software and the limitations of the version/service pack in use.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;7. Participate in design and architecture of new CRs. &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Participate/review the design and architecture of the CRs to ensure that the design/architecture is developed with scalability and performance considerations.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;8. Code Review&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Review procedures/functions. Evaluate compliance with the defined standards and best practices. Use available tools best practices compliance.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;9. Training&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Conduct training on database related topics. Introduce new versions of SQL server. Distribute study materials. Assist the developers to start working with the new version.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;10. Extend support to developers for writing complex programs&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Help the developers write complex queries in an optimized manner. Share common patterns/tips and tricks used in the industry to solve similar problems.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;11. Setup and maintain standards and best practices.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Define and enforce organization wide standards and best practices. Update the standards and practices based on the feedback and review experience.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;12. Recommend Architectural changes.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Recommend changes to the current design/architecture which can give a database wide performance boost.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;13. Monitor database activities&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Monitor the activities on the servers and take corrective action when required. Look for issues like connection creeping, blocks, deadlocks, slow response etc..&lt;br /&gt;&lt;br /&gt;&lt;b&gt;14. Perform database health checking&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Perform regular health checking activities on the database to ensure integrity, stability and robustness of the database. Check fragmentation levels and statistics concurrency. Perform re-indexing and update statistics when required.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;15. Establish and maintain backup policies&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Verify the backup process and occasionally test the backup. This includes the database backup and script backup.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;16. Define and Enforce security policies&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Define the minimum security credentials each role/user requires and enforce the defined security policy.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;17. Capacity Planning&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Monitor the space allocation and free space on the development and QA environments. Shrink the database files on a regular basis to recover free space. Configure/Recommend auto grow settings for each database based on its growth rate.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;18. Disaster Recovery Planning.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Document and test a DRP plan for the development and QA environments. This should be in sync with the DR plan for the production environment.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;19. Installation and configuration of SQL Server Databases.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Setup SQL server environments for development, QA and performance testing. Configure the servers and databases based on the requirement.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;20. Evaluate, test and apply service packs&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Test the service packs released for SQL server before applying them in a production environment to make sure they don't break the existing programs and the service pack is bug free.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;21. Evaluate, test and upgrade to new versions&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Evaluate the new versions of SQL server. Perform performance/scalability/availability/programmability comparisons with the existing version. Use the new versions to run in-house projects for a comfortable time period and recommend for upgrading to the new version if the results are positive.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;22. Evaluate, test and recommend third party components.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Evaluate the components available in market that can boost the performance, secure the server, ensure high availability, prevent data loss, perform fast backups etc.., and if essential, recommend using them.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;23. Coordinating and interfacing with developers, support persons, outside vendors, end users, other department team members, and service providers to resolve issues.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Interact with other departments and teams to resolve DB related issues. If required get assistance from the product support team.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-114371041489865902?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/114371041489865902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=114371041489865902&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/114371041489865902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/114371041489865902'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2006/03/responsibilities-of-development-dba_30.html' title='Responsibilities of a Development DBA'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-114085384433386007</id><published>2006-02-25T13:20:00.000+05:30</published><updated>2006-02-25T13:34:01.176+05:30</updated><title type='text'>BUG: Combination of GROUP BY with HAVING Clause and LEFT OUTER JOIN with Derived Table With LEFT Function Produces Incorrect Result</title><content type='html'>&lt;br /&gt;&lt;u&gt;Applies To :&lt;/u&gt;  SQL Server 2000 RTM to SP4&lt;br /&gt;&lt;br /&gt;This bug is a variant of KB &lt;a href="http://support.microsoft.com/default.aspx/kb/308458/en-us" title="FIX: Combination of GROUP BY with HAVINGClause and LEFT OUTER JOIN with Derived Table Produces Incorrect Result""&gt;308458&lt;/a&gt; which is fixed in SP2.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Symptoms&lt;/u&gt;&lt;br /&gt;&lt;br /&gt;If all of the following conditions are true for a query, the query will return extra rows.&lt;br /&gt;&lt;br /&gt;&amp;bull; You include GROUP BY and HAVING clauses.&lt;br /&gt;&amp;bull; You use a LEFT OUTER JOIN.&lt;br /&gt;&amp;bull; You incorporate derived tables.&lt;br /&gt;&amp;bull; You use an aggregate. &lt;br /&gt;&amp;bull; You use the LEFT function.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Cause&lt;/u&gt;&lt;br /&gt;The optimizer inappropriately processes a cross join. &lt;br /&gt; &lt;br /&gt;&lt;u&gt;Steps to Reproduce&lt;/u&gt;&lt;br /&gt;&lt;br /&gt;Execute the following query in Query Analyzer&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;Use Pubs&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;SELECT T.pub_id, T.type, SUM(T.price) AS BasePrice&lt;br /&gt;FROM Titles T&lt;br /&gt;LEFT JOIN&lt;br /&gt;(Select 1) X (pub_id)&lt;br /&gt;ON X.pub_id = T.pub_id&lt;br /&gt;WHERE  LEFT(T.title,3) = 'The'&lt;br /&gt;GROUP BY T.pub_id, T.type&lt;br /&gt;--HAVING  SUM(T.price) &gt; 0&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;You will get the following results&lt;br /&gt;&lt;br /&gt;&lt;Table bgColor="#CCCCCC"  border = 1&gt;&lt;br /&gt;&lt;font color="#400040"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;pub_id&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;type&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;BasePrice&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/font&gt;&lt;font color="#000040"&gt;&lt;tr&gt;&lt;td&gt;1389&lt;/td&gt;&lt;td&gt;business&lt;/td&gt;&lt;td&gt;19.9900&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;0877&lt;/td&gt;&lt;td&gt;mod_cook &lt;/td&gt;&lt;td&gt;2.9900&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;0877&lt;/td&gt;&lt;td&gt;UNDECIDED&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/font&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Now try executing the above query by uncommenting the the HAVING caluse to exclude the NULL value.&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;Use Pubs&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;SELECT T.pub_id, T.type, SUM(T.price) AS BasePrice&lt;br /&gt;FROM Titles T&lt;br /&gt;LEFT JOIN&lt;br /&gt;(Select 1) X (pub_id)&lt;br /&gt;ON X.pub_id = T.pub_id&lt;br /&gt;WHERE  LEFT(T.title,3) = 'The'&lt;br /&gt;GROUP BY T.pub_id, T.type&lt;br /&gt;HAVING  SUM(T.price) &gt; 0&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;you will get the following incorrect result. &lt;br /&gt;&lt;table bgColor="#CCCCCC" border=1  font color="#400040"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;pub_id&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;type&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;BasePrice&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#000040"&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;1389&lt;/td&gt;&lt;td&gt;business&lt;/td&gt;&lt;td&gt;19.9900&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;0877&lt;/td&gt;&lt;td&gt;mod_cook&lt;/td&gt;&lt;td&gt;19.9900&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;1389&lt;/td&gt;&lt;td&gt;business&lt;/td&gt;&lt;td&gt;2.9900&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;0877&lt;/td&gt;&lt;td&gt;mod_cook&lt;/td&gt;&lt;td&gt;2.9900&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;1389&lt;/td&gt;&lt;td&gt;business&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;0877&lt;/td&gt;&lt;td&gt;mod_cook&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;/font&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;If you look at the execution plan, you can see that the query performs an  incorrect cross join.&lt;br /&gt;&lt;br /&gt;&lt;font color="#0000A0"&gt; |--Nested Loops(Inner Join)&lt;br /&gt; ..... |--Compute Scalar(DEFINE:([Expr1005]=If ([Expr1018]=0) then NULL else [Expr1019]))&lt;br /&gt; ..... |....|--Stream Aggregate(GROUP BY:([T].[type], [T].[pub_id]) DEFINE:([Expr1018]=COUNT_BIG([T].[price]), [Expr1019]=SUM([T].[price])))&lt;br /&gt; ......|........|--Sort(ORDER BY:([T].[type] ASC, [T].[pub_id] ASC))&lt;br /&gt; ......|..............|--Clustered Index Scan(OBJECT:([pubs].[dbo].[titles].[UPKCL_titleidind] AS [T]), WHERE:(substring([T].[title], 1, 3)='The'))&lt;br /&gt; ......|--Table Spool&lt;br /&gt; ...........|--Filter(WHERE:([Expr1002]&gt;0.00))&lt;br /&gt; ................|--Compute Scalar(DEFINE:([Expr1002]=If ([Expr1020]=0) then NULL else [Expr1021]))&lt;br /&gt; .....................|--Stream Aggregate(GROUP BY:([T].[type], [T].[pub_id]) DEFINE:([Expr1020]=COUNT_BIG([T].[price]), [Expr1021]=SUM([T].[price])))&lt;br /&gt; ..........................|--Sort(ORDER BY:([T].[type] ASC, [T].[pub_id] ASC))&lt;br /&gt; ...............................|--Clustered Index Scan(OBJECT:([pubs].[dbo].[titles].[UPKCL_titleidind] AS [T]), WHERE:(substring([T].[title], 1, 3)='The'))&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Workaround&lt;/u&gt;&lt;br /&gt;You can workaround the problem by just replacing the LEFT function with SUBSTRING function.&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;SELECT T.pub_id, T.type, SUM(T.price) AS BasePrice&lt;br /&gt;FROM Titles T&lt;br /&gt;LEFT JOIN&lt;br /&gt;(Select 1) X (pub_id)&lt;br /&gt;ON X.pub_id = T.pub_id&lt;br /&gt;WHERE  SUBSTRING(T.title,1,3) = 'The'&lt;br /&gt;GROUP BY T.pub_id, T.type&lt;br /&gt;HAVING  SUM(T.price) &gt; 0&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Note&lt;/u&gt;&lt;br /&gt;This bug is fixed in SQL server 2005&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-114085384433386007?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/114085384433386007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=114085384433386007&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/114085384433386007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/114085384433386007'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2006/02/bug-combination-of-group-by-with.html' title='BUG: Combination of GROUP BY with HAVING Clause and LEFT OUTER JOIN with Derived Table With LEFT Function Produces Incorrect Result'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-114062017978873773</id><published>2006-02-22T20:26:00.000+05:30</published><updated>2006-02-22T20:26:19.826+05:30</updated><title type='text'>Named Constraints on Temporary tables</title><content type='html'>Last week I was investigating a peculiar issue reported by our testing team. They are receving an error  like the following occassionally. &lt;br /&gt;&lt;font color="#FF0000"&gt;&lt;br /&gt; Server: Msg 2714, Level 16, State 4, Line 2&lt;br /&gt;There is already an object named 'PK_Temp' in the database&lt;/font&gt;.&lt;br /&gt;&lt;br /&gt;It seems that the error occurs only when multiple users tries to access the same page. A concurrency issue. &lt;br /&gt;&lt;br /&gt;I looked at the code of the procedure being called from the page. I found that a code segment like the following is causing the problem.&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800040"&gt;&lt;br /&gt;CREATE TABLE #Temp(id int NOT NULL)&lt;br /&gt;ALTER TABLE #Temp ADD CONSTRAINT PK_Temp PRIMARY KEY(id) &lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;But why? SQL Server is supposed to  make a temp table name unique by adding a unique integer suffix. &lt;br /&gt;&lt;br /&gt;I opened two seperate connections in Query Analyzer and execute the above code. Same Error!&lt;br /&gt;&lt;br /&gt;It turns that even though the temprary table names automatically made unique between concurrent sessions, the constraint names still has to be unique across a database. &lt;br /&gt;&lt;br /&gt;I ended up adding "Do not use named constraints on temporary tables" to the list of best pracices.&lt;br /&gt;&lt;br /&gt;Alternatively you can define constraints on temporary tables either by specifying a nameless constructor when you create table, like, &lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800040"&gt;&lt;br /&gt;CREATE TABLE #Temp(id int NOT NULL PRIMARY KEY)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;Or by implicitly adding a constraint with the following syntax&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800040"&gt;&lt;br /&gt;ALTER TABLE #Temp ADD  PRIMARY KEY(id) &lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-114062017978873773?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/114062017978873773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=114062017978873773&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/114062017978873773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/114062017978873773'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2006/02/named-constraints-on-temporary-tables.html' title='Named Constraints on Temporary tables'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-113514775043755945</id><published>2005-12-21T12:19:00.000+05:30</published><updated>2005-12-21T16:07:07.256+05:30</updated><title type='text'>SQL Server 2005 System Table map</title><content type='html'>&lt;br /&gt;The SQL Server 2005 System Table Map shows the system tables included in SQL Server 2005, and the relationships between them.&lt;br /&gt;&lt;br /&gt;You can download it &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=2ec9e842-40be-4321-9b56-92fd3860fb32&amp;displaylang=en" target="_blank"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-113514775043755945?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/113514775043755945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=113514775043755945&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/113514775043755945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/113514775043755945'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/12/sql-server-2005-system-table-map.html' title='SQL Server 2005 System Table map'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-113083026988731612</id><published>2005-11-01T13:01:00.000+05:30</published><updated>2005-11-01T13:01:11.723+05:30</updated><title type='text'>What is your 2005 IQ?</title><content type='html'>Test your SQL Server 2005 knowledge and win &lt;a href="http://www.idera5iq.com/default.asp" target="_blank"&gt;grand prizes&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-113083026988731612?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/113083026988731612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=113083026988731612&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/113083026988731612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/113083026988731612'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/11/what-is-your-2005-iq.html' title='What is your 2005 IQ?'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-113073910516341197</id><published>2005-10-31T11:41:00.000+05:30</published><updated>2005-10-31T11:41:45.220+05:30</updated><title type='text'>SQL Server 2005 Articles</title><content type='html'>A Big collection of SQL Server 2005 related article links are posted at the SQL.RU site.&lt;br /&gt;&lt;br /&gt;Here is the &lt;a href="http://www.sql.ru/club/YukonArt.shtml" target="_blank"&gt;link&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-113073910516341197?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/113073910516341197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=113073910516341197&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/113073910516341197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/113073910516341197'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/10/sql-server-2005-articles.html' title='SQL Server 2005 Articles'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-113065296754852604</id><published>2005-10-30T11:46:00.000+05:30</published><updated>2005-10-30T11:46:07.553+05:30</updated><title type='text'>T-SQL Coding Challenge</title><content type='html'>&lt;br /&gt;Do you know what &lt;a href="http://www.answers.com/main/ntquery?s=quine&amp;gwp=11&amp;ver=1.0.3.109&amp;method=2" target="_blank"&gt;quine&lt;/a&gt; is?&lt;br /&gt;&lt;br /&gt;If yes, there is an interesting challenge on Ken Henderson's blog for self replicating  T-SQL code.&lt;br /&gt;&lt;br /&gt;As always, Steve Kass came up with the smartest one.&lt;br /&gt;&lt;br /&gt;Here are the links&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/khen1234/archive/2005/10/25/484555.aspx" target="_blank"&gt;T-SQL Coding Challenge&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/khen1234/archive/2005/10/26/485477.aspx" target="_blank"&gt;More about self-reproducing T-SQL&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-113065296754852604?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/113065296754852604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=113065296754852604&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/113065296754852604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/113065296754852604'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/10/t-sql-coding-challenge.html' title='T-SQL Coding Challenge'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-113065277522408857</id><published>2005-10-30T11:42:00.000+05:30</published><updated>2005-10-30T11:42:55.246+05:30</updated><title type='text'>The New Generation of Microsoft Certifications</title><content type='html'>&lt;br /&gt;The Microsoft Certifications are getting more specific, and is going to be available by early 2006.&lt;br /&gt;&lt;br /&gt;Here is an &lt;a href="http://www.microsoft.com/learning/mcp/newgen/" target="_blank"&gt;overview&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-113065277522408857?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/113065277522408857/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=113065277522408857&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/113065277522408857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/113065277522408857'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/10/new-generation-of-microsoft.html' title='The New Generation of Microsoft Certifications'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112893001006522609</id><published>2005-10-10T13:10:00.000+05:30</published><updated>2005-10-10T13:10:10.523+05:30</updated><title type='text'>Good News!</title><content type='html'>&lt;br /&gt;I am &lt;a href="http://toponewithties.blogspot.com/2004/06/why-blog.html" target="_blank"&gt;committed&lt;/a&gt; that I will be posting only things that are 'SQL', not anything personal, here. &lt;br /&gt;But what will I do when I have some great news to tell you guys?&lt;br /&gt;&lt;br /&gt;Hmmm.. I will tell that in an SQL (read crazy) way.&lt;br /&gt;&lt;br /&gt;So here you go.&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800040"&gt;&lt;br /&gt;SELECT &lt;br /&gt;	CHAR(LEFT(P.m,2)) +&lt;br /&gt;	CHAR(SUBSTRING(P.m,3,2^1)) +&lt;br /&gt;	CHAR(SUBSTRING(P.m,6,~2 * -1)) +&lt;br /&gt;	CHAR(RIGHT(P.m,(-3 &amp; 4 -1))) +&lt;br /&gt;	SPACE(1)+&lt;br /&gt;	STUFF(REPLACE(STUFF(OBJECT_NAME(1), 1, 4, ''),'j',''),4,1,REVERSE('emo'))+&lt;br /&gt;	SPACE(1)+ CHAR(ASCII('`')+1)+ SPACE(1)+&lt;br /&gt;	LEFT(@@VERSION,20)+&lt;br /&gt;	SPACE(1)+ UPPER(LEFT(DB_NAME(1),1))+&lt;br /&gt;	CHAR(CAST(LEFT(P.m,2) AS INT)+4)+&lt;br /&gt;	CONVERT(CHAR(2), 0x5021) AS [Good News]&lt;br /&gt;FROM&lt;br /&gt;	(SELECT  REVERSE(V.hugo+V.adam+V.david+V.louis) &lt;br /&gt;	 FROM&lt;br /&gt;		(SELECT  &lt;br /&gt;			CAST(M.a AS VARCHAR) AS thanksto_JCelko, &lt;br /&gt;			CAST(M.a + POWER(8^2,DB_ID('tempdb')) AS VARCHAR) AS thanksto_Sommarskog, &lt;br /&gt;			REPLICATE(DB_ID('master'),3) As thanksto_ItzikBenGan, &lt;br /&gt;			CAST(M.s AS VARCHAR) As thanksto_Tibor&lt;br /&gt;			FROM &lt;br /&gt;				(SELECT &lt;br /&gt;					(DB_ID('msdb') + 1) * POWER(10,DB_ID('tempdb')) + 1 AS thanksto_ASen,&lt;br /&gt;					 DATEDIFF(yy, '19760509','20051007')-1 AS thanksto_SKass) As  M(a,s)&lt;br /&gt;			)AS V(hugo, adam, david, louis)) P(m)&lt;br /&gt;UNION ALL&lt;br /&gt;SELECT  CONVERT(VARCHAR, 0x5468616E6B7320746F20796F7520616C6C21)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;-- :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112893001006522609?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112893001006522609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112893001006522609&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112893001006522609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112893001006522609'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/10/good-news.html' title='Good News!'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112479230609740202</id><published>2005-08-23T15:48:00.000+05:30</published><updated>2005-08-23T15:56:01.683+05:30</updated><title type='text'>Sampling Using TABLESAMPLE</title><content type='html'>&lt;br /&gt;With due credits to &lt;a href="http://www.users.drew.edu/skass/" target="_blank"&gt;Steve Kass&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;SQL Server 2005 Implements the TABLESAMPLE clause, which can be used to retrieve a sample  (of rows) from a table. &lt;br /&gt;&lt;br /&gt;Here is the syntax of the TABLESAMPLE command.&lt;br /&gt;&lt;br /&gt; &lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;TABLESAMPLE [SYSTEM] (sample_number [ PERCENT | ROWS ] ) &lt;br /&gt;        [ REPEATABLE (repeat_seed) ] &lt;br /&gt;&lt;br /&gt;eg.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT * FROM Person.Contact&lt;br /&gt;TABLESAMPLE SYSTEM(50 ROWS)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;The optional SYSTEM keyword specifies the sampling algorithm to use. In the case of SQL Server 2005 SYSTEM is the only sampling method available and applied by default. Other products like DB2 has implemented sampling methods like BERNOULLI.&lt;br /&gt;&lt;br /&gt;You can specify the number of rows or percentage of rows you want to get back. But remeber that the sampling method gives an approximate number of rows back. So when you are trying to apply TABLESAMPLE on a small table chances are likely that,  you may get zero rows back.&lt;br /&gt;&lt;br /&gt;WHEN used with the REPEATABLE option, with the same seed value, SQL Server will return the same sample as before. When specified with a different repeat_seed value, SQL Server will likely return a different sample of the rows in the table.&lt;br /&gt;&lt;br /&gt;TABLESAMPLE does not work with views or inline table-valued functions.&lt;br /&gt;&lt;br /&gt;When I tried TABLESAMPLE first,  I tried&lt;br /&gt;&lt;br /&gt; &lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;SELECT * FROM Sales.StoreContact &lt;br /&gt;TABLESAMPLE SYSTEM(10 ROWS)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;And to my surprize, most of the time I was getting Zero rows back, and sometimes  37 or 179 rows. I had reported this issue in a beta newsgroup and SQL Server MVP Steve Kass help me understand it better. Here is the excerpts from his reply.&lt;br /&gt;&lt;br /&gt;&lt;font color="#004080"&gt;&lt;br /&gt;&amp;lt;QUOTE&amp;gt;&lt;br /&gt;As documented in Books Online ("Limiting Results Sets by Using TABLESAMPLE"),&lt;br /&gt;the sampling algorithm can only return full data pages.  Each page is&lt;br /&gt;selected or skipped with probability [desired number of rows]/[rows in table]&lt;br /&gt;&lt;br /&gt;The StoreContact table fits on 4 data pages.  Three of those pages contain&lt;br /&gt;179 rows, and one contains 37 rows.  When you sample for 10 rows (1/75&lt;br /&gt;of the table), each of the 4 pages is returned with probability 1/75 and&lt;br /&gt;skipped with probabiliy 74/75.  The chance that no rows are returned is&lt;br /&gt;about (74/75)^4, or about 87%.  When rows are returned, about 3/4 of the&lt;br /&gt;time you will see 179 rows, and about 1/4 of the time you will see 37&lt;br /&gt;rows.  Very rarely, you will see more rows, if two or more pages are&lt;br /&gt;returned, but this is very unlikely.&lt;br /&gt;&lt;br /&gt;As BOL suggests, SYSTEM sampling (which is the only choice) is not&lt;br /&gt;recommended for small tables.  I would add that if the table fits on&lt;br /&gt;N data pages, you should not try to sample fewer than 1/N-th of the&lt;br /&gt;rows, or that you should never try to sample fewer rows than fit on&lt;br /&gt;at least 2 or 3 data pages.&lt;br /&gt;&lt;br /&gt;If you were to sample roughly two data pages worth of rows, say&lt;br /&gt;300 rows, the chance of seeing no rows would be about 13%.  The&lt;br /&gt;larger (more data pages) the table, the smaller the chance of&lt;br /&gt;seeing no rows when at least a couple of pages worth are requested.&lt;br /&gt;For example, if you request 300 rows from a 1,000,000 row table that&lt;br /&gt;fits on 10,000 data pages, only in 5% of trials would you see no&lt;br /&gt;rows, even though the request is for far less than 1% of the rows.&lt;br /&gt;&lt;br /&gt;By choosing the REPEATABLE option, you will get the same sample&lt;br /&gt;each time.  For most seeds, this will be an empty sample in your&lt;br /&gt;case.  With other seeds, it will contain 37, 179, 216, 358, 395,&lt;br /&gt;537, 574, or 753 rows, depending on which pages were selected,&lt;br /&gt;with the larger numbers of rows returned for very few choices&lt;br /&gt;of seed.&lt;br /&gt;&lt;br /&gt;That said, I agree that the consequences of returning only&lt;br /&gt;full data pages results in very confusing behavior!&lt;br /&gt;&amp;lt;/QUOTE&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;That makes things clear. For my question about the usability of the feature, Conor Cunningham,  Development Lead of  SQL Server Query Optimization team, gave the following answer.&lt;br /&gt;&lt;br /&gt;&lt;font color="#004080"&gt;&lt;br /&gt;&amp;lt;QUOTE&amp;gt;&lt;br /&gt;From a usability standpoint, we are following ANSI - we are allowed to &lt;br /&gt;arbitrarily over- or under-sample using the SYSTEM keyword.  For small &lt;br /&gt;tables, we happen to over-sample by sampling all rows.&lt;br /&gt;&lt;br /&gt;We believe that this provides an effective sampling algorithm for some &lt;br /&gt;classes of applications.&lt;br /&gt;&amp;lt;/QUOTE&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;But my concern was mostly about the zero rows case. I gave the following reply to Conor. &lt;br /&gt;&lt;br /&gt;&lt;font color="#004080"&gt;&lt;br /&gt;&amp;lt;QUOTE&amp;gt;&lt;br /&gt; I agree the point that in the SYSTEM sampling method, the implementor is &lt;br /&gt;allowed to arbitrarly over/under sample any given set. And I am OK with &lt;br /&gt;that.&lt;br /&gt;&lt;br /&gt;But my cause of concern is when I try to get a 10%  SAMPLE on a table that has &lt;br /&gt;over 700 rows, I get zero rows back.&lt;br /&gt;&lt;br /&gt;To me, Any sampling algorithm, that applied on a set that has one or more &lt;br /&gt;rows MUST return one or more rows. I dont think zero rows can be a proper &lt;br /&gt;sample.&lt;br /&gt;&amp;lt;/QUOTE&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;I was asked to open a bug, which I did &lt;a href="http://lab.msdn.microsoft.com/ProductFeedback/viewfeedback.aspx?feedbackid=7e289854-3acb-4cdc-b00c-444730b2e4b3" target="_blank"&gt;here &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Later the issue was Resolved as By Design by Microsoft.&lt;br /&gt;&lt;br /&gt;Meanwhile Steve Kass gave me the following T-SQL code to implement Bernoulli Sampling.&lt;br /&gt;&lt;br /&gt; &lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;select * from Sales.StoreContact&lt;br /&gt;where rand(checksum(newid())%1000000000+CustomerID)&lt; 0.1&lt;br /&gt;-- 0.1 is the desired probability of choosing a row, change as needed.&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Eventhough TABLESAMPLE can be confusing with small tables, you will still find it useful in some cases.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112479230609740202?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112479230609740202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112479230609740202&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112479230609740202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112479230609740202'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/08/sampling-using-tablesample.html' title='Sampling Using TABLESAMPLE'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112340090916129935</id><published>2005-08-07T13:18:00.000+05:30</published><updated>2005-08-07T13:32:19.146+05:30</updated><title type='text'>MAX Sized datatypes</title><content type='html'>&lt;br /&gt;You are no longer limited to that 8000 charcter limit for VARCHAR variables. SQL Server 2005 enhances the VARCHAR, NVARCHAR and VARBINARY datatypes by raising the capacity to Approximately 2GB. You can declare the variables with the MAX specifier. Lets quickly try some VARCHAR(MAX) operations.&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#400000"&gt;&lt;br /&gt;DECLARE @vchTest VARCHAR(MAX) &lt;br /&gt;SET @vchTest = REPLICATE('AA', 5000)&lt;br /&gt;SELECT LEN(@vchTest) as Length&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;Length&lt;br /&gt;--------&lt;br /&gt;8000&lt;br /&gt;&lt;br /&gt;Ofcourse, I expected to see 10000 back as result. I refer the REPLICATE command in BOL which clearly says&lt;br /&gt;&lt;br /&gt;"If character_expression is not of type varchar(max) or nvarchar(max), REPLICATE truncates the return value at 8,000 bytes. To return values greater than 8,000 bytes, character_expression must be explicitly cast to the appropriate large-value data type. "&lt;br /&gt;&lt;br /&gt;So I tried&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#400000"&gt;&lt;br /&gt;DECLARE @vchTest VARCHAR(MAX) &lt;br /&gt;SET @vchTest = REPLICATE(CAST('AA' AS VARCHAR(MAX)), 5000)&lt;br /&gt;SELECT LEN(@vchTest) as Length&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Length&lt;br /&gt;--------&lt;br /&gt;10000&lt;br /&gt;&lt;br /&gt;Then I tried Concatenating many VARCHAR(n) values and assign it to VARCHAR(MAX) .&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#400000"&gt;&lt;br /&gt;DECLARE @vchTest VARCHAR(MAX) &lt;br /&gt;SET @vchTest = REPLICATE('AA',4000)+ REPLICATE('AA', 4000)&lt;br /&gt;SELECT LEN(@vchTest) as Length&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;Length&lt;br /&gt;--------&lt;br /&gt;8000&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This time I expected to see 16000 as the result. But I still get 8000 back! &lt;br /&gt;&lt;br /&gt;I got help from &lt;a href="http://blogs.conchango.com/christianwade/archive/2004/11/06/199.aspx" target="_blank"&gt;Christian Wade's blog&lt;/a&gt; Which says, &lt;br /&gt;&lt;br /&gt;&lt;font color="#000080"&gt;&amp;lt;QUOTE&amp;gt;&lt;br /&gt;The problem is that if you concatenate two varchar(8000) variables, you will be left with a varchar(8000) variable.  This is the same issue as populating a float with the division of two integers.&lt;br /&gt;The reason is that varchar(n) variables are physically stored in the same way - irrespective of length.  Whereas an varchar(MAX) is effectively a text under the covers and needs to worry about managing pointers to the relevant data page (although this is abstracted away from the developer).&lt;br /&gt;&amp;lt;QUOTE/&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;To ensure I just tried &lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#400000"&gt;&lt;br /&gt;DECLARE @S VARCHAR(9000)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;which returned the error.&lt;br /&gt;&lt;br /&gt;&lt;font color="#FF0000"&gt;Msg 131, Level 15, State 3, Line 1&lt;br /&gt;The size (9000) given to the type 'varchar' exceeds the maximum allowed for any data type (8000).&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;The workaround Christian Wade suggested iscasting the two expressions individually to the large-valued type and then do the assignment.&lt;br /&gt;&lt;br /&gt;However, I find it more easy to do an Initialisation and Concantenation with the actual variable, like&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#400000"&gt;&lt;br /&gt;DECLARE @vchTest VARCHAR(MAX) &lt;br /&gt;SET @vchTest = 'Start'&lt;br /&gt;SET @vchTest = @vchTest + REPLICATE('AbC2',2000) + 'Test'+  REPLICATE('AbC2',2000) + 'End'&lt;br /&gt;SELECT LEN(@vchTest) as Length&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;Length&lt;br /&gt;---------&lt;br /&gt;16012&lt;br /&gt;&lt;br /&gt;Then I tried all String functions on the variable&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#400000"&gt;&lt;br /&gt;SELECT LEN(LEFT(@vchTest,9000)) --OK&lt;br /&gt;SELECT RIGHT(@vchTest,3)&lt;br /&gt;SET @vchTest= REPLACE(@vchTest,'End','XXX')&lt;br /&gt;SELECT RIGHT(@vchTest,3) &lt;br /&gt;SET @vchTest = REVERSE(@vchTest)&lt;br /&gt;SELECT RIGHT(@vchTest,3) &lt;br /&gt;SET @vchTest = REVERSE(@vchTest)&lt;br /&gt;SET @vchTest = SPACE(9000) + @vchTest&lt;br /&gt;SELECT LEN(@vchTest)&lt;br /&gt;SELECT CHARINDEX('Test',@vchTest) --Correct&lt;br /&gt;SET @vchTest = STUFF(@vchTest,24001,4,'SQL')&lt;br /&gt;SELECT CHARINDEX('SQL',@vchTest) --Correct&lt;br /&gt;SELECT SUBSTRING(@vchTest,32000,3)&lt;br /&gt;SET @vchTest = LOWER(UPPER(@vchTest))&lt;br /&gt;SELECT LEN(@vchTest)&lt;br /&gt;SET  @vchTest = LTRIM(@vchTest)&lt;br /&gt;SELECT LEN(@vchTest)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;All seems to work fine. &lt;br /&gt;&lt;br /&gt;The text, ntext and image data types will be deprecated. The varchar(max), nvarchar(max) and varbinary(max) data types are far superior than these old datatypes, because you dont have to use special statements like WRITETEXT and UPDATE text. You can use the standard INSERT and UPDATE statements. . For more information, see the topic Using Large Value Data Types in Books Online.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112340090916129935?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112340090916129935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112340090916129935&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112340090916129935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112340090916129935'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/08/max-sized-datatypes.html' title='MAX Sized datatypes'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112333831904066082</id><published>2005-08-06T19:55:00.000+05:30</published><updated>2005-08-06T20:54:15.306+05:30</updated><title type='text'>New APPLY Operator</title><content type='html'>The new APPLY Operator lets you reference one or more columns from  the LEFT table in the right Derived table or table valued function. There are to variations of the Operator, CROSS APPLY and OUTER APPLY. You can use CROSS APPLY like an INNER JOIN except that you dont have to specify any JOIN condition and you can reference the left table columns in the right hand side of the Operator. OUTER APPLY is like LEFT JOIN, that all rows from the left table is included in the result even when there is no match.&lt;br /&gt;&lt;br /&gt;The main advantage of the CROSS APPLY operator is that it lets you pass values from the columns of the joined table to a table valued UDF, which was not possible in previous versions of SQL Server.&lt;br /&gt;&lt;br /&gt;Suppose you have the following table structure.&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;CREATE TABLE #Client(ClientId int, ClientName VARCHAR(35))&lt;br /&gt;CREATE TABLE #Account(AccountId int, ClientId int, AccountValue numeric(18,2))&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client VALUES(1, 'Anil')&lt;br /&gt;INSERT INTO #Client VALUES(2, 'Robin')&lt;br /&gt;&lt;br /&gt;INSERT INTO #Account VALUES(1,1,100)&lt;br /&gt;INSERT INTO #Account VALUES(2,1,200)&lt;br /&gt;INSERT INTO #Account VALUES(3,1,300)&lt;br /&gt;INSERT INTO #Account VALUES(4,2,100)&lt;br /&gt;INSERT INTO #Account VALUES(5,2,400)&lt;br /&gt;INSERT INTO #Account VALUES(6,2,500)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;And you were asked to get the TOP 2 Accounts based on AccountValue of each client.&lt;br /&gt;&lt;br /&gt;Is SQL Server 2000 you can achieve it by writing a query like,&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;SELECT C.ClientName, A.AccountValue&lt;br /&gt;FROM #Client C&lt;br /&gt;INNER JOIN #Account A&lt;br /&gt;ON C.ClientId=A.ClientId&lt;br /&gt;AND A.AccountID IN(&lt;br /&gt;	SELECT TOP 2 AccountId &lt;br /&gt;	FROM #Account D&lt;br /&gt;	WHERE D.ClientID=A.ClientId&lt;br /&gt;	ORDER BY D.AccountValue DESC)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Which is ofcourse costly.  See how CROSS APPLY makes life easy for you.&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;SELECT C.ClientName, A.AccountValue&lt;br /&gt;FROM #Client C&lt;br /&gt;CROSS APPLY&lt;br /&gt;(SELECT TOP 2 AccountId,  AccountValue&lt;br /&gt;	FROM #Account D&lt;br /&gt;	WHERE D.ClientID=C.ClientId&lt;br /&gt;	ORDER BY D.AccountValue DESC)A&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;Here is the result of the above two queries.&lt;br /&gt;&lt;br /&gt;&lt;TABLE bgColor=#CCCCCC Border=1&gt;&lt;TR&gt;&lt;TD&gt;ClientName&lt;/TD&gt;&lt;TD&gt;AccountValue&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Anil&lt;/TD&gt;&lt;TD&gt;300.00&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Anil&lt;/TD&gt;&lt;TD&gt;200.00&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Robin&lt;/TD&gt;&lt;TD&gt;500.00&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Robin&lt;/TD&gt;&lt;TD&gt;400.00&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;&lt;br /&gt;&lt;br /&gt;To see OUTER APPLY at work, Lets add a client without any accounts and try the above query with OUTER APPLY&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;INSERT INTO #Client VALUES(3, 'Roji')&lt;br /&gt;&lt;br /&gt;SELECT C.ClientName, A.AccountValue&lt;br /&gt;FROM #Client C&lt;br /&gt;OUTER APPLY&lt;br /&gt;(SELECT TOP 2 AccountId,  AccountValue&lt;br /&gt;	FROM #Account D&lt;br /&gt;	WHERE D.ClientID=C.ClientId&lt;br /&gt;	ORDER BY D.AccountValue DESC)A&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;And here is the result.&lt;br /&gt;&lt;br /&gt;&lt;TABLE bgColor=#CCCCCC Border=1&gt;&lt;TR&gt;&lt;TD&gt;ClientName&lt;/TD&gt;&lt;TD&gt;AccountValue&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Anil&lt;/TD&gt;&lt;TD&gt;300.00&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Anil&lt;/TD&gt;&lt;TD&gt;200.00&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Robin&lt;/TD&gt;&lt;TD&gt;500.00&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Robin&lt;/TD&gt;&lt;TD&gt;400.00&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Roji&lt;/TD&gt;&lt;TD&gt;NULL&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;&lt;br /&gt;&lt;br /&gt;You feel the real power of OUTER/CROSS APPLY When you use them with the Table Values UDFs. There is a UDF named &lt;b&gt;dbo.ufnGetContactInformation&lt;/b&gt; in the new AdventureWorks Sample database, which accepts a ContactID as the input and return all contact details as a table. Lets try using that function to get the contact details of all the contacts in the&lt;b&gt; Sales.ContactCreditCard&lt;/b&gt; table.&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;SELECT B.FirstName, B.LastName, B.JobTitle, B.ContactType&lt;br /&gt;FROM Sales.ContactCreditCard A&lt;br /&gt;CROSS APPLY dbo.ufnGetContactInformation(A.ContactId) B&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;And here is the (abridged) result.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;TABLE bgColor=#CCCCCC Border=1&gt;&lt;TR&gt;&lt;TD&gt;FirstName&lt;/TD&gt;&lt;TD&gt;LastName&lt;/TD&gt;&lt;TD&gt;JobTitle&lt;/TD&gt;&lt;TD&gt;ContactType&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Catherine&lt;/TD&gt;&lt;TD&gt;Abel&lt;/TD&gt;&lt;TD&gt;Owner&lt;/TD&gt;&lt;TD&gt;Store Contact&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Kim&lt;/TD&gt;&lt;TD&gt;Abercrombie&lt;/TD&gt;&lt;TD&gt;Owner&lt;/TD&gt;&lt;TD&gt;Store Contact&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Humberto&lt;/TD&gt;&lt;TD&gt;Acevedo&lt;/TD&gt;&lt;TD&gt;Owner&lt;/TD&gt;&lt;TD&gt;Store Contact&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;Pilar&lt;/TD&gt;&lt;TD&gt;Ackerman&lt;/TD&gt;&lt;TD&gt;Owner&lt;/TD&gt;&lt;TD&gt;Store Contact&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But thats just an introduction. I had seen a lot of smart SQL using CROSS APPLY in NG posting recently. So stay tuned.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112333831904066082?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112333831904066082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112333831904066082&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112333831904066082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112333831904066082'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/08/new-apply-operator.html' title='New APPLY Operator'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112314509110802004</id><published>2005-08-04T14:14:00.000+05:30</published><updated>2005-08-04T14:23:04.893+05:30</updated><title type='text'>DML With Output</title><content type='html'>SQL Server 2005 introduces a new feature for retrieving rows affected by an INSERT, UPDATE or Delete statement. It is a common requirement to get the affected rows back for further processing, auditing or simply return them back to the client. &lt;br /&gt;&lt;br /&gt;Those who had worked with triggers are familiar with the special inserted and deleted tables. The new OUTPUT clause also work in the same manner. You can use the OUTPUT keyword to return information about the results of a Transact-SQL statement into a table variable, temporary table, permanent table or just return it back to the client.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Using the OUTPUT Clause with INSERT&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;CREATE Table #OutputTest(someid int IDENTITY(1,1), sometext varchar(100))&lt;br /&gt;--Table variable to collect changes&lt;br /&gt;&lt;br /&gt;DECLARE @InsertDetails TABLE(someid int,sometext varchar(100))&lt;br /&gt;INSERT INTO #OutputTest(sometext)&lt;br /&gt;OUTPUT Inserted.SomeId, Inserted.someText INTO @InsertDetails&lt;br /&gt;VALUES('Some Text goes Here')&lt;br /&gt;&lt;br /&gt;SELECT * FROM @InsertDetails&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Here is the result.&lt;br /&gt;(1 row(s) affected)&lt;br /&gt;someid      sometext&lt;br /&gt;----------- ----------------------------------&lt;br /&gt;1           Some Text goes Here&lt;br /&gt;&lt;br /&gt;(1 row(s) affected)&lt;br /&gt;&lt;br /&gt;Note that we are retriving the just inserted IDENTITY value also.&lt;br /&gt;&lt;br /&gt;Now lets try to insert a batch of rows.&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;--Table variable to collect changes&lt;br /&gt;DECLARE @InsertDetails TABLE(someid int,sometext varchar(100))&lt;br /&gt;&lt;br /&gt;--Inserting a batch&lt;br /&gt;INSERT INTO #OutputTest(sometext)&lt;br /&gt;OUTPUT Inserted.SomeId, Inserted.someText INTO @InsertDetails&lt;br /&gt;SELECT 'Test 1' UNION&lt;br /&gt;SELECT 'Test 2' UNION&lt;br /&gt;SELECT 'Test 3' &lt;br /&gt;&lt;br /&gt;SELECT * FROM @InsertDetails&lt;br /&gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;And here is the OUTPUT.&lt;br /&gt;(3 row(s) affected)&lt;br /&gt;someid      sometext&lt;br /&gt;----------- -----------------------------------------------------------------&lt;br /&gt;1           Test 1&lt;br /&gt;2           Test 2&lt;br /&gt;3           Test 3&lt;br /&gt;&lt;br /&gt;(3 row(s) affected)&lt;br /&gt;&lt;br /&gt; &lt;b&gt;Using the OUTPUT Clause with UPDATE&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;DECLARE @UpdateDetails TABLE(id int, prevtext VARCHAR(100), newText VARCHAR(100))&lt;br /&gt;&lt;br /&gt;UPDATE #OutputTest&lt;br /&gt;SET sometext = 'XYZ'&lt;br /&gt;OUTPUT deleted.someid, deleted.sometext,inserted.sometext INTO @UpdateDetails&lt;br /&gt;WHERE SomeID &lt; 3&lt;br /&gt;&lt;br /&gt;SELECT * FROM @UpdateDetails&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Here is the output.&lt;br /&gt;&lt;br /&gt;(2 row(s) affected)&lt;br /&gt;id          prevtext   newText&lt;br /&gt;----------- ---------- ----------&lt;br /&gt;1           Test 1     XYZ&lt;br /&gt;2           Test 2     XYZ&lt;br /&gt;&lt;br /&gt;(2 row(s) affected)&lt;br /&gt;&lt;br /&gt;Note that here we are capturing both the current and previous values of the affected column.&lt;br /&gt;&lt;br /&gt; &lt;b&gt;Using the OUTPUT Clause with DELETE&lt;/b&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;DECLARE @DeleteDetails TABLE(id int, DeletedBy sysname)&lt;br /&gt;DELETE FROM #OutputTest&lt;br /&gt;OUTPUT deleted.someid, SUSER_NAME() INTO @DeleteDetails&lt;br /&gt;WHERE SomeID=3&lt;br /&gt;&lt;br /&gt;SELECT * FROM @DeleteDetails&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Here is the result&lt;br /&gt;&lt;br /&gt;(1 row(s) affected)&lt;br /&gt;id          DeletedBy&lt;br /&gt;----------- --------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;3          DOMAIN\rojipt&lt;br /&gt;&lt;br /&gt;(1 row(s) affected)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I believe the DML OUTPUTwill  be one of the most favourite feature of T-SQL developers.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112314509110802004?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112314509110802004/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112314509110802004&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112314509110802004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112314509110802004'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/08/dml-with-output.html' title='DML With Output'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112306716205733988</id><published>2005-08-03T16:24:00.000+05:30</published><updated>2005-08-03T16:40:03.400+05:30</updated><title type='text'>Common (TOP 10?) T-SQL Programming mistakes</title><content type='html'>&lt;strong&gt;1. TOP Without ORDER BY&lt;/strong&gt;&lt;br /&gt;SQL Server doesn’t guarantee the order of records returned, if an explicit ORDER BY clause is not specified. Records are not returned in the order they were created. Most of the times records are returned in the order of the clustered index, but not necessarily always.&lt;br /&gt;Eg.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Client(ClientID int IDENTITY(1,1), ClientName varchar(30), AnnualIncome int)&lt;br /&gt;&lt;br /&gt;--Add a clustered index on ClientName&lt;br /&gt;--CREATE CLUSTERED INDEX idx1 ON #Client(ClientName)&lt;br /&gt;&lt;br /&gt;--Populate the client table.&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Prasanth', 10000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Binu', 20000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Shino', 30000)&lt;br /&gt;&lt;br /&gt;--Populate the account table&lt;br /&gt;&lt;br /&gt;SELECT TOP 1 * FROM #Client&lt;br /&gt;--ORDER BY ClientID&lt;br /&gt;&lt;br /&gt;DROP TABLE #Client&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;2. TOP Without TIES&lt;br /&gt;&lt;/strong&gt;If you are expecting TIES in the result and you want all tied records, (like in the case of finding rank) you should use WITH TIES clause with the SELECT statement.&lt;br /&gt;&lt;br /&gt;Eg.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Client(ClientID int IDENTITY(1,1), ClientName varchar(30), AnnualIncome int)&lt;br /&gt;&lt;br /&gt;--Populate the client table.&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Prasanth', 10000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Binu', 30000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Shino', 30000)&lt;br /&gt;&lt;br /&gt;SELECT TOP 1 * FROM #Client&lt;br /&gt;ORDER BY AnnualIncome DESC&lt;br /&gt;&lt;br /&gt;DROP TABLE #Client&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3. Not Using an Alias&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Consider the following query.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Client(ClientID int IDENTITY(1,1), ClientName varchar(30), AnnualIncome int)&lt;br /&gt;&lt;br /&gt;CREATE TABLE #Account(AccountId int IDENTITY(1,1), ClientId int, AccountValue int)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--Populate the client table.&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Prasanth', 10000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Binu', 20000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Shino', 30000)&lt;br /&gt;&lt;br /&gt;--Populate the account table&lt;br /&gt;&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(1, 500)&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(2, 1500)&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(3, 2000)&lt;br /&gt;&lt;br /&gt;SELECT * FROM #Account&lt;br /&gt;WHERE AccountId IN(SELECT AccountId FROM #Client)&lt;br /&gt;&lt;br /&gt;DROP TABLE #Client&lt;br /&gt;DROP TABLE #Account&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Obviously there is no column called AccountId in the #Client table. Probably you are expecting an error, but the query returns all the records from the #Account table. What happened behind the scenes is that, SQL Server looks for the accountId column in the #Client table and when it fails to find the column there, it looks for the column in the outer table. This behaviour is referred as fancy scoping.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4. Aggreagation And JOINS&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Be careful when doing aggregation on joined resultset. Chances are there that you may getting the wrong result. Consider the following example.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Client(ClientID int IDENTITY(1,1), ClientName varchar(30), AnnualIncome int)&lt;br /&gt;&lt;br /&gt;CREATE TABLE #Account(AccountId int IDENTITY(1,1), ClientId int, AccountValue int)&lt;br /&gt;&lt;br /&gt;--Populate the client table.&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Prasanth', 10000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Binu', 20000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Shino', 30000)&lt;br /&gt;&lt;br /&gt;--Populate the account table&lt;br /&gt;&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(1, 500)&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(1, 1500)&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(2, 1500)&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(3, 2000)&lt;br /&gt;&lt;br /&gt;SELECT C.ClientId, C.ClientName,SUM(C.AnnualIncome)&lt;br /&gt;FROM #Client C&lt;br /&gt;INNER JOIN #Account A&lt;br /&gt;ON C.ClientId = A.ClientId&lt;br /&gt;GROUP BY C.ClientId, C.ClientName&lt;br /&gt;ORDER BY C.ClientId&lt;br /&gt;&lt;br /&gt;DROP TABLE #Client&lt;br /&gt;DROP TABLE #Account&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;5. NOT IN AND NULL&lt;br /&gt;&lt;/strong&gt;If you are using the NOT IN Opereator with a subquery and the subquery contains any NULL values, the subquery will return NULL!. This can be dangerous, and this is not the case if you use IN.&lt;br /&gt;&lt;br /&gt;Eg.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Client(ClientID int IDENTITY(1,1), ClientName varchar(30), AnnualIncome int)&lt;br /&gt;&lt;br /&gt;CREATE TABLE #Account(AccountId int IDENTITY(1,1), ClientId int, AccountValue int)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--Populate the client table.&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Prasanth', 10000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Binu', 20000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Shino', 30000)&lt;br /&gt;&lt;br /&gt;--Populate the account table&lt;br /&gt;&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(1, 500)&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(2, 1500)&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(NULL, 2000)&lt;br /&gt;&lt;br /&gt;SELECT * FROM #Client&lt;br /&gt;WHERE ClientID NOT IN(SELECT ClientId FROM #Account)&lt;br /&gt;&lt;br /&gt;DROP TABLE #Client&lt;br /&gt;DROP TABLE #Account&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;6. Aggregation And NULL&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;If any of the columns you are apllying aggregate functions contains NULL , SQL Server will return a warning, “Warning: Null value is eliminated by an aggregate or other SET operation.”. If you are accessing the recordset using ADO, you might face problems. Either use ISNULL() function or SET ANSI_WARNINGS OFF. Setting ANSI_WARNINGS inside an SP will cause it to recompile everytime.&lt;br /&gt;&lt;br /&gt;Eg.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Client(ClientID int IDENTITY(1,1), ClientName varchar(30), AnnualIncome int)&lt;br /&gt;&lt;br /&gt;--Populate the client table.&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Prasanth', 10000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Binu', 30000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Shino', NULL)&lt;br /&gt;&lt;br /&gt;SELECT SUM(AnnualIncome) FROM #Client&lt;br /&gt;&lt;br /&gt;DROP TABLE #Client&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;7. OUTER JOIN AND WHERE Condition&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;Consider the following query.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Client(ClientID int IDENTITY(1,1), ClientName varchar(30), AnnualIncome int)&lt;br /&gt;&lt;br /&gt;CREATE TABLE #Account(AccountId int IDENTITY(1,1), ClientId int, AccountValue int)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--Populate the client table.&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Prasanth', 10000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Binu', 20000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Shino', 30000)&lt;br /&gt;&lt;br /&gt;--Populate the account table&lt;br /&gt;&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(1, 500)&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(2, 1500)&lt;br /&gt;&lt;br /&gt;--To find Clients who has an annualIncome &gt; 10000&lt;br /&gt;SELECT C.ClientName&lt;br /&gt;FROM #Client C&lt;br /&gt;LEFT JOIN #Account A&lt;br /&gt;ON C.ClientId = A.ClientId&lt;br /&gt;AND C.AnnualIncome &gt; 10000&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DROP TABLE #Client&lt;br /&gt;DROP TABLE #Account&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This query returns incorrect result. In case of INNER JOINs putting the filter condition on the WHERE clause or ON Clause has the same effect. But in case of OUTER JOINS, it’s a different story. You specify the JOIN Criteria on the ON clause and filter criteria on the WHERE clause. The condition ON the join criteria doesn’t have an impact on the number of rows returned.&lt;br /&gt;&lt;br /&gt;A Select statement works in the following way.&lt;br /&gt;&lt;br /&gt;SELECT&lt;br /&gt;JOIN&lt;br /&gt;WHERE&lt;br /&gt;GROUP BY&lt;br /&gt;HAVING&lt;br /&gt;DISTINCT&lt;br /&gt;ORDER BY&lt;br /&gt;TOP&lt;br /&gt;&lt;br /&gt;(See this &lt;a href="http://tinyurl.com/7523h"&gt;link&lt;/a&gt; for a detailed description by Joe CELKO)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;8. Concatenation And NULL&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;If you are concatenating a field which has a NULL value, the result will be NULL. To avoid this either use ISNULL() function or SET CONCAT_NULL_YIELDS_NULL OFF&lt;br /&gt;&lt;br /&gt;Eg.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Client(ClientID int IDENTITY(1,1), ClientName varchar(30), AnnualIncome int)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-- Populate the client table.&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Prasanth', 10000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Binu', 20000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Shino', NULL)&lt;br /&gt;&lt;br /&gt;SELECT * FROM #Client&lt;br /&gt;&lt;br /&gt;SELECT ClientName + ' - '+ CONVERT(VARCHAR,AnnualIncome) AS [ClientInfo]&lt;br /&gt;FROM #Client&lt;br /&gt;&lt;br /&gt;DROP TABLE #Client&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;9. NULL valued Parameters&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;If the parameter you are passing has a NULL value and even if there is matching records for NULL, the query wont return any rows back.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Client(ClientID int IDENTITY(1,1), ClientName varchar(30), AnnualIncome int)&lt;br /&gt;&lt;br /&gt;CREATE TABLE #Account(AccountId int IDENTITY(1,1), ClientId int, AccountValue int)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--Populate the client table.&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Prasanth', 10000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Binu', 20000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Shino', 30000)&lt;br /&gt;&lt;br /&gt;--Populate the account table&lt;br /&gt;&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(1, 500)&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(2, 1500)&lt;br /&gt;INSERT INTO #Account(ClientId, AccountValue)&lt;br /&gt;VALUES(NULL, 2000)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DECLARE @intClientId int&lt;br /&gt;SET @intClientId = NULL&lt;br /&gt;&lt;br /&gt;SELECT * FROM #Account&lt;br /&gt;WHERE ClientId = @intClientId&lt;br /&gt;&lt;br /&gt;DROP TABLE #Client&lt;br /&gt;DROP TABLE #Account&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;10. Error Handling&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;consider the following example.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Client(ClientID int IDENTITY(1,1), ClientName varchar(30), AnnualIncome int)&lt;br /&gt;&lt;br /&gt;-- Populate the client table.&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Prasanth', 10000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Binu', 20000)&lt;br /&gt;&lt;br /&gt;INSERT INTO #Client(ClientName, AnnualIncome)&lt;br /&gt;VALUES('Shino', 3000)&lt;br /&gt;&lt;br /&gt;--SELECT * FROM #Client&lt;br /&gt;&lt;br /&gt;DECLARE @intVar int&lt;br /&gt;SET @intVar = 0&lt;br /&gt;SELECT AnnualIncome/@intVar AS Something&lt;br /&gt;FROM #Client&lt;br /&gt;&lt;br /&gt;IF @@ERROR &lt;&gt; 0&lt;br /&gt;SELECT @@ERROR&lt;br /&gt;ELSE&lt;br /&gt;SELECT @@ROWCOUNT&lt;br /&gt;&lt;br /&gt;DROP TABLE #Client&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;In both the cases, the Error handling section will not work as expected, because both @@ERROR and @@ROWCOUNT return the status of the last statement executed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112306716205733988?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112306716205733988/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112306716205733988&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112306716205733988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112306716205733988'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/08/common-top-10-t-sql-programming.html' title='Common (TOP 10?) T-SQL Programming mistakes'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112255257201340228</id><published>2005-07-31T14:38:00.000+05:30</published><updated>2005-08-23T15:59:56.820+05:30</updated><title type='text'>SQL Server 2005 Notes</title><content type='html'>&lt;a href="http://toponewithties.blogspot.com/2005/07/top-enhancements.html"&gt;TOP Enhancements&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/07/structured-error-handling.html"&gt;Structured error Handling&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/07/except-and-intersect.html"&gt;Except And Intersect&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/07/how-many-times-you-want-to-go-today.html"&gt;&lt;strike&gt;Where&lt;/strike&gt; How many Times you want to GO Today..! &lt;/a&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/07/some-any-all-are-not-new-features.html"&gt;SOME, ANY, ALL are NOT new Features&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/07/adventureworks.html"&gt;AdventureWorks OLTP Database&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/07/ranking-and-windowing-functions.html"&gt;Ranking and Windowing Functions&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/08/dml-with-output.html"&gt;DML With OUTPUT&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/08/new-apply-operator.html"&gt;New APPLY Operator&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/08/max-sized-datatypes.html"&gt;MAX Sized datatypes&lt;/a&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/08/sampling-using-tablesample.html"&gt;Sampling Using TABLESAMPLE&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112255257201340228?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112255257201340228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112255257201340228&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112255257201340228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112255257201340228'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/07/sql-server-2005-notes.html' title='SQL Server 2005 Notes'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112255236436446479</id><published>2005-07-31T14:00:00.000+05:30</published><updated>2006-03-30T14:48:59.676+05:30</updated><title type='text'>SQL Articles</title><content type='html'>&lt;a href="http://toponewithties.blogspot.com/2006/02/bug-combination-of-group-by-with.html"&gt;BUG: Combination of GROUP BY with HAVING Clause and LEFT OUTER JOIN with Derived Table With LEFT Function Produces Incorrect Result&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2006/02/named-constraints-on-temporary-tables.html"&gt;Named Constraints on Temporary tables&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/08/common-top-10-t-sql-programming.html"&gt;Common (TOP 10?) T-SQL Programming mistakes&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2005/03/path-enumeration-using-prime-number.html"&gt;Path Enumeration Using Prime Number Products&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2004/08/difference-between-table-variable-and.html"&gt;Difference between Table Variable and Temporary Table&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2004/08/difference-between-set-and-select.html"&gt;Difference Between SET and SELECT&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2004/08/let-us-count-them.html"&gt;Let Us Count them!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2004/08/differences-between-coalesce-and.html"&gt;Differences between COALESCE and ISNULL&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://toponewithties.blogspot.com/2004/06/fancy-scoping.html"&gt;Fancy Scoping&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112255236436446479?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112255236436446479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112255236436446479&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112255236436446479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112255236436446479'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/07/sql-articles.html' title='SQL Articles'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112279496066539752</id><published>2005-07-31T12:59:00.000+05:30</published><updated>2005-07-31T13:44:11.236+05:30</updated><title type='text'>Ranking and Windowing Functions</title><content type='html'>&lt;br /&gt;SQL Server 2005 ships with four functions exclusively for ranking and windowing operations. These functions will make the life of tthe T-SQL programmer easy. The following are the four functions.&lt;br /&gt;&lt;br /&gt;1. ROW_NUMBER()&lt;br /&gt;&lt;br /&gt;This function allows you to provide a pseudo column containing sequential integer values to result rows of a query, which makes many tasks like paging easy. Before 2005, to get the same result, you had to write complex queries like,&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;use pubs&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;Select job_desc, (Select Count(*) + 1 FROM jobs B&lt;br /&gt;WHERE B.job_desc &lt; A.job_desc) AS RecNo&lt;br /&gt;FROM jobs A&lt;br /&gt;ORDER By job_desc&lt;br /&gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Lets see how easy its in 2005&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;CREATE TABLE #Students(StudentName VARCHAR(10), subject VARCHAR(10), Mark int)&lt;br /&gt;INSERT INTO #Students VALUES('Jaison','.Net',90)&lt;br /&gt;INSERT INTO #Students VALUES('Senthil','.Net',70)&lt;br /&gt;INSERT INTO #Students VALUES('Joe','.Net',50)&lt;br /&gt;INSERT INTO #Students VALUES('Jaison','SQL',70)&lt;br /&gt;INSERT INTO #Students VALUES('Senthil','SQL',90)&lt;br /&gt;INSERT INTO #Students VALUES('Joe','SQL',80)&lt;br /&gt;&lt;br /&gt;--SELECT * FROM #Students&lt;br /&gt;&lt;br /&gt;SELECT ROW_NUMBER() OVER (ORDER BY Mark DESC) as rownum, * FROM #Students&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;And here is the output.&lt;br /&gt;rownum               StudentName subject    Mark&lt;br /&gt;-------------------- ----------- ---------- -----------&lt;br /&gt;1                    Jaison      .Net       90&lt;br /&gt;2                    Senthil     SQL        90&lt;br /&gt;3                    Joe         SQL        80&lt;br /&gt;4                    Senthil     .Net       70&lt;br /&gt;5                    Jaison      SQL        70&lt;br /&gt;6                    Joe         .Net       50&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Note that in the above example we have 2 ties, for marks 90 and 70.  The  ROW_NUMBER() break ties and assign a unique integer number to each row. If the column specified in the ORDER BY clause is not unique, then the ROW_NUMBER() function is not deterministic. That is the assignment of sequential values for tied rows may vary from execution to execution.&lt;br /&gt;&lt;br /&gt;2. RANK()&lt;br /&gt;The Rank function is similiar to ROW_NUMBER function in the sense that Rank() also produces a ranking column. But the difference is that the Rank function does not break ties. It assigns the same value to the tied rows. Lets see Rank() in action.&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;SELECT RANK() OVER (ORDER BY Mark DESC) as rank, * FROM #Students&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;rank                 StudentName subject    Mark&lt;br /&gt;-------------------- ----------- ---------- -----------&lt;br /&gt;1                    Jaison      .Net       90&lt;br /&gt;1                    Senthil     SQL        90&lt;br /&gt;3                    Joe         SQL        80&lt;br /&gt;3                    Ann         SQL        80&lt;br /&gt;5                    Senthil     .Net       70&lt;br /&gt;5                    Jaison      SQL        70&lt;br /&gt;7                    Joe         .Net       50&lt;br /&gt;&lt;br /&gt;Noe that the result has ties and gaps.&lt;br /&gt;&lt;br /&gt;3. DENSE_RANK()&lt;br /&gt;The DENSE_RANK() function is same as RANK() except that it doesnt leave gaps.&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;SELECT DENSE_RANK() OVER (ORDER BY Mark DESC) as rank, * FROM #Students&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;rank                 StudentName subject    Mark&lt;br /&gt;-------------------- ----------- ---------- -----------&lt;br /&gt;1                    Jaison      .Net       90&lt;br /&gt;1                    Senthil     SQL        90&lt;br /&gt;2                    Joe         SQL        80&lt;br /&gt;2                    Ann         SQL        80&lt;br /&gt;3                    Senthil     .Net       70&lt;br /&gt;3                    Jaison      SQL        70&lt;br /&gt;4                    Joe         .Net       50&lt;br /&gt;&lt;br /&gt;4.NTILE()&lt;br /&gt;&lt;br /&gt;NTile(n) will evenly divide all the results into approximately even pieces based on the input argument,  and assign each piece by the same number in the result set. For eg, if you want to assign grades to students based on their  mark you can use NTILE function like&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;SELECT NTILE(2) OVER (ORDER BY Mark DESC) as grade, * FROM #Students&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;grade                StudentName subject    Mark&lt;br /&gt;-------------------- ----------- ---------- -----------&lt;br /&gt;1                    Jaison      .Net       90&lt;br /&gt;1                    Senthil     SQL        90&lt;br /&gt;1                    Joe         SQL        80&lt;br /&gt;1                    Ann         SQL        80&lt;br /&gt;2                    Senthil     .Net       70&lt;br /&gt;2                    Jaison      SQL        70&lt;br /&gt;2                    Joe         .Net       50&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;PARTITION BY&lt;/b&gt;&lt;br /&gt;Ranking functions can be used for windowing with the PARTITION BY Clause. PARTITION BY clause lets you apply ranking functions for subgroups.  For eg. if you want to get the ranks in the Subject Level, you canget that by using the PARTITION BY clause along with the ORDER BY Clause.&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;SELECT RANK() OVER (PARTITION BY subject ORDER BY Mark DESC) as rank, * FROM #Students&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Here is the result.&lt;br /&gt;&lt;br /&gt;rank                 StudentName subject    Mark&lt;br /&gt;-------------------- ----------- ---------- -----------&lt;br /&gt;1                    Jaison      .Net       90&lt;br /&gt;2                    Senthil     .Net       70&lt;br /&gt;3                    Joe         .Net       50&lt;br /&gt;1                    Senthil     SQL        90&lt;br /&gt;2                    Joe         SQL        80&lt;br /&gt;2                    Ann         SQL        80&lt;br /&gt;4                    Jaison      SQL        70&lt;br /&gt;&lt;br /&gt;You can apply the PARTITION BY Clause on all the ranking functions.&lt;br /&gt;&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace" color="#800000"&gt;&lt;br /&gt;SELECT &lt;br /&gt;	ROW_NUMBER() OVER (PARTITION BY subject ORDER BY Mark DESC) as rownum,&lt;br /&gt;	RANK() OVER (PARTITION BY subject ORDER BY Mark DESC) as rank, &lt;br /&gt;	DENSE_RANK() OVER (PARTITION BY subject ORDER BY Mark DESC) as dese_rank,&lt;br /&gt;	NTILE(3) OVER (PARTITION BY subject ORDER BY Mark DESC) as grade, * FROM #Students&lt;br /&gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Here is the result.&lt;br /&gt;&lt;br /&gt;rownum               rank                 dese_rank            grade                StudentName subject    Mark&lt;br /&gt;-------------------- -------------------- -------------------- -------------------- ----------- ---------- -----------&lt;br /&gt;1                    1                    1                    1                    Jaison      .Net       90&lt;br /&gt;2                    2                    2                    2                    Senthil     .Net       70&lt;br /&gt;3                    3                    3                    3                    Joe         .Net       50&lt;br /&gt;1                    1                    1                    1                    Senthil     SQL        90&lt;br /&gt;2                    2                    2                    1                    Joe         SQL        80&lt;br /&gt;3                    2                    2                    2                    Ann         SQL        80&lt;br /&gt;4                    4                    3                    3                    Jaison      SQL        70&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;For more info on ranking functions, see these articles(&lt;a href="http://www.windowsitpro.com/Windows/Articles/ArticleID/42302/pg/2/2.html" target="_blank"&gt;1&lt;/a&gt;, &lt;a href="http://www.windowsitpro.com/SQLServer/Articles/ArticleID/42646/pg/2/2.html" target="_blank"&gt;2&lt;/a&gt;) by SQL MVP Itzik Ben Gan.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112279496066539752?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112279496066539752/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112279496066539752&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112279496066539752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112279496066539752'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/07/ranking-and-windowing-functions.html' title='Ranking and Windowing Functions'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112271008356806552</id><published>2005-07-30T13:24:00.000+05:30</published><updated>2005-07-31T13:32:16.586+05:30</updated><title type='text'>AdventureWorks</title><content type='html'>The samples used in these notes use the new AdventureWorks database. You can download the adventureworks databas diagram from &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=0f6e0bcf-a1b5-4760-8d79-67970f93d5ff&amp;amp;displaylang=en" target="_blank"&gt;this link.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112271008356806552?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112271008356806552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112271008356806552&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112271008356806552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112271008356806552'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/07/adventureworks.html' title='AdventureWorks'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112263146491635287</id><published>2005-07-29T15:34:00.000+05:30</published><updated>2005-07-29T15:41:03.870+05:30</updated><title type='text'>SOME, ANY, ALL are NOT new Features</title><content type='html'>This more of a Whats not new rather than Whats NEW.&lt;br /&gt;&lt;br /&gt;I had seen many authentic links like &lt;a href="http://www.qssug.org/SQL2005Developer.ppt" target="_blank"&gt;this &lt;/a&gt;and even the book &lt;a href="http://xmlwriter.net/books/viewbook/Introducing_Microsoft__SQL_Server(TM)_2005_for_Developers_(Pro___Developer)-073561962X.html" target="_blank"&gt;Introducing Microsoft SQL Server(TM) 2005 for Developers&lt;/a&gt; saying that SOME, ANY, ALL are new T-SQL extensions in SQL Server 2005. But the fact is that they are present in SQL Server 200 also.&lt;br /&gt;&lt;br /&gt;See the below code samples, executed from Query Analyser, using the pubs database, in SQL Server 2000&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;USE PUBS&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;SELECT * FROM Titles WHERE Type = 'business'&lt;br /&gt;AND price &gt; SOME(SELECT Price FROM Titles WHERE Type = 'psychology')&lt;br /&gt;&lt;br /&gt;SELECT * FROM Titles WHERE Type = 'business'&lt;br /&gt;AND price &gt; ANY(SELECT Price FROM Titles WHERE Type = 'psychology')&lt;br /&gt;&lt;br /&gt;SELECT * FROM Titles WHERE Type = 'business'&lt;br /&gt;AND price &gt; ALL(SELECT Price FROM Titles WHERE Type = 'psychology')&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112263146491635287?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112263146491635287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112263146491635287&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112263146491635287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112263146491635287'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/07/some-any-all-are-not-new-features.html' title='SOME, ANY, ALL are NOT new Features'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112263037088958376</id><published>2005-07-28T15:16:00.000+05:30</published><updated>2005-07-29T15:17:07.210+05:30</updated><title type='text'>How Many Times you want To GO Today</title><content type='html'>&lt;strike&gt;Where &lt;/strike&gt;How Many Times you want To GO Today !&lt;br /&gt;&lt;br /&gt;This is about a really INTERESTING SQL server 2005 feature.&lt;br /&gt;&lt;br /&gt;You can execute a transact sql batch any number of times just by Giving the number with GO.&lt;br /&gt;&lt;br /&gt;See Go in action here&lt;br /&gt;&lt;br /&gt;PRINT 'Hai.. How many times you expect to see this message..?'&lt;br /&gt;GO 10&lt;br /&gt;&lt;br /&gt;And here is the output.&lt;br /&gt;&lt;br /&gt;Beginning execution loop&lt;br /&gt;Hai.. How many times you expect to see this message..?&lt;br /&gt;Hai.. How many times you expect to see this message..?&lt;br /&gt;Hai.. How many times you expect to see this message..?&lt;br /&gt;Hai.. How many times you expect to see this message..?&lt;br /&gt;Hai.. How many times you expect to see this message..?&lt;br /&gt;Hai.. How many times you expect to see this message..?&lt;br /&gt;Hai.. How many times you expect to see this message..?&lt;br /&gt;Hai.. How many times you expect to see this message..?&lt;br /&gt;Hai.. How many times you expect to see this message..?&lt;br /&gt;Hai.. How many times you expect to see this message..?&lt;br /&gt;Batch execution completed 10 times.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thats &lt;a href="http://en.wikipedia.org/wiki/Cool" target="_blank"&gt;COOL &lt;/a&gt;right?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112263037088958376?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112263037088958376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112263037088958376&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112263037088958376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112263037088958376'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/07/how-many-times-you-want-to-go-today.html' title='How Many Times you want To GO Today'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112255501036480698</id><published>2005-07-27T17:43:00.000+05:30</published><updated>2005-07-28T18:21:59.860+05:30</updated><title type='text'>TOP Enhancements</title><content type='html'>Okay, Lets start at the Top. (Afterall this blog is named TopOneWithTies.) The Good news is that, in SQL Server 2005, you can specify a variable as the argument for the Top clause. Wait, not just a variable, you can specify a sub query or a UDF as an argument for the TOP clause.&lt;br /&gt;&lt;br /&gt;Also you can specify the TOP clause NOT just with the select, but also with INSERT, DELETE and UPDATE.&lt;br /&gt;&lt;br /&gt;Sounds great right!. Lets see TOP in action.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color:#660000;"&gt;USE AdventureWorks&lt;br /&gt;GO&lt;br /&gt;DECLARE @n int&lt;br /&gt;SET @n = 5&lt;br /&gt;SELECT TOP(@n) * FROM Sales.SalesOrderHeader&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Now lets try to use a User Defined function as the input for TOP.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color:#660000;"&gt;CREATE FUNCTION dbo.MyFunc()&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#660000;"&gt;RETURNS INT&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#660000;"&gt;AS &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#660000;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#660000;"&gt;RETURN 3&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#660000;"&gt;END&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#660000;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#660000;"&gt;SELECT TOP(dbo.MyFunc()) * FROM Sales.SalesOrderHeader&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And a subquery,&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color:#660000;"&gt;SELECT TOP ((SELECT COUNT(*) FROM Production.Product)) * FROM Sales.SalesOrderHeader&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Now lets try to run some INSERT, UPDATE, DELTE Statements with the TOP Clause.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #TopSales(SalesOrderId int, OrderDate datetime)&lt;br /&gt;&lt;br /&gt;INSERT TOP (5) INTO #TopSales&lt;br /&gt;SELECT SalesOrderId, OrderDate&lt;br /&gt;FROM Sales.SalesOrderHeader&lt;br /&gt;ORDER By TotalDue DESC&lt;br /&gt;&lt;br /&gt;SELECT * FROM #TopSales&lt;br /&gt;&lt;br /&gt;UPDATE TOP (2) #TopSales&lt;br /&gt;SET OrderDate = OrderDate +1&lt;br /&gt;&lt;br /&gt;SELECT * FROM #TopSales&lt;br /&gt;&lt;br /&gt;DELETE TOP (2) FROM #TopSales&lt;br /&gt;&lt;br /&gt;SELECT * FROM #TopSales&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Note that in case of UPDATE and DELETE you cannot specify an ORDER BY Clause (It seems).&lt;br /&gt;So use this option carefully (for eg. Splitting the update of large no of rows into batches) as you cannot predict which rows will get affected. (I may have to do some further research on this)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112255501036480698?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112255501036480698/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112255501036480698&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112255501036480698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112255501036480698'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/07/top-enhancements.html' title='TOP Enhancements'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112262976016034029</id><published>2005-07-27T15:06:00.000+05:30</published><updated>2005-07-29T15:07:37.426+05:30</updated><title type='text'>EXCEPT AND INTERSECT</title><content type='html'>It was a common question in SQL server newsgroups that how one can implement EXCEPT and INTERSECT set operations in T-SQL. The answer is, When NULLs are not involved, you can achieve the INTERSECT effect by using INNER JOIN and except effect using NOT EXISTS or LEFT JOIN with a NULL check.&lt;br /&gt;&lt;br /&gt;But When NULLS are present in data, the above methods will fail because, INTERSECT treats NULLs as equal for matching rows. &lt;a href="http://tinyurl.com/55pq5" target="_blank"&gt;This NG thread&lt;/a&gt; by SQL MVP David Portas discuss some some full equivalents. Also, SQL MVP Itzik Ben Gan has an excellent article on &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsqlmag03/html/Set-OperationAlternatives.asp" target="_blank"&gt;Mimicking INTERSECT and EXCEPT in T-SQL&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;But those are the days when EXCEPT and INTERSECT were not part of the T-SQL. SQL Sever 2005 adds both these set operators to the language, to make it more powerful.&lt;br /&gt;&lt;br /&gt;See&lt;a href="http://ioc.unesco.org/oceanteacher/resourcekit/Module2/Database/DBMS/relational_operations.html" target="_blank"&gt; this link&lt;/a&gt; for for a list of Relational Operators&lt;br /&gt;&lt;br /&gt;&lt;b&gt;INTERSECT&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;INTERSECT is one of the the basic relational operators. INTERSECT works on two sets. It returns rows exists in both sets eliminating duplicates.&lt;br /&gt;&lt;br /&gt;INTERSECT ALL also returns rows existis in both the inputs, but if a row repeat n times in the first input and m times in the second input, then the output will contain n or m number of the same row, whichever is less.&lt;br /&gt;Note that both the set should be UNION compatible, that is the number of columns should be same etc..&lt;br /&gt;&lt;br /&gt;The ALL version of the INTERSECT is NOT Currently supported in SQL Server 2005.&lt;br /&gt;&lt;br /&gt;Enough theory, its time to see the new INTERSECT Operator in action&lt;br /&gt;&lt;br /&gt;CREATE TABLE #Skills(Programmer VARCHAR(20), Skill CHAR(3))&lt;br /&gt;&lt;br /&gt;INSERT INTO #Skills VALUES('Jaison','NET')&lt;br /&gt;INSERT INTO #Skills VALUES('Roji','NET')&lt;br /&gt;INSERT INTO #Skills VALUES('Roji','SQL')&lt;br /&gt;INSERT INTO #Skills VALUES('Srinivas','SQL')&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT * FROM #Skills&lt;br /&gt;&lt;br /&gt;Lets get the list of Programmers who has both SQL server and .Net skills&lt;br /&gt;&lt;br /&gt;SELECT Programmer FROM #Skills WHERE Skill='NET'&lt;br /&gt;INTERSECT&lt;br /&gt;SELECT Programmer FROM #Skills WHERE Skill='SQL'&lt;br /&gt;&lt;br /&gt;Here is the output&lt;br /&gt;&lt;br /&gt;Programmer&lt;br /&gt;--------------------&lt;br /&gt;Roji&lt;br /&gt;&lt;br /&gt;(1 row(s) affected)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;EXCEPT&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;EXCEPT, also called MINUS returns DISTINCT rows from the LEFT input, which is not present in the RIGHT input.&lt;br /&gt;With EXCEPT ALL, if a row appears more times in the LEFT set than the RIGHT set, then the row will appear in the output n number of times, where n is the number of times the row appear in the left set minus the number of times the row appears in the right set. The ALL version of the EXCEPT is NOT Currently supported in SQL Server 2005.&lt;br /&gt;&lt;br /&gt;Here is the EXCEPT version of our above query&lt;br /&gt;&lt;br /&gt;Lets get the list of programmers who knows .NEt, but doesnt know SQL.&lt;br /&gt;&lt;br /&gt;SELECT Programmer FROM #Skills WHERE Skill='NET'&lt;br /&gt;EXCEPT&lt;br /&gt;SELECT Programmer FROM #Skills WHERE Skill='SQL'&lt;br /&gt;&lt;br /&gt;Here is the output.&lt;br /&gt;&lt;br /&gt;Programmer&lt;br /&gt;--------------------&lt;br /&gt;Jaison&lt;br /&gt;&lt;br /&gt;(1 row(s) affected)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112262976016034029?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112262976016034029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112262976016034029&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112262976016034029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112262976016034029'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/07/except-and-intersect.html' title='EXCEPT AND INTERSECT'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-112255997762449923</id><published>2005-07-26T19:34:00.000+05:30</published><updated>2005-07-28T19:46:40.126+05:30</updated><title type='text'>Structured Error handling</title><content type='html'>Its time to to forget the @@Error Global variable. SQL Server 2005 Provides you the power of structured Error handling as you do in any .Net Language, Which eliminates the need for checking IF @@ERROR &gt; 0 ...&lt;br /&gt;&lt;br /&gt;Now lets just create a table&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #Student(StudentID int PRIMARY KEY, StudentName VARCHAR(50))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And try the following.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;BEGIN TRY &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;INSERT INTO #Student(StudentId, StudentName) VALUES(1, 'Roji. P. Thomas') &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;PRINT 'Successfully Inserted'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;END TRY&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;BEGIN CATCH &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;PRINT 'Insert Failed'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;END CATCH&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When you run the above code for the first time you will get the message 'Successfully Inserted'. When you try the code for the second time, You will get the message saying 'Insert failed', which means that our Catch block executed.&lt;br /&gt;&lt;br /&gt;You can see that, when a statement within the TRY block fails, control is passed to the first statement within the catch block.&lt;br /&gt;&lt;br /&gt;In the catch block you can use the new ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_SEVERITY() and ERROR_STATE() functions to get the details of the error. For eg. you can modify the above code as follows to get the details of the Error.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;BEGIN TRY &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;INSERT INTO #Student(StudentId, StudentName) VALUES(1, 'Roji. P. Thomas') &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;PRINT 'Successfully Inserted'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;END TRY&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;BEGIN CATCH &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;PRINT 'Insert Failed' &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;PRINT ERROR_NUMBER() &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;PRINT ERROR_MESSAGE() &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;PRINT ERROR_SEVERITY() &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;PRINT ERROR_STATE()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;END CATCH&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;TRANSACTIONS and Error Handling&lt;/strong&gt;&lt;br /&gt;The new XACT_State function will come handy when you are using explicit transactions in the Try block. The XACT_STATE() function returns the transaction state. The possible values are -1,0 and 1.&lt;br /&gt;&lt;br /&gt;-1 : Means that a transaction is open, but in a doomed (uncommitable) state. This typically happens when an error occutred, which has a severity level higher than 17.&lt;br /&gt;0 : No transactions are open&lt;br /&gt;1 : a transaction is open and commitable.&lt;br /&gt;&lt;br /&gt;The following code shows the usage of XACT_STATE() function.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;BEGIN TRY&lt;br /&gt;BEGIN TRAN&lt;br /&gt;INSERT INTO #Student(StudentId, StudentName) VALUES(1, 'Roji. P. Thomas')&lt;br /&gt;PRINT 'Successfully Inserted'&lt;br /&gt;COMMIT TRAN&lt;br /&gt;END TRY&lt;br /&gt;BEGIN CATCH&lt;br /&gt;PRINT XACT_STATE()&lt;br /&gt;ROLLBACK TRAN&lt;br /&gt;PRINT XACT_STATE()&lt;br /&gt;PRINT 'Insert Failed'&lt;br /&gt;PRINT ERROR_NUMBER()&lt;br /&gt;PRINT ERROR_MESSAGE()&lt;br /&gt;PRINT ERROR_SEVERITY()&lt;br /&gt;PRINT ERROR_STATE()&lt;br /&gt;END CATCH&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Note that the error will not be propogated to the application from the try block, unless you explicitly throw the error using RAISERROR, as in the following code segment.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;BEGIN TRY&lt;br /&gt;BEGIN TRAN&lt;br /&gt;INSERT INTO #Student(StudentId, StudentName)&lt;br /&gt;VALUES(1, 'Roji. P. Thomas')&lt;br /&gt;PRINT 'Successfully Inserted'&lt;br /&gt;COMMIT TRAN&lt;br /&gt;END TRY&lt;br /&gt;BEGIN CATCH&lt;br /&gt;RAISERROR('Insert Failed',16,1)&lt;br /&gt;END CATCH&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;For more information see the following MSDN article.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsql90/html/sql_05TSQLEnhance.asp"&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsql90/html/sql_05TSQLEnhance.asp&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-112255997762449923?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/112255997762449923/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=112255997762449923&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112255997762449923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/112255997762449923'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/07/structured-error-handling.html' title='Structured Error handling'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-111078532461081661</id><published>2005-03-14T12:58:00.000+05:30</published><updated>2006-04-06T17:10:20.906+05:30</updated><title type='text'>Path Enumeration using Prime Number Products</title><content type='html'>Managing Hierarchies in Relational Database Environment is always a challenging task. Over the years many models like Adjacency List Model, &lt;a href="http://www.developersdex.com/gurus/articles/112.asp" target="_blank"&gt;Nested Set Model&lt;/a&gt;, &lt;a href="http://dbazine.com/tropashko4.shtml" target="_blank"&gt;Nested Interval Model&lt;/a&gt;, &lt;a href="http://www.onlamp.com/pub/a/onlamp/2004/08/05/hierarchical_sql.html" target="_blank"&gt;Path Enumeration Model&lt;/a&gt; etc. were proposed and implemented. There are also &lt;a href="http://www.windowsitpro.com/Articles/Print.cfm?ArticleID=16123" target="_blank"&gt;other&lt;/a&gt; popular methods using recursion and user defined function. &lt;a href="http://www.sqlservercentral.com/columnists/sSampath/recursivequeriesinsqlserver2005.asp" target="_blank"&gt;SQL Server 2005 T-SQL Extensions&lt;/a&gt; has special operators for managing recursive queries. Joe CELKO has written a &lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/1558609202/ref=pd_sim_b_2/103-8718663-9878203?%5Fencoding=UTF8&amp;amp;v=glance" target="_blank"&gt;book &lt;/a&gt;exclusively on Managing Trees and Hierarchies.&lt;br /&gt;&lt;br /&gt;The basic Hierarchical operations in a typical Employee-Manager type of relation, include&lt;br /&gt;&lt;br /&gt;1. Add a new Employee&lt;br /&gt;2. Show the whole Hierarchy with levels.&lt;br /&gt;3. Show the superiors of a given employee.&lt;br /&gt;4. Show the subordinates of a given employee.&lt;br /&gt;5. Show the immediate subordinates of a given employee.&lt;br /&gt;6. List all the Leaf Level Employees.&lt;br /&gt;7. Change the manager of an Employee&lt;br /&gt;8. Delete an Employee and all his subordiantes.&lt;br /&gt;9. Delete an Employee.&lt;br /&gt;&lt;br /&gt;Here I am trying to propose a simple model which works almost like Path Enumeration model. This model uses a&lt;b&gt; Prime Number&lt;/b&gt; table and basic mathematical operations to answer the above questions. Also the Model only uses set based solutions and can be implemented as a self managing system with the help of triggers.&lt;br /&gt;&lt;br /&gt;This model works on two basic concepts.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. There is a unique path to every node in a hierarchy from the root node.&lt;br /&gt;2. The Prime Number that can be a divisor of the Product of a set of Prime Numbers, are only the Prime numbers in the set.&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;That is, Let product of n prime numbers be Px, then, the factors of Px can only be the Prime Numbers that participated in the multiplication, or the sub products.&lt;br /&gt;So the product cannot be divided by any other Prime Number.&lt;br /&gt;&lt;br /&gt;For eg.&lt;br /&gt;&lt;br /&gt;P1, P2, P3,...Pn is the list of Prime Numbers.&lt;br /&gt;&lt;br /&gt;Let P be the Product.&lt;br /&gt;&lt;br /&gt;Then P1 * P2 * P3 * ... * Pn = P&lt;br /&gt;&lt;br /&gt;Then the factors of P can be either P1, P2, P3,...Pn Or the sub product of P1, P2, P3,...Pn.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now let's try to answer the above questions.&lt;br /&gt;&lt;br /&gt;The following is the &lt;a href="http://toponewithties.blogspot.com/2005/03/emphierarchy-table-script-this-is.html" target="_blank"&gt;table&lt;/a&gt; used in the examples.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;CREATE TABLE dbo.EmpHierarchy&lt;br /&gt;(EmpId int PRIMARY KEY,&lt;br /&gt;EmpName VARCHAR(15),&lt;br /&gt;ManagerId int,&lt;br /&gt;HKey bigint UNIQUE,&lt;br /&gt;Path bigint)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;The purpose of the first three columns are obvious. The column Hkey is a Unique Prime Number assigned to each employee. The column Path Holds the product of the Hkey values of the current node and nodes above the current node.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://toponewithties.blogspot.com/2005/03/prime-numbers-table-and-insert-script.html" target="_blank"&gt;script&lt;/a&gt; used for creating and Populating the PrimeNumber table is here.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Add a new Employee&lt;/b&gt;&lt;br /&gt;For inserting a new node (employee), we will get the least available Prime Number and use it as the Hkey of the node. The Path will be the Product of the Hkey and the Path of the parent node. For the root level entry the path will be the Hkey itself.&lt;br /&gt;&lt;br /&gt;Here is the script for the stored procedure &lt;a href="http://toponewithties.blogspot.com/2005/03/insert-node-stored-procedure-for.html" target="_blank"&gt;dbo.InsertNode&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now lets insert some sample data.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.InsertNode 1,'Albert', NULL&lt;br /&gt;EXEC dbo.InsertNode 2,'Bert', 1&lt;br /&gt;EXEC dbo.InsertNode 3,'Chuck', 1&lt;br /&gt;EXEC dbo.InsertNode 4,'Dona', 3&lt;br /&gt;EXEC dbo.InsertNode 5,'Eddie', 3&lt;br /&gt;EXEC dbo.InsertNode 6,'Fred', 3&lt;br /&gt;&lt;br /&gt;SELECT * FROM EmpHierarchy&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Now we have this data in the table.&lt;br /&gt;&lt;br /&gt;&lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;EmpId&lt;/td&gt;&lt;td&gt;EmpName&lt;/td&gt;&lt;td&gt;ManagerId&lt;/td&gt;&lt;td&gt;HKey&lt;/td&gt;&lt;td&gt;Path&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Dona&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;70&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Eddie&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;110&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;Fred&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;13&lt;/td&gt;&lt;td&gt;130&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;2. Show the whole Hierarchy with levels.&lt;/b&gt;&lt;br /&gt;The level of a node in a hierarchy depends on the number of levels above it. So the level of a given node can be found by counting the levels above it. Thats the technique used in the stored procedure &lt;a href="http://toponewithties.blogspot.com/2005/03/print-hierarchy-print-hierarchy-with.html" target="_blank"&gt;dbo.PrintHierarchy&lt;/a&gt;. The SP also accepts an EmployeeId, to display a partial hierarchy.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.PrintHierarchy&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here is the output&lt;br /&gt;&lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Hierarchy&lt;/td&gt;&lt;td&gt;Level&lt;/td&gt;&lt;td&gt;Employee&lt;/td&gt;&lt;td&gt;Manager&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Dona&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Eddie&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Fred&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;3. Show the superiors of a given employee.&lt;/b&gt;&lt;br /&gt;The path of a given employee is the product of the Hkeys of his superiors and his Hkey. As per our rule the path can be divided only by the Prime Numbers participated in it. Based on that finding the superiors logic is failrly easy. You can get the list of the superios of a given employee by&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;SELECT A.EmpId, A.EmpName&lt;br /&gt;FROM EmpHierarchy A&lt;br /&gt;WHERE [Path of the given Employee] % A.Hkey = 0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have this Stored Procedure &lt;a href="http://toponewithties.blogspot.com/2005/03/list-of-superiors-get-list-of.html" target="_blank"&gt;dbo.getSuperiors&lt;/a&gt; which accepts an Employee Id and return the list of his superiors.&lt;br /&gt;&lt;br /&gt;To get the Superiors of 'Fred', execute&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo. getSuperiors 6&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here is the output&lt;br /&gt;&lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;EmpId&lt;/td&gt;&lt;td&gt;Employee&lt;/td&gt;&lt;td&gt;Manager&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;Fred&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;4. Show the subordinates of a given employee.&lt;/b&gt;&lt;br /&gt;The Hkey of a given employee will be a factor of the Path of all his subordinates and only his subordinates.&lt;br /&gt;So to get the list of the subordinates of an employee, you can run a query like&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;SELECT A.EmpId, A.EmpName AS Employee&lt;br /&gt;FROM EmpHierarchy A&lt;br /&gt;WHERE A.Path % [HKey of the given Employee] = 0&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Here is the stored procedure &lt;a href="http://toponewithties.blogspot.com/2005/03/list-of-subordinates-get-list-of.html" target="_blank"&gt;dbo. getSubordinates&lt;/a&gt; for doing the same.&lt;br /&gt;&lt;br /&gt;Now to get the list of subordiantes of 'Chuck', execute&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo. getSubordinates 3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here is the output&lt;br /&gt;&lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;EmpId&lt;/td&gt;&lt;td&gt;Employee&lt;/td&gt;&lt;td&gt;Manager&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Dona&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Eddie&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;Fred&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;5. Show the immediate subordinates of a given employee.&lt;/b&gt;&lt;br /&gt;The path of the immediate subordiantes of a given employee will be the product of the path of the manager and the HKey of the subordinate.&lt;br /&gt;So one can find the immediate subordinates of a given employee by writing a query like&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;SELECT EmpId, EmpName&lt;br /&gt;FROM EmpHierarchy&lt;br /&gt;WHERE Path = HKey * [Path of the Given Employee]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;For eg, to get All the immediate subordinates of Albert, the query will be&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;SELECT EmpId, EmpName&lt;br /&gt;FROM EmpHierarchy&lt;br /&gt;WHERE Path = HKey *2 --Path of Albert&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Here is the output&lt;br /&gt;&lt;br /&gt;&lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;EmpId&lt;/td&gt;&lt;td&gt;EmpName&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;6. List all the Leaf Level Employees.&lt;/b&gt;&lt;br /&gt;Leaf level employees are those who dont have any subordinates. So finding them is a trivial task.&lt;br /&gt;The following query gives you the list of leaf level employees.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;SELECT EmpId, EmpName&lt;br /&gt;FROM EmpHierarchy A&lt;br /&gt;WHERE NOT Exists(SELECT 1 FROM EmpHierarchy T&lt;br /&gt;WHERE T.Path % A.Hkey = 0&lt;br /&gt;AND T.Path &gt; A.Path)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;And here is the output.&lt;br /&gt;&lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;EmpId&lt;/td&gt;&lt;td&gt;EmpName&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Dona&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Eddie&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;Fred&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;7. Change the manager of an Employee&lt;/b&gt;&lt;br /&gt;Updating can be of two types, promotion and demotion. When updating an Employees manager, you need to update the rows of the given employee and all his subordinates Path. Also you need to perform some validation to avoid cyclic reference. Here is the stored Procedure &lt;a href="http://toponewithties.blogspot.com/2005/03/update-node-update-employee-with-new.html" target="_blank"&gt;dbo.UpdateNode&lt;/a&gt; to update a given node.&lt;br /&gt;&lt;br /&gt;So now to change Fred's Manager to Bert from Chuck, you can Execute&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.UpdateNode EmployeeId, NewManagerId&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.UpdateNode 6, 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After the update, the hierarchy will look like&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.PrintHierarchy&lt;/span&gt;&lt;br /&gt;&lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Hierarchy&lt;/td&gt;&lt;td&gt;Level&lt;/td&gt;&lt;td&gt;Employee&lt;/td&gt;&lt;td&gt;Manager&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Dona&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Eddie&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Fred&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Now, lets try a promotion. Eddie directly reports to Albert instead of Chuck&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.UpdateNode 5, 1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is how the hierarchy will look like now.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.PrintHierarchy&lt;/span&gt;&lt;br /&gt;&lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Hierarchy&lt;/td&gt;&lt;td&gt;Level&lt;/td&gt;&lt;td&gt;Employee&lt;/td&gt;&lt;td&gt;Manager&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Eddie&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Fred&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Dona&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Finally lets demote chuck one level down the hierarchy. Instead of reporting to Albert, he will now report to Bert&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.UpdateNode 3, 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.PrintHierarchy&lt;/span&gt;&lt;br /&gt;&lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Hierarchy&lt;/td&gt;&lt;td&gt;Level&lt;/td&gt;&lt;td&gt;Employee&lt;/td&gt;&lt;td&gt;Manager&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Eddie&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Fred&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;----&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Dona&lt;/td&gt;&lt;td&gt;Chuck&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;8. Delete an Employee and all his subordiantes.&lt;/b&gt;&lt;br /&gt;Deleting a subtree is fairly easy. we can use the same logic of finding subordinates and apply that in the where clause.&lt;br /&gt;Here is the stored procedure &lt;a href="http://toponewithties.blogspot.com/2005/03/delete-subtree-delete-subtree-from.html" target="_blank"&gt;dbo.deleteSubTree&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now to fire the whole team of Chuck, you can execute&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.deleteSubTree 3 --EmployeeId of chuck&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After the deletion, the Hierarchy will look like&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.PrintHierarchy&lt;/span&gt;&lt;br /&gt;&lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Hierarchy&lt;/td&gt;&lt;td&gt;Level&lt;/td&gt;&lt;td&gt;Employee&lt;/td&gt;&lt;td&gt;Manager&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Eddie&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;---&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Fred&lt;/td&gt;&lt;td&gt;Bert&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;strong&gt;9. Delete an Employee.&lt;br /&gt;&lt;/strong&gt;This can be more tricky, because when you delete an Employee, If he has subordinates, the hierarchy will be broken. So all the subordinates of the deleted employee should report to the Manager of the deleted employee. Here is the Stored Procedure &lt;a href="http://toponewithties.blogspot.com/2005/03/delete-single-node-delete-given-node.html" target="_blank"&gt;dbo.deleteNode&lt;/a&gt;, which takes care of it.&lt;br /&gt;&lt;br /&gt;So Now lets try deleting Bert.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;EXEC dbo.deleteNode 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After the deletion, the hierarchy will look like &lt;table bgcolor="#cccccf" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Hierarchy&lt;/td&gt;&lt;td&gt;Level&lt;/td&gt;&lt;td&gt;Employee&lt;/td&gt;&lt;td&gt;Manager&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Eddie&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Fred&lt;/td&gt;&lt;td&gt;Albert&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;And thats it :)&lt;br /&gt;&lt;br /&gt;These are the pro's and con's of the model from my point of view.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Pros&lt;/b&gt;&lt;br /&gt;1. Use only standard SQL constructs.&lt;br /&gt;2. Use only set based solutions.&lt;br /&gt;3. Can be implemented as self manageable using triggers.&lt;br /&gt;4. Gives better performance because it uses Numeric operations instead of string operations.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Cons&lt;/b&gt;&lt;br /&gt;1. For larger Hierarchies, you may encounter out of range errors because the Path value grows in an exponential rate.&lt;br /&gt;Still you can replace the bigint with a larger datatype like numeric and replace the % operator with division operator and overcome the issue.&lt;br /&gt;&lt;br /&gt;AS I mentioned earlier, this model is still in its evolving face. So as always, your feedback is highly appreciated.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-111078532461081661?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/111078532461081661/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=111078532461081661&amp;isPopup=true' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078532461081661'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078532461081661'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/03/path-enumeration-using-prime-number.html' title='Path Enumeration using Prime Number Products'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-111078204925910162</id><published>2005-03-14T12:57:00.000+05:30</published><updated>2005-03-14T13:25:04.440+05:30</updated><title type='text'></title><content type='html'>&lt;b&gt;EmpHierarchy Table Script&lt;/b&gt;&lt;br /&gt;This is the table script used in the examples for Path enumeration using Prime Number Products.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;CREATE TABLE dbo.EmpHierarchy(EmpId int PRIMARY KEY,&lt;br /&gt;EmpName VARCHAR(50),&lt;br /&gt;ManagerId int,&lt;br /&gt;HKey bigint UNIQUE,&lt;br /&gt;Path bigint)&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-111078204925910162?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/111078204925910162/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=111078204925910162&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078204925910162'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078204925910162'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/03/emphierarchy-table-script-this-is.html' title=''/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-111078243767728351</id><published>2005-03-14T12:56:00.000+05:30</published><updated>2005-03-14T13:41:15.113+05:30</updated><title type='text'></title><content type='html'>&lt;b&gt;Prime Numbers table and Insert Script&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Here is the script to create the Prime Numbers table and populate the first 1000 Prime numbers.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;CREATE TABLE dbo.PrimeNumbers(Number bigint PRIMARY KEY)&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;--Insert First 1000 Prime Numbers&lt;br /&gt;&lt;br /&gt;DECLARE @num bigint&lt;br /&gt;DECLARE @cnt int&lt;br /&gt;DECLARE @isPrime bit&lt;br /&gt;DECLARE @nsqrt int&lt;br /&gt;DECLARE @divisor int&lt;br /&gt;&lt;br /&gt;INSERT INTO PrimeNumbers VALUES(2) -- First Prime Number&lt;br /&gt;&lt;br /&gt;SET @num = 3 --Next Prime Number&lt;br /&gt;SET @cnt = 1 --One row already inserted.&lt;br /&gt;&lt;br /&gt;WHILE @cnt &lt;&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;BEGIN &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;SET @isPrime = 1 -- Be Optimistic ;) &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;SET @nsqrt = FLOOR(SQRT(@num)) &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;SET @divisor = 3 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;WHILE @divisor &lt;= @nsqrt &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;BEGIN &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;   IF @num % @divisor = 0 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;   BEGIN &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;     SET @isPrime = 0 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;     BREAK &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;   END &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;   SET @divisor = @divisor + 2 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;END &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;IF @isPrime = 1 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;BEGIN &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;   SET @cnt = @cnt + 1 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;   INSERT INTO PrimeNumbers VALUES(@num) &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;END &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;SET @num = @num+2 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;END &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;--SELECT * FROM PrimeNumbers &lt;/span&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-111078243767728351?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/111078243767728351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=111078243767728351&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078243767728351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078243767728351'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/03/prime-numbers-table-and-insert-script.html' title=''/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-111078278394109486</id><published>2005-03-14T12:55:00.000+05:30</published><updated>2005-03-16T11:02:33.860+05:30</updated><title type='text'></title><content type='html'>&lt;strong&gt;Insert Node&lt;/strong&gt;&lt;br /&gt;Stored Procedure for Inserting a new Employee&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;&lt;br /&gt;/*&lt;br /&gt;Inserts a new Employee into the table&lt;br /&gt;*/&lt;br /&gt;CREATE PROC dbo.InsertNode&lt;br /&gt;(@empid int,&lt;br /&gt;@empName VARCHAR(50),&lt;br /&gt;@MgrId int)&lt;br /&gt;AS&lt;br /&gt;&lt;br /&gt;BEGIN&lt;br /&gt;DECLARE @Hkey int&lt;br /&gt;DECLARE @PathVal Numeric(32,0)&lt;br /&gt;&lt;br /&gt;BEGIN TRAN&lt;br /&gt;&lt;br /&gt;--Get the next Prime Number&lt;br /&gt;SELECT @Hkey = Min(Number) FROM PrimeNumbers&lt;br /&gt;WHERE Number &gt; (SELECT ISNULL(Max(Hkey),0) FROM EmpHierarchy)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;IF @MgrID IS NULL OR @MgrId = @EmpId --Root Node&lt;br /&gt;SET @PathVal = @Hkey&lt;br /&gt;ELSE --Get Managers Path and Calculate the path of the new node&lt;br /&gt;SELECT @PathVal = Path * @Hkey FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @MgrId&lt;br /&gt;&lt;br /&gt;INSERT INTO EmpHierarchy&lt;br /&gt;VALUES(@empid, @empName, @MgrId,@Hkey, @PathVal)&lt;br /&gt;&lt;br /&gt;IF @@ERROR &lt;&gt; 0&lt;br /&gt;ROLLBACK TRAN&lt;br /&gt;ELSE&lt;br /&gt;COMMIT TRAN&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-111078278394109486?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/111078278394109486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=111078278394109486&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078278394109486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078278394109486'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/03/insert-node-stored-procedure-for.html' title=''/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-111078299038850949</id><published>2005-03-14T12:54:00.000+05:30</published><updated>2005-03-16T11:03:09.566+05:30</updated><title type='text'></title><content type='html'>&lt;b&gt;Print Hierarchy&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;&lt;br /&gt;/*&lt;br /&gt;Print Hierarchy with Graphical representation of the Level&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;CREATE PROC dbo.PrintHierarchy&lt;br /&gt;@EmpID as bigint = 1&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;SET NOCOUNT ON&lt;br /&gt;DECLARE @PathVal as bigint&lt;br /&gt;SELECT @PathVal = Path FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @EmpID&lt;br /&gt;&lt;br /&gt;SELECT REPLICATE('-',(SELECT COUNT(*) FROM EmpHierarchy B WHERE A.Path % B.Path = 0)) As Hierarchy,&lt;br /&gt;(SELECT COUNT(*) FROM EmpHierarchy B WHERE A.Path % B.Path = 0) as [Level],&lt;br /&gt;A.EmpName AS Employee, C.EmpName As Manager&lt;br /&gt;FROM EmpHierarchy A&lt;br /&gt;LEFT JOIN EmpHierarchy C&lt;br /&gt;ON A.ManagerId = C.EmpId&lt;br /&gt;WHERE A.Path % @PathVal = 0&lt;br /&gt;ORDER By [Level]&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-111078299038850949?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/111078299038850949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=111078299038850949&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078299038850949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078299038850949'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/03/print-hierarchy-print-hierarchy-with.html' title=''/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-111078312137088305</id><published>2005-03-14T12:53:00.000+05:30</published><updated>2005-03-16T11:04:45.156+05:30</updated><title type='text'></title><content type='html'>&lt;b&gt;List of Superiors&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;/*&lt;br /&gt;Get the List of Superiors and their managers&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;CREATE PROC dbo.getSuperiors&lt;br /&gt;(@EmpId int)&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;SET NOCOUNT ON&lt;br /&gt;DECLARE @Path bigint&lt;br /&gt;&lt;br /&gt;SELECT @Path = Path&lt;br /&gt;FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @EmpId&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT A.EmpId, A.EmpName AS Employee, C.EmpName As Manager&lt;br /&gt;FROM EmpHierarchy A&lt;br /&gt;LEFT JOIN EmpHierarchy C&lt;br /&gt;ON A.ManagerId = C.EmpId&lt;br /&gt;WHERE @Path % A.Hkey = 0&lt;br /&gt;ORDER By A.Path DESC&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-111078312137088305?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/111078312137088305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=111078312137088305&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078312137088305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078312137088305'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/03/list-of-superiors-get-list-of.html' title=''/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-111078332902743746</id><published>2005-03-14T12:52:00.000+05:30</published><updated>2005-03-16T11:05:10.843+05:30</updated><title type='text'></title><content type='html'>&lt;b&gt;List of Subordinates&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;/*&lt;br /&gt;Get the List of Subordinates and their managers&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE PROC dbo.getSubordinates&lt;br /&gt;(@EmpId int)&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;SET NOCOUNT ON&lt;br /&gt;DECLARE @Hkey bigint&lt;br /&gt;&lt;br /&gt;SELECT @HKey = Hkey&lt;br /&gt;FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @EmpId&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT A.EmpId, A.EmpName AS Employee, C.EmpName As Manager&lt;br /&gt;FROM EmpHierarchy A&lt;br /&gt;LEFT JOIN EmpHierarchy C&lt;br /&gt;ON A.ManagerId = C.EmpId&lt;br /&gt;WHERE A.Path % @HKey = 0&lt;br /&gt;ORDER By A.Path&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;GO&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-111078332902743746?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/111078332902743746/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=111078332902743746&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078332902743746'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078332902743746'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/03/list-of-subordinates-get-list-of.html' title=''/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-111078358236227727</id><published>2005-03-14T12:51:00.000+05:30</published><updated>2005-03-16T11:05:39.713+05:30</updated><title type='text'></title><content type='html'>&lt;b&gt;Update Node&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;/*&lt;br /&gt;Update an Employee with a new Manager. Also adjusts the path of the&lt;br /&gt;Employee and his Subordinates&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;CREATE PROC dbo.UpdateNode&lt;br /&gt;(@Empid bigint,&lt;br /&gt;@NewMgrId bigint)&lt;br /&gt;AS&lt;br /&gt;&lt;br /&gt;BEGIN&lt;br /&gt;SET NOCOUNT ON&lt;br /&gt;&lt;br /&gt;DECLARE @CurrentMgrPath bigint&lt;br /&gt;DECLARE @NewMgrPath bigint&lt;br /&gt;DECLARE @CurrentMgr bigint&lt;br /&gt;DECLARE @CurrentPath bigint&lt;br /&gt;DECLARE @NewPath bigint&lt;br /&gt;&lt;br /&gt;--Employee Exists?&lt;br /&gt;IF NOT EXISTS(SELECT 1 FROM EmpHierarchy WHERE EmpId = @empid)&lt;br /&gt;RAISERROR('Employee Id %d Does not exists',16,1,@Empid)&lt;br /&gt;&lt;br /&gt;--Manager Exists&lt;br /&gt;IF NOT EXISTS(SELECT 1 FROM EmpHierarchy WHERE EmpId = @NewMgrId)&lt;br /&gt;RAISERROR('Manager %d Does not exists',16,1,@NewMgrId)&lt;br /&gt;&lt;br /&gt;--Get the required values to variables&lt;br /&gt;SELECT @CurrentMgr = ManagerId,&lt;br /&gt;@CurrentPath = Path&lt;br /&gt;FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @empid&lt;br /&gt;&lt;br /&gt;SELECT @CurrentMgrPath = Path&lt;br /&gt;FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @CurrentMgr&lt;br /&gt;&lt;br /&gt;SELECT @NewMgrPath = Path&lt;br /&gt;FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @NewMgrId&lt;br /&gt;&lt;br /&gt;--Cyclic Reference&lt;br /&gt;IF EXISTS(SELECT 1 FROM EmpHierarchy WHERE EmpId = @NewMgrId&lt;br /&gt;AND Path % @CurrentPath = 0)&lt;br /&gt;RAISERROR('Error: Cyclic Reference',16,1)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--Seems OK. Update.&lt;br /&gt;BEGIN TRAN&lt;br /&gt;--Update Manager&lt;br /&gt;UPDATE EmpHierarchy&lt;br /&gt;SET ManagerId = @NewMgrId&lt;br /&gt;WHERE EmpId = @Empid&lt;br /&gt;&lt;br /&gt;IF @@ROWCOUNT = 0 OR @@ERROR &lt;&gt; 0&lt;br /&gt;BEGIN&lt;br /&gt;ROLLBACK&lt;br /&gt;RAISERROR('Failed To update',16,1)&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;--Update Path&lt;br /&gt;UPDATE EmpHierarchy&lt;br /&gt;SET Path = ((Path / @CurrentMgrPath)*@NewMgrPath)&lt;br /&gt;WHERE Path % @CurrentPath = 0&lt;br /&gt;&lt;br /&gt;IF @@ROWCOUNT = 0 OR @@ERROR &lt;&gt; 0&lt;br /&gt;BEGIN&lt;br /&gt;ROLLBACK&lt;br /&gt;RAISERROR('Failed To update',16,1)&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN&lt;br /&gt;COMMIT&lt;br /&gt;RETURN 1&lt;br /&gt;END&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;GO&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-111078358236227727?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/111078358236227727/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=111078358236227727&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078358236227727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078358236227727'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/03/update-node-update-employee-with-new.html' title=''/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-111078369920077892</id><published>2005-03-14T12:50:00.000+05:30</published><updated>2005-03-16T11:05:59.843+05:30</updated><title type='text'></title><content type='html'>&lt;b&gt;Delete a SubTree&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;&lt;br /&gt;/*&lt;br /&gt;Delete a subtree from the hierarchy&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE PROC dbo.deleteSubTree&lt;br /&gt;(@EmpId int)&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;SET NOCOUNT ON&lt;br /&gt;DECLARE @Hkey bigint&lt;br /&gt;&lt;br /&gt;SELECT @Hkey = Hkey&lt;br /&gt;FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @EmpId&lt;br /&gt;&lt;br /&gt;DELETE FROM EmpHierarchy&lt;br /&gt;WHERE Path % @Hkey = 0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-111078369920077892?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/111078369920077892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=111078369920077892&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078369920077892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078369920077892'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/03/delete-subtree-delete-subtree-from.html' title=''/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-111078380765943642</id><published>2005-03-14T12:49:00.000+05:30</published><updated>2005-03-16T11:06:25.236+05:30</updated><title type='text'></title><content type='html'>&lt;b&gt;Delete a Single Node&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:'Courier New',Courier,monospace;color:#800000;"&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;Delete a given node. All Employees reporting to&lt;br /&gt;the deleted employee will now report to the manager of the deleted employee&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ALTER PROC dbo.deleteNode&lt;br /&gt;(@EmpId int)&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;SET NOCOUNT ON&lt;br /&gt;DECLARE @Hkey bigint&lt;br /&gt;DECLARE @MgrId bigint&lt;br /&gt;DECLARE @EmpPath bigint&lt;br /&gt;DECLARE @MgrPath bigint&lt;br /&gt;&lt;br /&gt;SELECT @Hkey = Hkey,&lt;br /&gt;@MgrId = ManagerId,&lt;br /&gt;@EmpPath = Path&lt;br /&gt;FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @EmpId&lt;br /&gt;&lt;br /&gt;SELECT @MgrPath = Path&lt;br /&gt;FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @MgrId&lt;br /&gt;&lt;br /&gt;--Delete Employee&lt;br /&gt;DELETE FROM EmpHierarchy&lt;br /&gt;WHERE EmpId = @EmpId&lt;br /&gt;&lt;br /&gt;--Update ManagerID of Immediate Subordiantes&lt;br /&gt;UPDATE EmpHierarchy&lt;br /&gt;SET ManagerId = @MgrId&lt;br /&gt;WHERE Path / Hkey = @EmpPath&lt;br /&gt;&lt;br /&gt;--Connect subordinates to the immediate superior&lt;br /&gt;UPDATE EmpHierarchy&lt;br /&gt;SET Path = ((Path/@EmpPath)*@MgrPath)&lt;br /&gt;WHERE PAth % @Hkey = 0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-111078380765943642?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/111078380765943642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=111078380765943642&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078380765943642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/111078380765943642'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2005/03/delete-single-node-delete-given-node.html' title=''/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-109329762376993042</id><published>2004-08-24T03:06:00.000+05:30</published><updated>2005-09-11T17:16:42.736+05:30</updated><title type='text'>Difference between Table Variable and Temporary Table</title><content type='html'>&lt;span style="font-family:verdana;"&gt;Table variables were introduced in SQL Server 2000. Many times they are presented as a replacement for temporary tables. There is a lot of arguement about the performance advantages of one over the other. It is generally believed that table variables give better performance than temporary tables. But there are so many cases reported where the usage of table variable slow down the performance, especially when the number of rows involved are high. So now the general recommendation is that use a table variable only if there is a performance gain over the temp table. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Lets see what are the basic difference between them.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;1. Contrary to the popular belief that table variables exists in memory, KB Article &lt;/span&gt;&lt;a href="http://support.microsoft.com/?kbid=305977"&gt;&lt;span style="font-family:verdana;"&gt;305977&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:verdana;"&gt; states that "A table variable is not a memory-only structure. Because a table variable might hold more data than can fit in memory, it has to have a place on disk to store data. Table variables are created in the tempdb database similar to temporary tables. If memory is available, both table variables and temporary tables are created and processed while in memory (data cache)."&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;The implementation of table variables is from a logging and tempdb usage very similar to temporary tables. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;br /&gt;2. You can create indexes on a temp table. Table variables does not support explicit index creation. You can create indexes on table variables using the PRIMARY KEY and Unique constraints.&lt;br /&gt;&lt;br /&gt;3. User defined functions are not permitted to do DDL operations. But UDFs can CREATE, INSERT, UPDATE, DELETE and RETURN table variables. (But you cannot use user-defined data types in the table variable you declare for the return value.)&lt;br /&gt;&lt;br /&gt;4. Table variables are always local to its scope while Temporary tables can be global or local. So table variables cannot be accessed from calling procedures in case of nested sps.&lt;br /&gt;&lt;br /&gt;5. Stored Procedure Recompilations. Using table variables can reduce the number of stored procedure recompilations. thats one place where table variables excel over temp tables.&lt;br /&gt;&lt;br /&gt;6. Table variables do not maintain statistics like temporary tables. This might lead to bad execution plan and slow performance when dealing with higher number of rows.&lt;br /&gt;&lt;br /&gt;7. Temp tables can be ALTERed. But you cannot change the definition of a table variable after the initial DECLARE statement.&lt;br /&gt;&lt;br /&gt;8. Parallelism is not possible when you insert into a table variable.&lt;br /&gt;&lt;br /&gt;9. You cannot do&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;INSERT INTO @tablevar&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;EXEC yourspname&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;But&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;INSERT INTO #temptable &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;EXEC yourspname&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;is possible.&lt;br /&gt;&lt;br /&gt;10. You cannot do&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT * &lt;collist&gt;INTO @tableVar FROM source&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;But&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT * &lt;collist&gt;INTO #temptable FROM source&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;is possible.&lt;br /&gt;&lt;br /&gt;11. You cannot truncate a table variable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;DECLARE @x table(a int)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;INSERT INTO @x VALUES(1)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;TRUNCATE TABLE @x&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;produces a syntax Error.&lt;br /&gt;&lt;br /&gt;But the same is possible with temp table.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;DECLARE #x table(a int)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;INSERT INTO #x VALUES(1)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;TRUNCATE TABLE #x&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;12. Transactions involving table variables last only for the duration of an update on the table variable. Thus, table variables require less locking and logging resources. That is table variables are automatically committed, where as temporary tables can be included in a transaction. This can make a performance difference.&lt;br /&gt;&lt;br /&gt;13. Join Syntax. You MUST use an alias when referring a table variable in a JOIN. The following query will throw an error.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;USE PUBS&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;GO&lt;br /&gt;DECLARE @x table(someid varchar(15))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;INSERT INTO @x &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT Top 10 title_id FROM Titles&lt;br /&gt;SELECT * FROM Titles&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;INNER JOIN @x &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;ON Titles.title_id = @x.someid&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It should be written as&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;DECLARE @x table(someid varchar(15))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;INSERT INTO @x &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT Top 10 title_id FROM Titles&lt;br /&gt;SELECT * FROM Titles&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;INNER JOIN @x a&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;ON Titles.title_id = a.someid&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Temporary tables doesnt have such limitations.&lt;br /&gt;&lt;br /&gt;14. Temporary tables can be explicitly destroyed using DROP statement.&lt;br /&gt;&lt;br /&gt;15. You cannot assign a table variable to another as in the case of other variables.&lt;br /&gt;&lt;br /&gt;16. CHECK constraints, DEFAULT values, and computed columns in the table type declaration cannot call user-defined functions.&lt;br /&gt;&lt;br /&gt;17. "Display Estimated Execution Plan" option in query analyser does'nt work with T-SQL code that has a reference to Temporary tables.&lt;br /&gt;&lt;br /&gt;18. More, anyone...?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-109329762376993042?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/109329762376993042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=109329762376993042&amp;isPopup=true' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/109329762376993042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/109329762376993042'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2004/08/difference-between-table-variable-and.html' title='Difference between Table Variable and Temporary Table'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-109284596024392813</id><published>2004-08-18T21:26:00.000+05:30</published><updated>2005-02-26T11:58:58.113+05:30</updated><title type='text'>Let Us Count them!</title><content type='html'>&lt;span style="font-family:verdana;"&gt;Lets have a quick look on the differences between using COUNT(*) and COUNT(colname). Also discuss other ways to get the count of rows.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;1. COUNT(*) returns the number of total rows. Count(colname) returns the total number of rows with Non NULL value for colname. If the specified column doesnt allow NULLs the result will be same.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;eg. (USE PUBS)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT count(*) FROM Titles&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;-- Returns 18&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT count(title_id) FROM Titles&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;-- Returns 18&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT count(royalty) FROM Titles&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;-- Returns 16&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;When you are doing Count on a column with NULLs SQL server will give you the warning. "Warning: Null value is eliminated by an aggregate or other SET operation."&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;As Count(colname) excludes columns with NULL values, the following query &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT count(royalty) FROM Titles where royalty IS NULL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;will return zero. If you want to get the count of rows with NULL in a specific column, you should use,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT count(*) FROM Titles where royalty IS NULL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;which returns two in this case. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;2. COUNT(colname) supports the use of ALL/DISTINCT clause (ALL is the default). COUNT(*) doesn't. So to get the UNIQUE Royalty values, you can use the query &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT COUNT(DISTINCT royalty) FROM Titles&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;You can combine these to see the difference.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT COUNT(*), COUNT(royalty), COUNT(DISTINCT royalty) FROM Titles&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;3. As COUNT(*) returns the total number of records (in each group when GROUP BY is present in the query), like SELECT @@ROWCOUNT, SELECT COUNT(*) is also a valid statement in its own, which always returns 1.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT COUNT(*)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;4. Performance. (with due credits to Itzik Ben Gan) If the specified column name does not allow NULLS, there isn't any performance difference between using COUNT(*) or COUNT(colname). The Optimizer will choose the smallest index available to get the number of records.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT COUNT(*) FROM Titles&lt;/span&gt;&lt;br /&gt;---------------------------------------------------------------------&lt;br /&gt;&lt;span style="color:#000099;"&gt;--Compute Scalar(DEFINE:([Expr1002]=Convert([Expr1003]))) &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000099;"&gt;--Stream Aggregate(DEFINE:([Expr1003]=Count(*))) &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000099;"&gt;--Index Scan(OBJECT:([pubs].[dbo].[titles].[titleind]))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT Count(type) FROM Titles&lt;br /&gt;&lt;/span&gt;---------------------------------------------------------------------&lt;br /&gt;&lt;span style="color:#000099;"&gt;--Compute Scalar(DEFINE:([Expr1002]=Convert([Expr1003]))) &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000099;"&gt;--Stream Aggregate(DEFINE:([Expr1003]=Count(*))) &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000099;"&gt;--Index Scan(OBJECT:([pubs].[dbo].[titles].[titleind]))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;As the type column doesnt allow NULLS, both the counts return the same number and SQL Server uses the smallest index available. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;If you issue the COUNT(colname) on a column that allows NULL, the execution plan might be different, as in&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT count(notes) FROM Titles&lt;br /&gt;&lt;/span&gt;---------------------------------------------------------------------------------------&lt;br /&gt;&lt;span style="color:#000099;"&gt;--Compute Scalar(DEFINE:([Expr1002]=Convert([Expr1003]))) &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000099;"&gt;--Stream Aggregate(DEFINE:([Expr1003]=COUNT_BIG([titles].[notes]))) &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000099;"&gt;--Clustered Index Scan(OBJECT:([pubs].[dbo].[titles].[UPKCL_titleidind]))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;In this case, SQL Server will use a nonclustered index, if one is defined on the specified column. Otherwise a clustered index scan(as in the above case) or a table scan will be performed. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Here you can also notice that SQL Server internally replace the COUNT() function with COUNT_BIG() function. COUNT_BIG works like the COUNT function. The only difference between them is their return values: COUNT_BIG always returns a bigint data type value. COUNT always returns an int data type value.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;5. Conditional Count&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Using the CASE Expression, you can get count of items conditionally. See the following example.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;Use NothWind&lt;br /&gt;Go&lt;br /&gt;SELECT COUNT(*) as ProductCount,&lt;br /&gt;COUNT(CASE WHEN DisContinued = 0 Then 1 END) As Available,&lt;br /&gt;COUNT(CASE WHEN DisContinued = 1 Then 1 END) As Discontinued&lt;br /&gt;FROM Products&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;6. Getting Count from multiple tables&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Here is two methods to get the count of rows from more than one table.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT SUM(cnt) as EmployeesandCustomers FROM&lt;br /&gt;(SELECT COUNT(*) cnt FROM Employees&lt;br /&gt;UNION&lt;br /&gt;SELECT COUNT(*) cnt FROM Customers) T&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT (SELECT COUNT(*) cnt FROM Employees)+&lt;br /&gt;(SELECT COUNT(*) cnt FROM Customers) as EmployeesandCustomers&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;7. Count('AnythingGoesHere')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;The parameter for the count function can be a column name, number, literal or an expression. The BOL says that "expression can be of any type except uniqueidentifier, text, image, or ntext. Aggregate functions and subqueries are not permitted."&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;SELECT COUNT(1) or SELECT COUNT('abc') is equivalent to SELECT COUNT(*)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;8.&lt;span style="font-family:verdana;"&gt; Alternatives. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;If you don't require an exact answer, it isn't necessary use a SELECT count(*) query on the rows in a table to get the row count, because it might be a time consuming process to get the count of rows from a table with millions of rows. SQL Server keeps the row count in sysindexes and it can be retrieved there. But it may not always reflect the exact number of records.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;See below.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT rows as linecount &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;FROM sysindexes &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;WHERE id = OBJECT_ID('Titles') AND indid &lt;&gt; 2&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="color:#000000;"&gt;If you have a tip on count, plz post a comment.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;&lt;/span&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-109284596024392813?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/109284596024392813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=109284596024392813&amp;isPopup=true' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/109284596024392813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/109284596024392813'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2004/08/let-us-count-them.html' title='Let Us Count them!'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-109222114908932842</id><published>2004-08-02T14:40:00.000+05:30</published><updated>2004-08-14T12:29:45.576+05:30</updated><title type='text'>Difference Between SET and SELECT</title><content type='html'>&lt;span style="font-family:verdana;"&gt;T-SQL Programmers use both SET and SELECT Statements for variable assignments. Lets see what are the differences.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;1. SET is the ANSI Standard for variable assignment. Variable assignment using SELECT is T-SQL Proprietory.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;2. SELECT can be used for multiple variable assignment. Using SET you can only assign one variable at a time.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;DECLARE @myval1 int&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;DECLARE @myval2 int&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SET @myVal1 = 5&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SET @myVal2 = 6&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT @myVal1 = 5, @myVal2 = 6&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;3. Different Behavior when No rows are Returned.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;If variables are assigned in the SELECT then the value of the variables will remain unchanged, but thats not the case with SET. See the following example.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;DECLARE @id INTEGER&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SET @id = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT @id = id FROM sysobjects WHERE name = 'does not exist'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT @id -- Returns Zero&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SET @id= (SELECT id FROM sysobjects WHERE name = 'does not exist')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT @id -- Returns NULL&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Verdana;"&gt;But if the SELECT includes an aggregate function it will NOT retain the initial value. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;DECLARE @id INTEGER&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SET @id = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT @id = Max(id) FROM sysobjects WHERE name = 'does not exist'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT @id -- Returns NULL&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Verdana;"&gt;4. Different Behavior when Multiple rows are returned by the expression in the right side. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Verdana;"&gt;When using SET, it returns the 'Subquery Returned more than one value' Error.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;DECLARE @id INTEGER&lt;br /&gt;SET @id = 0&lt;br /&gt;&lt;br /&gt;SET @id= (SELECT id FROM sysobjects)&lt;br /&gt;-- Returns Error&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Verdana;"&gt;But with SELECT it assigns the 'last' returned value to the variable, whic can be anything, if an ORDER BY clause is not specified, as in -&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;DECLARE @id INTEGER&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SET @id = 0 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT @id = id FROM sysobjects&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT @id&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;So you have to be careful, to avoid disatsters. Lets take an example.&lt;br /&gt;Suppose you want to assign the orderid of the Last order placed by a given customer, to a variable.&lt;br /&gt;(There might be better way to do that with an aggregate function, but this is just an example)&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#660000;"&gt;&lt;span style="font-family:courier new;"&gt;USE Northwind&lt;br /&gt;GO &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="color:#660000;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;DECLARE @OrderId int&lt;br /&gt;SELECT @OrderId = OrderId&lt;br /&gt;FROM Orders&lt;br /&gt;WHERE CustomerId = 'VINET'&lt;br /&gt;ORDER BY OrderId ASC&lt;br /&gt;&lt;br /&gt;SELECT @OrderId&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Here we have used &lt;span style="color:#660000;"&gt;ORDER BY OrderId ASC&lt;/span&gt;. So the last OrderID of the customer will be assigned to the variable @OrderId. But suppose you add TOP 1 to the above query, thinking that you only want one OrderId anyway, then you will be getting only the first order of the customer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;USE Northwind&lt;br /&gt;GO &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;DECLARE @OrderId int&lt;br /&gt;SELECT TOP 1 @OrderId = OrderId&lt;br /&gt;FROM Orders&lt;br /&gt;WHERE CustomerId = 'VINET'&lt;br /&gt;ORDER BY OrderId ASC&lt;br /&gt;&lt;br /&gt;SELECT @OrderId&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;To get the expected result you have to change the ORDER BY clause to DESC.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;USE Northwind&lt;br /&gt;GO &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;DECLARE @OrderId int&lt;br /&gt;SELECT TOP 1 @OrderId = OrderId&lt;br /&gt;FROM Orders&lt;br /&gt;WHERE CustomerId = 'VINET'&lt;br /&gt;ORDER BY OrderId DESC&lt;br /&gt;&lt;br /&gt;SELECT @OrderId&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;5. Looping Behavior of SELECT&lt;br /&gt;Further exploring the above point, we can introduce some intuitive looping behaviour using SELECT. Consider the following example.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;CREATE TABLE #tmp (a int)&lt;br /&gt;INSERT INTO #tmp VALUES(1)&lt;br /&gt;INSERT INTO #tmp VALUES(2)&lt;br /&gt;INSERT INTO #tmp VALUES(3)&lt;br /&gt;INSERT INTO #tmp VALUES(4)&lt;br /&gt;INSERT INTO #tmp VALUES(5)&lt;br /&gt;&lt;br /&gt;DECLARE @p int&lt;br /&gt;SELECT @p = isnull(@p, 1) * a FROM #tmp&lt;br /&gt;SELECT @p&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:verdana;"&gt;Here @p become 120, the product of all values of a. We can observe that the assignment is carried out once for each row of in the table #tmp.&lt;br /&gt;&lt;br /&gt;The same logic is used in the varchar concatenation technique shown below.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;USE PUBS&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;DECLARE @vchAuthors VARCHAR(400)&lt;br /&gt;SET @vchAuthors = ''&lt;br /&gt;SELECT @vchAuthors = @vchAuthors +&lt;br /&gt;CASE WHEN @vchAuthors = '' THEN '' ELSE ', ' END + au_lname&lt;br /&gt;FROM authors&lt;br /&gt;&lt;br /&gt;SELECT @vchAuthors&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Thats all I have about it. SQL Server MVP Narayana Vyas has an &lt;/span&gt;&lt;/span&gt;&lt;a href="http://vyaskn.tripod.com/differences_between_set_and_select.htm"&gt;&lt;span style="font-family:verdana;"&gt;article&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-family:verdana;"&gt; abt the differences between SET and SELECT, which also includes a performance comparison between the two.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-109222114908932842?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/109222114908932842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=109222114908932842&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/109222114908932842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/109222114908932842'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2004/08/difference-between-set-and-select.html' title='Difference Between SET and SELECT'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-109212484366403065</id><published>2004-08-01T13:22:00.000+05:30</published><updated>2004-12-02T20:28:36.433+05:30</updated><title type='text'>Differences between COALESCE and ISNULL</title><content type='html'>&lt;span style="font-family:verdana;"&gt;I am trying to document the difference between some of the Keywords/functions, that are used for the same purpose and has some differences. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Let me start with COALESCE and ISNULL today. What comes first to my mind is COALESCE is hard to spell ;)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Lets see what are the relevant differences.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;1. COALESCE is ANSI standard and ISNULL is T-SQL proprietary.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;2. You can work with only one value at a time with ISNULL, but COALESCE can deal with multiple values. as in&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT ISNULL(NULL, 'SomeValue')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT COALESCE(NULL, NULL, NULL, 'SomeValue')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;3. &lt;span style="font-family:verdana;"&gt;With ISNULL, the Alternate value you specify is limited to the length of the first parameter. In case of COALESCE, you dont have such restrictions. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;See the example below.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;DECLARE @somestring CHAR(4)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SET @somestring = NULL&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT ISNULL(@somestring, 'Roji Thomas')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;--Returns 'Roji'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;SELECT COALESCE(@somestring, 'Roji Thomas')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#660000;"&gt;--Returns 'Roji Thomas'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;4. When using COALESCE All expressions must be of the same type or must be implicitly convertible to the same type. If you are not careful, this can give you incorrect results. See the examples below.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT COALESCE(NULL, GetDate())&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Returns : 2004-07-26 13:47:15.937&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Correct&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT COALESCE(1, GetDate())&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Returns 1900-01-02 00:00:00.000 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Incorrect Value&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT COALESCE(1,'abcd')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Returns 1&lt;br /&gt;SELECT COALESCE('abcd',1)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Returns Error&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;-- Server: Msg 245, Level 16, State 1, Line 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;-- Syntax error converting the varchar value 'abcd' to a column of data type int.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT COALESCE(NULL,435,'abcd', CURRENT_TIMESTAMP,'xyzzz',435)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Returns 1901-03-12 00:00:00.000&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Incorrect&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT COALESCE(NULL,GetDate(),9999999999)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Returns : 2004-07-26 13:47:15.937&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Correct&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;SELECT COALESCE(NULL,9999999999, GetDate())&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;--Returs Error&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;-- Server: Msg 8115, Level 16, State 2, Line 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;color:#990000;"&gt;-- Arithmetic overflow error converting expression to data type datetime.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;5. Eventhough COALESCE is generally the preferred way, there are some performance consideration especially when you have a select statement as an arguument to COALESCE. So always analyse the execution plan. You can read further abt it &lt;/span&gt;&lt;a href="http://groups.google.com/groups?hl=en&amp;threadm=eOoNk3AJBHA.1340%40tkmsftngp04"&gt;&lt;span style="font-family:verdana;"&gt;here&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Here is two interesting Performance comparison between COALESCE  and ISNULL.&lt;/span&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:verdana;"&gt;&lt;a href="http://blogs.x2line.com/al/archive/2004/03/01/189.aspx"&gt;http://blogs.x2line.com/al/archive/2004/03/01/189.aspx&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Verdana;"&gt;&lt;a href="http://weblogs.sqlteam.com/mladenp/articles/2937.aspx"&gt;http://weblogs.sqlteam.com/mladenp/articles/2937.aspx&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:verdana;"&gt;&lt;br /&gt;Feel Free to postback your comments.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-109212484366403065?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/109212484366403065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=109212484366403065&amp;isPopup=true' title='32 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/109212484366403065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/109212484366403065'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2004/08/differences-between-coalesce-and.html' title='Differences between COALESCE and ISNULL'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>32</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-108843783023026867</id><published>2004-06-28T20:45:00.000+05:30</published><updated>2004-06-28T21:20:30.230+05:30</updated><title type='text'>Fancy Scoping</title><content type='html'>Try the following query.&lt;br /&gt;&lt;br /&gt;USE Pubs&lt;br /&gt;GO&lt;br /&gt;SELECT * FROM Authors&lt;br /&gt;WHERE au_id IN&lt;br /&gt;(SELECT au_id FROM Titles)&lt;br /&gt;&lt;br /&gt;As we know there is no column called au_id &lt;br /&gt;in the TITLES table, and the query returns&lt;br /&gt;all the records in the Authors table, instead&lt;br /&gt;of an invalid column name Error.&lt;br /&gt;&lt;br /&gt;Amazed..?  Actually I was amzed when I see&lt;br /&gt;this behaviour first. &lt;br /&gt;&lt;br /&gt;But this is the expected behaviour and thats &lt;br /&gt;what makes the correlated subqueries work.&lt;br /&gt;&lt;br /&gt;When SQL Server fails to find the au_id in the &lt;br /&gt;TITLES table, it looks for the au_id column in&lt;br /&gt;the Authors table.&lt;br /&gt;&lt;br /&gt;So if our statement was &lt;br /&gt;IN (SELECT T.au_id FROM Titles T) &lt;br /&gt;the query will throw an Error.&lt;br /&gt;&lt;br /&gt;Joe CELKO referred this behaviour as "fancy scoping"&lt;br /&gt;You can read his original posting &lt;a href="http://groups.google.com/groups?hl=en&amp;lr=lang_en&amp;ie=UTF-8&amp;oe=UTF-8&amp;selm=%23tBR4VgvAHA.712%40tkmsftngp04"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-108843783023026867?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/108843783023026867/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=108843783023026867&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/108843783023026867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/108843783023026867'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2004/06/fancy-scoping.html' title='Fancy Scoping'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7354546.post-108841280166197912</id><published>2004-06-28T12:04:00.000+05:30</published><updated>2004-06-28T14:23:21.663+05:30</updated><title type='text'>Why BLOG?</title><content type='html'>Hmmm Good question. Especially when&lt;br /&gt;its considered that I hate people blogging&lt;br /&gt;abt what breakfast they had and what dress they&lt;br /&gt;wear.&lt;br /&gt;&lt;br /&gt;I want to blog because, I believe in learning something &lt;br /&gt;new everyday and I always try to do. As I am currently &lt;br /&gt;focusing on The RDBMS side, I'll try to post my SQL Server&lt;br /&gt;experiments as and when possible, not necessarily on a &lt;br /&gt;daly basis.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7354546-108841280166197912?l=toponewithties.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toponewithties.blogspot.com/feeds/108841280166197912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7354546&amp;postID=108841280166197912&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/108841280166197912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7354546/posts/default/108841280166197912'/><link rel='alternate' type='text/html' href='http://toponewithties.blogspot.com/2004/06/why-blog.html' title='Why BLOG?'/><author><name>Roji. P. Thomas</name><uri>http://www.blogger.com/profile/07837495547296394554</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>
