<?xml version="1.0" encoding="UTF-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><title type="html">John Magnabosco</title><subtitle type="html">SQL Server Development and Data Security</subtitle><id>http://www.simple-talk.com/community/blogs/johnm/atom.aspx</id><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/default.aspx" /><link rel="self" type="application/atom+xml" href="http://www.simple-talk.com/community/blogs/johnm/atom.aspx" /><generator uri="http://communityserver.org" version="2.0.60217.2664">Community Server</generator><updated>2010-06-05T15:30:14Z</updated><entry><title>The Legend of the Filtered Index</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2011/10/06/103697.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2011/10/06/103697.aspx</id><published>2011-10-06T10:52:07Z</published><updated>2011-10-06T10:52:07Z</updated><content type="html">&lt;p&gt;Once upon a time there was a big and bulky twenty-nine million row table. He tempestuously hoarded data like a maddened shopper amid a clearance sale. Despite his leviathan nature and eager appetite he loved to share his treasures. Multitudes from all around would embark upon an epiphanous journey to sample contents of his mythical purse of knowledge.&lt;/p&gt;  &lt;p&gt;After a long day of performing countless table scans the table was overcome with fatigue. After a short period of unavailability, he decided that he needed to consider a new way to share his prized possessions in a more efficient manner. Thus, a &lt;a href="http://msdn.microsoft.com/en-us/library/ms177484.aspx"&gt;non-clustered index&lt;/a&gt; was born. She dutifully directed the pilgrims that sought the table's data - no longer would those despicable table scans darken the doorsteps of this quaint village. and yet, the table's veracious appetite did not wane.&lt;/p&gt;  &lt;p&gt;Any bit or byte that wondered near him was consumed with vigor. His columns and rows continued to expand beyond the expectations of even the most liberal &lt;a href="http://www.sql-server-performance.com/2006/database-space-grow/"&gt;estimation&lt;/a&gt;. As his rows grew grander they became more difficult to organize and maintain. The once bright and cheerful disposition of the non-clustered index began to dim. The wait time for those who sought the table's treasures began to increase. Some of those who came to nibble upon the banquet of knowledge even timed-out and never realized their aspired enlightenment. After a period of heart-wrenching introspection, the table decided to &lt;a href="http://msdn.microsoft.com/en-us/library/ms176118.aspx"&gt;drop the index&lt;/a&gt; and attempt another solution.&lt;/p&gt;  &lt;p&gt;At the darkest hour of the table's desperation came a grand flash of light. As his eyes regained their vision there stood several creatures who looked very similar to his former, beloved, non-clustered index. They all spoke in unison as they introduced themselves:&lt;em&gt; "Fear not, for we come to organize your data and direct those who seek to partake in it. We are the &lt;/em&gt;&lt;a href="http://technet.microsoft.com/en-us/library/cc280372.aspx"&gt;&lt;em&gt;filtered index&lt;/em&gt;&lt;/a&gt;&lt;em&gt;."&lt;/em&gt; Immediately, the filtered indexes began to scurry about. One took control of the past quarter's data. Another took control of the previous quarter's data. All of the remaining filtered indexes followed suit. As the nearly gluttonous habits of the table scaled forward more filtered indexes appeared. Regardless of the table's size, all of the eagerly awaiting data seekers were delivered data as quickly as a &lt;a href="http://www.jimmyjohns.com/"&gt;Jimmy John's&lt;/a&gt; sandwich. The table was moved to tears. All in the land of data rejoiced and all lived happily ever after, at least until the next data challenge crept from the fearsome cave of the unknown.&lt;/p&gt;  &lt;p&gt;The End.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=103697" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>SQL Server MVP Deep Dives Vol. 2</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2011/09/29/103577.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2011/09/29/103577.aspx</id><published>2011-09-30T02:36:24Z</published><updated>2011-09-30T02:36:24Z</updated><content type="html">&lt;p&gt;The confetti and silly hats, which are quintessential standards of the celebration of a new year, had just been freshly packed away when an email popped up in my inbox. It was &lt;a href="http://sqlblog.com/blogs/kalen_delaney/default.aspx"&gt;Kalen Delaney&lt;/a&gt; announcing the call for submissions for upcoming the &lt;em&gt;&lt;strong&gt;SQL Server Deep Dives Volume 2&lt;/strong&gt;&lt;/em&gt; book. Potential authors were challenged to write about their area of &lt;em&gt;passion&lt;/em&gt; in regard to SQL Server. I jumped at the chance to offer my contribution. To my delight, my chapter made the cut! &lt;/p&gt;  &lt;p&gt;The topic of passion that I contributed was on the topic of personally identifiable data and the super powers that the DBA holds in its protection. I titled it &lt;em&gt;&lt;strong&gt;Will the real Mr. Smith please stand up?&lt;/strong&gt;,&lt;/em&gt; in honor of the tag line of old &lt;strong&gt;&lt;em&gt;&lt;a href="http://en.wikipedia.org/wiki/To_Tell_the_Truth"&gt;To Tell The Truth&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; game show. It can be found as the eleventh chapter of the book within the &lt;em&gt;&lt;strong&gt;Database Administration&lt;/strong&gt;&lt;/em&gt; section. It was quite an honor to participate in the authoring of this book and to share these pages with such an esteemed list of SQL Server Gurus.&lt;/p&gt;  &lt;p&gt;All royalties from &lt;strong&gt;&lt;em&gt;SQL Server Deep Dives Volume 2&lt;/em&gt;&lt;/strong&gt; will be donated to &lt;a href="http://www.operationsmile.org/"&gt;Operation Smile&lt;/a&gt; which is an international children's medial charity. So when you purchase this book, you not only help yourself you also will help a child who suffers from facial deformities start a new life.&lt;/p&gt;  &lt;p&gt;For those who will be attending the &lt;a href="http://www.sqlpass.org/summit/2011/"&gt;2011 PASS Summit&lt;/a&gt; on October 11 - 14 in Seattle, Washington, there will be an opportunity to get your hands on a fresh off-the-press copy of this life changing book. There will also be the opportunity to have your copy signed by many of the contributing authors. Others, like myself - who will not make it to the biggest SQL Server event of the year, a copy of this book can be ordered directly from &lt;a href="http://www.manning.com/delaney/"&gt;Manning Publishing&lt;/a&gt;, &lt;a href="http://www.amazon.com/SQL-Server-Deep-Dives-Vol/dp/1617290475/ref=sr_1_1?ie=UTF8&amp;amp;qid=1317347060&amp;amp;sr=8-1"&gt;Amazon.com&lt;/a&gt; and &lt;a href="http://www.barnesandnoble.com/w/sql-server-mvp-deep-dives-volume-2-kalen-delaney/1105682150?ean=9781617290473&amp;amp;itm=1&amp;amp;usri=sql%2bserver%2bmvp%2bdeep%2bdives%2b2"&gt;Barnes and Noble&lt;/a&gt; shortly after the Summit.&lt;/p&gt;  &lt;p&gt;Enjoy!&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=103577" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>SQL Saturday and Exploring Data Privacy</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2011/06/28/102129.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2011/06/28/102129.aspx</id><published>2011-06-29T01:28:06Z</published><updated>2011-06-29T01:28:06Z</updated><content type="html">&lt;p&gt;I have been highly impressed with the growth of the &lt;a href="http://www.sqlsaturday.com/default.aspx"&gt;SQL Saturday&lt;/a&gt; phenomenon. It seems that an announcement for a new wonderful event finds its way to my inbox on a daily basis. I have had the opportunity to attend the first of the SQL Saturday's for Tampa, Chicago, Louisville and recently my home town of Indianapolis. It is my hope that there will be many more in my future. This past weekend I had the honor of being selected to speak amid a great line up of speakers at &lt;a href="http://www.sqlsaturday.com/82/eventhome.aspx"&gt;SQL Saturday #82&lt;/a&gt; in Indianapolis. My session topic/title was "Exploring Data Privacy". &lt;/p&gt;  &lt;p&gt;Below is a brief synopsis of my session:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Data Privacy in a Nutshell&lt;/strong&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - Definition of data privacy    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - Examples of personally identifiable data     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - Examples of Sensitive data&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Laws and Stuff&lt;/strong&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - Various examples of laws, regulations and policies that influence the definition of data privacy    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - General rules of thumb that encompasses most laws&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Your Data Footprint&lt;/strong&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - Who has personal information about you?    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - What are you exchanging data privacy for?    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - The amazing resilience of data     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - The cost of data loss&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Weapons of Mass Protection&lt;/strong&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - Data classification    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - Extended properties    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - Database Object Schemas    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - An extraordinarily brief introduction of encryption    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; - The amazing data professional&amp;#160; &lt;em&gt;&lt;font color="#ff0000"&gt;&amp;lt;-the most important point of the entire session!&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;The subject of data privacy is one that is quickly making its way to the forefront of the mind of many data professionals. Somewhere out there someone is storing personally identifiable and other sensitive data about you. In some cases it is kept reasonably secure. In other cases it is kept in total exposure without the consideration of its potential of damage to you. Who has access to it and how is it being used? Are we being unnecessarily required to supply sensitive data in exchange for products and services? These are just a few questions on everyone's mind. As data loss events of grand scale hit the headlines in a more frequent succession, the level of frustration and urgency for a solution increases. &lt;/p&gt;  &lt;p&gt;I assembled this session with the intent to raise awareness of sensitive data and remind us all that we, data professionals, are the ones who have the greatest impact and influence on how sensitive data is regarded and protected. &lt;a href="http://en.wikipedia.org/wiki/Mohandas_Karamchand_Gandhi"&gt;Mahatma Gandhi&lt;/a&gt; once said "&lt;em&gt;Be the change you want to see in the world&lt;/em&gt;." This is guidance that I keep near to my heart as I approached this topic of data privacy.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=102129" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>Moving Dates</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2011/04/23/101347.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2011/04/23/101347.aspx</id><published>2011-04-23T23:32:00Z</published><updated>2011-04-23T23:32:00Z</updated><content type="html">&lt;p&gt;At the loading dock, hard working individuals load a semi trailer with your new television, stereo system and personal computer. There is a dependency in this process: it is that your favorite electronics store has a loading dock that will be able to accommodate the size of the semi. If the semi were to arrive to the store and the location of receiving deliveries is only the size of a one-car garage it may either result in a refused delivery or a lot of manual work to perform the task of unloading the semi.&lt;/p&gt;  &lt;p&gt;This experience is a shared one between semi drivers and database administrators. We pack up data from one database and deliver it to another. Not always does the proverbial loading dock meet the needs of the data that is being delivered. Consider the &lt;a href="http://technet.microsoft.com/en-us/library/ms187819.aspx"&gt;datetime&lt;/a&gt; data type for an example.&lt;/p&gt;  &lt;p&gt;The datetime data type is one in which we are all familiar. It has been part of the data type options for quite sometime. The range of dates that can be stored in this data type is from January 1, 1753 through December 31, 9999. The release of SQL Server 2008 a collection of date data types were introduced: &lt;a href="http://msdn.microsoft.com/en-us/library/bb630352.aspx"&gt;date&lt;/a&gt;, &lt;a href="http://msdn.microsoft.com/en-us/library/bb677335.aspx"&gt;datetime2&lt;/a&gt;,  and &lt;a href="http://msdn.microsoft.com/en-us/library/bb630289.aspx"&gt;datetimeoffset&lt;/a&gt;; all of which provide an accepted date range from January 1, 0001 through December 31, 9999. The expansion of date range for these new date data types provides compliance with &lt;a href="http://www.contrib.andrew.cmu.edu/%7Eshadow/sql/sql1992.txt"&gt;ANSI 92 SQL Standard&lt;/a&gt; for the &lt;a href="http://en.wikipedia.org/wiki/Gregorian_calendar"&gt;Gregorian calendar&lt;/a&gt;. This also presents a challenge when shipping data from a SQL Server 2008 database, which is using the date data type, to a SQL Server 2005 database, which is using the datetime data type.&lt;/p&gt;  &lt;p&gt;This situation can be illustrated through the execution of the following code:&lt;/p&gt; &lt;p&gt;&lt;font face="courier new" size="2"&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@Date &lt;/font&gt;&lt;font color="blue"&gt;DATE&lt;/font&gt;&lt;font color="gray"&gt;;           &lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@Datetime &lt;/font&gt;&lt;font color="blue"&gt;DATETIME&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SET &lt;/font&gt;&lt;font color="#434343"&gt;@Date &lt;/font&gt;&lt;font color="blue"&gt;= &lt;/font&gt;&lt;font color="red"&gt;'10/24/1492'&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SET &lt;/font&gt;&lt;font color="#434343"&gt;@Datetime &lt;/font&gt;&lt;font color="blue"&gt;= &lt;/font&gt;&lt;font color="#434343"&gt;@Date&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
  &lt;p&gt;The resulting error that occurs is:&lt;/p&gt; &lt;font color="#008000" face="Courier New"&gt;&lt;/font&gt;  &lt;p&gt;&lt;font face="Cordia New"&gt;&lt;font color="#c0504d" face="Courier New" size="2"&gt;The conversion of date data type to a datetime type resulted in an out-of-range value.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;The quick and easy reply might be to upgrade the SQL Server 2005 database to SQL Server 2008 and change the data type of the column in question. While this is certainly a valid option, not always is making such changes to the receiving database within our realm of control or the desire of the business.&lt;/p&gt;  &lt;p&gt;Data type modifications, such as varchar or numeric could provide a means of resolving this issue, but this conversion does loose some date characteristics that are valuable, such as ordering of dates and the use of date methods like &lt;a href="http://msdn.microsoft.com/en-us/library/ms189794.aspx"&gt;DATEDIFF&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;In essence, the resolution of this issue resides in an application of some minor business logic and compromise with the data that is being sent. It could be determined that since the receiving database does not allow October 24, 1492 that it has no functional use for dates preceding January 1, 1753. Therefore, these rows could be filtered out of the data that is being delivered. Another option could be to return NULL or another date in the date column to substitute out of range dates; thus, delivering the row but with a compatible, although less than accurate, data value. An illustration of such a statement would be:&lt;/p&gt;&lt;p&gt; &lt;font face="courier new" size="2"&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@Date &lt;/font&gt;&lt;font color="blue"&gt;DATE&lt;/font&gt;&lt;font color="gray"&gt;;           &lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@Datetime &lt;/font&gt;&lt;font color="blue"&gt;DATETIME&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SET &lt;/font&gt;&lt;font color="#434343"&gt;@Date &lt;/font&gt;&lt;font color="blue"&gt;= &lt;/font&gt;&lt;font color="red"&gt;'10/24/1492'&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SET &lt;/font&gt;&lt;font color="#434343"&gt;@Datetime &lt;/font&gt;&lt;font color="blue"&gt;= &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="#434343"&gt;@Date &lt;/font&gt;&lt;font color="gray"&gt;&lt;/font&gt;&lt;font color="red"&gt;'1753-01-01' &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="red"&gt;'1753-01-01' &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="#434343"&gt;@Date &lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;);&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="#434343"&gt;@Datetime&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
 &lt;p&gt;The latter solution noted above certainly does not settle well for those of us who are concerned with data integrity. It certainly should not be the option executed as your default response, nor should it be implemented without the exclusion of the options noted prior. However, it does offer a solution that could be mutually acceptable depending on the data's use. The key factor here is to work closely with those who are requesting the delivery of data. Before packing up your semi gain an understanding of the dock to which you are delivering. The time taken here could save your driver a load of sweat.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=101347" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>Expanding Influence and Community</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2011/01/24/99051.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2011/01/24/99051.aspx</id><published>2011-01-25T02:29:40Z</published><updated>2011-01-25T02:29:40Z</updated><content type="html">&lt;p&gt;When I was just nine years of age my father introduced me to the computer. It was a &lt;a href="http://en.wikipedia.org/wiki/TRS-80_Color_Computer"&gt;Radio Shack TRS-80 Color Computer&lt;/a&gt; (aka: CoCo). He shared with me the nuances of writing &lt;a href="http://en.wikipedia.org/wiki/Color_BASIC"&gt;BASIC&lt;/a&gt; and it wasn't long before I was in the back seat of the school bus scribbling, on a pad of paper, the code I would later type. My father demonstrated that while my friends were playing their &lt;a href="http://en.wikipedia.org/wiki/Atari_2600"&gt;Atari 2600&lt;/a&gt; consoles, I had the unique opportunity to create my own games on the Coco. One of which provided a great friend of mine hours and hours of hilarity and entertainment.&lt;/p&gt;  &lt;p&gt;It wasn't long before my father was inviting me to tag along as he drove to the local high school where a gathering of fellow Coco enthusiasts assembled. In these meetings all in attendance would chat about their latest challenges and solutions. They would swap the labors of their sleepless nights eagerly gazing into their green and black screens. Friendships were built and business partners were developed. While these experiences at the time in my pre-teen mind were chalked up to simply sharing time with my father, it had a tremendous impact on me later in life.&lt;/p&gt;  &lt;p&gt;This past weekend I attended the &lt;a href="http://www.sqlsaturday.com/45/eventhome.aspx"&gt;Louisville SQL Saturday&lt;/a&gt; (#45). It was great to see that there were some who brought along their children. It is encouraging to see fresh faces in the crowd at our&amp;#160; monthly &lt;a href="http://indiana.sqlpass.org/Home/tabid/2576/Default.aspx"&gt;IndyPASS&lt;/a&gt; meetings. Each time I see the youthful eyes peering from the audience while the finer details of SQL Server is presented, I cannot help but to be transported back to the experiences that I enjoyed in those Coco days. It is exciting to think of how these experiences are impacting their lives and stimulating their minds. Some of these children have actually approached me asking questions about what was presented or simply bragging about their latest discovery in programming.&lt;/p&gt;  &lt;p&gt;One of the topics that arose in the "Women in Technology" session in Louisville, which was masterfully facilitated by &lt;a href="http://www.sqlservercentral.com/blogs/kathi_kellenberger/default.aspx"&gt;Kathi Kellenberger&lt;/a&gt;, was exploring how we could ignite the spark of interest in databases among the youth. It was awesome to hear that there were some that volunteer their time to share their experiences with students. It made me wonder what user groups could achieve if we were to consider expanding our influence and community beyond our immediate peers to include those who are simply enjoying their time with their father or mother.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=99051" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>SQL Prompt Easter Egg</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2011/01/13/98836.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2011/01/13/98836.aspx</id><published>2011-01-14T03:49:00Z</published><updated>2011-01-14T03:49:00Z</updated><content type="html">&lt;p&gt;Having &lt;a href="http://www.red-gate.com/products/sql-development/sql-prompt/"&gt;Red Gate's SQL Prompt&lt;/a&gt; installed with SQL Server Management Studio has saved me many headaches over the years of its use. It is extremely nice to type in a table name and see not only the column names, but also their data types and identification of primary keys. Another cool feature is the built-in short cut scripts that are included toward the bottom of the suggestion box. An example of these short cut scripts would be to type in the letters&amp;#160; &lt;strong&gt;&lt;font color="#008000" face="Courier New"&gt;cv&lt;/font&gt;&lt;/strong&gt; and then hit enter and the following template for &lt;a href="http://msdn.microsoft.com/en-us/library/ms188783.aspx"&gt;CREATE VIEW&lt;/a&gt; will appear:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000"&gt;CREATE VIEW      &lt;br /&gt;--WITH ENCRYPTION, SCHEMABINDING, VIEW_METADATA       &lt;br /&gt;AS       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SELECT /* query specification */       &lt;br /&gt;-- WITH CHECK OPTION       &lt;br /&gt;GO&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;These scripts are great, and on occasion rather humorous. Recently, I was writing an &lt;a href="http://msdn.microsoft.com/en-us/library/ms177523.aspx"&gt;UPDATE&lt;/a&gt; statement that would update a derived and aliased set of data in . An example of such a statement is as follows:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;UPDATE y      &lt;br /&gt;SET a.[FieldA] = b.[FieldB]       &lt;br /&gt;FROM       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; (       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; SELECT       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; a.[FieldA]       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ,b.[FieldB]       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FROM       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [MyTableA] a       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; INNER JOIN [MyTableB] b       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ON a.[PKA] = b.[PKB]       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ) y;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Upon typing the &lt;font color="#008000" face="Courier New"&gt;&lt;strong&gt;UPDATE y&lt;/strong&gt; &lt;/font&gt;portion I hit enter and the expression "&lt;strong&gt;&lt;font color="#008000" face="Courier New"&gt;A A A A R G H !&lt;/font&gt;&lt;/strong&gt;" appeared resulting in an unexpected burst of laughter. With a dash of curiosity and a pinch of research I discovered that at the bottom of the SQL Prompt suggestion box resides a short cut script called "&lt;strong&gt;yell&lt;/strong&gt;", which is described as "&lt;strong&gt;Vent your frustration&lt;/strong&gt;". Another humorous short cut script is "&lt;strong&gt;neo&lt;/strong&gt;", which is described as "&lt;strong&gt;-- I know Kung-Fu&lt;/strong&gt;". All is required for these to activate is to type the first letter and hit enter. I wonder if there are any undocumented ones?&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=98836" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>Embracing Imperfection</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2010/12/04/95984.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2010/12/04/95984.aspx</id><published>2010-12-04T21:55:41Z</published><updated>2010-12-04T21:55:41Z</updated><content type="html">&lt;p&gt;The &lt;strong&gt;pursuit of perfection&lt;/strong&gt; is a road on which we often find ourselves traveling. It is an unpaved road filed with pot-holes and ruts that often destroy our stride. The shoulders of this road are lined with the bones and rotting carcasses of well planned projects, solutions and dreams of others who have dared the journey. &lt;/p&gt;  &lt;p&gt;Often the choice to engage in this travel is a compulsive one. We can't help but to pack our bags and make the trip. We justify it by equating it to the delivery of a quality product or service. We use our past travels as validation of our worthiness and value. Our shared experience, as tortured pilgrims of perfection, reveals that each odyssey that bewitched us resulted in a stark reminder of the very weaknesses and fears that we were attempting to mollify. The voice of the critic that berated us for the lack of craftsmanship was our own. Although, at the end of the journey our own critical voice was joined by the gnashing of teeth of those who could not reap the fruit of your labor due to its lack of timely delivery.&lt;/p&gt;  &lt;p&gt;There is another road in which to travel. It is the &lt;strong&gt;pursuit of embracing imperfection&lt;/strong&gt;. The cost of traveling this route is your contribution to its eternal construction. Each segment is designed uniquely. At times it has the appearance of a patchwork quilt; while other times it is well organized and highly measured. In all cases, its construction has continually advanced and been utilized as each segment was delivered by its architect. &lt;/p&gt;  &lt;p&gt;Those who choose to select this spindle of these crossroads crack open the shells of their fears to reveal the vapor that is within. They construct their houses upon these shells. Through their hunger for mastery they wring every drop of nectar from failure and discard its husks to the ditches of this road. Through their efforts the thoroughfare begins to develop a personality of its own, a beautifully human one, rich with the strengths and weaknesses of all of its contributors. &lt;/p&gt;  &lt;p&gt;Like many of us, the pursuit of perfection has not served me well. In fact, I would say that it has been more damaging than it has been helpful. While the perfectionist in me occasionally makes its presence known, I consider myself a "&lt;strong&gt;recovering perfectionist&lt;/strong&gt;". It is evident to me that there is immense beauty found in imperfection. I choose to embrace it. It is grounding. It is constructive. It is honest.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=95984" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>Converting Encrypted Values</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2010/11/27/95872.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2010/11/27/95872.aspx</id><published>2010-11-28T03:43:21Z</published><updated>2010-11-28T03:43:21Z</updated><content type="html">&lt;p&gt;Your database has been protecting sensitive data at rest using the cell-level encryption features of SQL Server for quite sometime. The employees in the auditing department have been inviting you to their after-work gatherings and buying you drinks. Thousands of customers implicitly include you in their prayers of thanks giving as their identities remain safe in your company's database. &lt;/p&gt;  &lt;p&gt;The cipher text resting snuggly in a column of the &lt;a href="http://msdn.microsoft.com/en-us/library/ms188362.aspx"&gt;varbinary&lt;/a&gt; data type is great for security; but it can create some interesting challenges when interacting with other data types such as the &lt;a href="http://msdn.microsoft.com/en-us/library/ms187339.aspx"&gt;XML&lt;/a&gt; data type. The XML data type is one that is often used as a &lt;a href="http://msdn.microsoft.com/en-us/library/ms187744.aspx"&gt;message type&lt;/a&gt; for the &lt;a href="http://msdn.microsoft.com/en-us/library/ms345108(SQL.90).aspx"&gt;Service Broker&lt;/a&gt; feature of SQL Server. It also can be an interesting data type to capture for auditing or integrating with external systems. The challenge that cipher text presents is that the need for decryption remains even after it has experienced its XML metamorphosis. Quite an interesting challenge nonetheless; but fear not. There is a solution.&lt;/p&gt;  &lt;p&gt;To simulate this scenario, we first will want to create a plain text value for us to encrypt. We will do this by creating a variable to store our plain text value:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;-- set plain text value        &lt;br /&gt;DECLARE @PlainText NVARCHAR(255);         &lt;br /&gt;SET @PlainText = 'This is plain text to encrypt';&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;The next step will be to create a variable that will store the cipher text that is generated from the encryption process. We will populate this variable by using a pre-defined &lt;a href="http://msdn.microsoft.com/en-us/library/ms188357.aspx"&gt;symmetric key&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/ms187798.aspx"&gt;certificate&lt;/a&gt; combination:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;-- encrypt plain text value        &lt;br /&gt;DECLARE @CipherText VARBINARY(MAX);         &lt;br /&gt;OPEN SYMMETRIC KEY SymKey         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; DECRYPTION BY CERTIFICATE SymCert         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; WITH PASSWORD='mypassword2010';         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SET @CipherText = EncryptByKey        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt;(&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Key_GUID('SymKey'),&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; @PlainText&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; );         &lt;br /&gt;CLOSE ALL SYMMETRIC KEYS;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;The value of our newly generated cipher text is &lt;font color="#646b86" face="Courier New"&gt;0x006E12933CBFB0469F79ABCC79A583--&lt;/font&gt;. This will be important as we reference our cipher text later in this post. Our final step in preparing our scenario is to create a table variable to simulate the existence of a table that contains a column used to hold encrypted values. Once this table variable has been created, populate the table variable with the newly generated cipher text:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;-- capture value in table variable        &lt;br /&gt;DECLARE @tbl TABLE (EncVal varbinary(MAX));         &lt;br /&gt;INSERT INTO @tbl (EncVal) VALUES (@CipherText);&lt;/font&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We are now ready to experience the challenge of capturing our encrypted column in an XML data type using the &lt;a href="http://msdn.microsoft.com/en-us/library/ms178107.aspx"&gt;FOR XML&lt;/a&gt; clause:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;-- capture set in xml        &lt;br /&gt;DECLARE @xml XML;         &lt;br /&gt;SET @xml = (SELECT&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; EncVal         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt;FROM @tbl AS MYTABLE        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FOR XML AUTO, BINARY BASE64, ROOT('root'));&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;If you add the &lt;font color="#008000" face="Courier New"&gt;SELECT @XML&lt;/font&gt; statement at the end of this portion of the code you will see the contents of the XML data in its raw format:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#646b86" face="Courier New"&gt;&amp;lt;root&amp;gt;        &lt;br /&gt;&amp;#160; &amp;lt;MYTABLE EncVal=&amp;quot;AG4Skzy/sEafeavMeaWDBwEAAACE--&amp;quot; /&amp;gt;         &lt;br /&gt;&amp;lt;/root&amp;gt;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Strangely, the value that is captured appears nothing like the value that was created through the encryption process. The result being that when this XML is converted into a readable data set the encrypted value will not be able to be decrypted, even with access to the symmetric key and certificate used to perform the decryption. An immediate thought might be to &lt;a href="http://msdn.microsoft.com/en-us/library/ms187928.aspx"&gt;convert&lt;/a&gt; the varbinary data type to either a varchar or nvarchar before creating the XML data. This approach makes good sense. The code for this might look something like the following:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;-- capture set in xml        &lt;br /&gt;DECLARE @xml XML;         &lt;br /&gt;SET @xml = (SELECT&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;CONVERT(NVARCHAR(MAX),EncVal)&lt;/strong&gt; AS EncVal         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FROM @tbl AS MYTABLE         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FOR XML AUTO, BINARY BASE64, ROOT('root'));&lt;/font&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;However, this results in the following error:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#c0504d" face="Courier New"&gt;Msg 9420, Level 16, State 1, Line 26        &lt;br /&gt;XML parsing: line 1, character 37, illegal xml character&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;A quick query that returns &lt;font color="#008000" face="Courier New"&gt;CONVERT(NVARCHAR(MAX),EncVal)&lt;/font&gt; reveals that the value that is causing the error looks like something off of a genuine Chinese menu. While this situation does present us with one of those spine-tingling, expletive-generating challenges, rest assured that this approach is on the right track. With the addition of the "style" argument to the CONVERT method, our solution is at hand. When dealing with converting varbinary data types we have three styles available to us:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;- The first is to not include the style parameter, or use the value of "0". As we see, this style will not work for us. &lt;/p&gt;    &lt;p&gt;- The second option is to use the value of "1" will keep our varbinary value including the "0x" prefix. In our case, the value will be &lt;font color="#646b86" face="Courier New"&gt;0x006E12933CBFB0469F79ABCC79A583--&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;- The third option is to use the value of "2" which will chop the "0x" prefix off of our varbinary value. In our case, the value will be &lt;font color="#646b86" face="Courier New"&gt;006E12933CBFB0469F79ABCC79A583--&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Since we will want to convert this back to varbinary when reading this value from the XML data we will want the "0x" prefix, so we will want to change our code as follows:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;-- capture set in xml        &lt;br /&gt;DECLARE @xml XML;         &lt;br /&gt;SET @xml = (SELECT&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CONVERT(NVARCHAR(MAX),EncVal,1) AS EncVal         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FROM @tbl AS MYTABLE         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FOR XML AUTO, BINARY BASE64, ROOT('root'));&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Once again, with the inclusion of the &lt;font color="#008000" face="Courier New"&gt;SELECT @XML&lt;/font&gt; statement at the end of this portion of the code you will see the contents of the XML data in its raw format:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#646b86" face="Courier New"&gt;&amp;lt;root&amp;gt;        &lt;br /&gt;&amp;#160; &amp;lt;MYTABLE EncVal=&amp;quot;&lt;font color="#646b86" face="Courier New"&gt;0x006E12933CBFB0469F79ABCC79A583--&lt;/font&gt;&amp;quot; /&amp;gt;         &lt;br /&gt;&amp;lt;/root&amp;gt;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Nice! We are now cooking with gas. To continue our scenario, we will want to parse the XML data into a data set so that we can glean our freshly captured cipher text. Once we have our cipher text snagged we will capture it into a variable so that it can be used during decryption:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;-- read back xml        &lt;br /&gt;DECLARE @hdoc INT;         &lt;br /&gt;DECLARE @EncVal NVARCHAR(MAX);         &lt;br /&gt;EXEC sp_xml_preparedocument @hDoc OUTPUT, @xml;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;SELECT @EncVal = EncVal        &lt;br /&gt;FROM OPENXML (@hdoc, '/root/MYTABLE')         &lt;br /&gt;WITH ([EncVal] VARBINARY(MAX) '@EncVal');&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;EXEC sp_xml_removedocument @hDoc;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Finally, the decryption of our cipher text using the &lt;a href="http://msdn.microsoft.com/en-us/library/ms182559.aspx"&gt;DECRYPTBYKEYAUTOCERT&lt;/a&gt; method and the certificate utilized to perform the encryption earlier in our exercise:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;SELECT        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; CONVERT(NVARCHAR(MAX),         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; DecryptByKeyAutoCert        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; (&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CERT_ID('AuditLogCert'),&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; N'mypassword2010',&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; @EncVal&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; )         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ) EncVal;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Ah yes, another hurdle presents itself! The decryption produced the value of &lt;a href="http://en.wikipedia.org/wiki/Null_(SQL)"&gt;NULL&lt;/a&gt; which in cryptography means that either you don't have permissions to decrypt the cipher text or something went wrong during the decryption process (ok, sometimes the value is actually NULL; but not in this case). As we see, the &lt;font color="#008000" face="Courier New"&gt;@EncVal&lt;/font&gt; variable is an nvarchar data type. The third parameter of the DECRYPTBYKEYAUTOCERT method requires a varbinary value. Therefore we will need to utilize our handy-dandy CONVERT method:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;SELECT        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; CONVERT(NVARCHAR(MAX),         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; DecryptByKeyAutoCert        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; (&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CERT_ID('AuditLogCert'),&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; N'mypassword2010',&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CONVERT(VARBINARY(MAX),@EncVal)&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; )         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ) EncVal;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Oh, almost. The result remains NULL despite our conversion to the varbinary data type. This is due to the creation of an varbinary value that does not reflect the actual value of our &lt;font color="#008000" face="Courier New"&gt;@EncVal&lt;/font&gt; variable; but rather a varbinary conversion of the variable itself. In this case, something like &lt;font color="#646b86" face="Courier New"&gt;0x3000780030003000360045003--&lt;/font&gt;. Considering the "style" parameter got us past XML challenge, we will want to consider its power for this challenge as well. Knowing that the value of "1" will provide us with the actual value including the "0x", we will opt to utilize that value in this case:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;SELECT        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; CONVERT(NVARCHAR(MAX),         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; DecryptByKeyAutoCert        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; (&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CERT_ID('SymCert'),&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; N'mypassword2010',&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CONVERT(VARBINARY(MAX),@EncVal,1)&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt;)        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ) EncVal; &lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt; Bingo, we have success! We have discovered what happens with varbinary data when captured as XML data. We have figured out how to make this data useful post-XML-ification. Best of all we now have a choice in after-work parties now that our very happy client who depends on our XML based interface invites us for dinner in celebration. All thanks to the effective use of the style parameter.    &lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=95872" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>Databases and Beer</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2010/11/13/95646.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2010/11/13/95646.aspx</id><published>2010-11-13T18:42:00Z</published><updated>2010-11-13T18:42:00Z</updated><content type="html">&lt;p&gt;It is a bit of a no-brainer: Include the word "beer" in a subject line of an e-mail or blog post title and you can be certain that it will be read. While there are times this practice might be a ploy to increase readership, it is not the case for this blog post. There is inspiration that can be drawn from other industries to which we, as database professionals, can apply in our industry. In this post I will highlight one of my favorite participants of the brewing industry.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.samueladams.com"&gt;The Boston Beer Company&lt;/a&gt; started in the 1970s in Boston, Massachusetts. Others may be more familiar with this company through their Samuel Adams Boston Lager and other various seasonal beers. I am continually inspired by their commitment to mastery of the brewing process to which they evangelize frequently in their commercials. They also are continually in pursuit of pushing the boundaries of beer as we know it while working within traditional constraints.&lt;/p&gt;  &lt;p&gt;A recent example of this is their collaboration with &lt;a href="http://www.weihenstephaner.de/"&gt;Weihenstephan Brewery&lt;/a&gt; of Munich, Germany to produce the soon to be released &lt;a href="http://www.uncrate.com/men/culture/drinks/sam-adams-infinium-beer/"&gt;Infinium&lt;/a&gt; beer. This beer, while brewed as an ale, is touted as something closer to something like Champaign - all while complying with the &lt;a href="http://en.wikipedia.org/wiki/Reinheitsgebot"&gt;Reinheitsgebot&lt;/a&gt;. The Reinheitsgebot is also known as the "German Beer Purity Law" which was originated in 1516. This law states that beer is to consist of water, barley, hops and yeast. That's it. Quite a limiting constraint indeed. and yet, The Boston Beer Company pushed forward.&lt;/p&gt;  &lt;p&gt;Much like the process of brewing, the discipline of database design and architecture is one that is continually in process and driven by the pursuit of mastery. While we do not have purity laws to constrain us, we have many other types: best practices, company policies, government regulations, security and budgets. Through our fellow comrades, we discuss the challenges and constraints in which we operate. We boil down the principles and theories that define our profession. We reassemble these into something that is complementary to the business needs that we must fulfill. As a result, it is not uncommon to see something amazingly innovative in a small business who is pushing the boundaries of their database well beyond its intended state. It is equally common to see innovation in the use of features available in the more advanced features of databases that are found in large businesses.&lt;/p&gt;  &lt;p&gt;The tag line for The Boston Beer Company is: "Take Pride In Your Beer.", I would like to offer an alternative and say "Take Pride In Your Database." So, As you pour your next Boston Lager into a frosted glass, consider those who spend their lives mastering the craft of brewing and strive to interject their spirit into everything that you do as a database professional.&lt;/p&gt;  &lt;p&gt;Cheers! &lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=95646" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>Return to Sender: Identity Values and Triggers</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2010/10/02/94871.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2010/10/02/94871.aspx</id><published>2010-10-02T23:03:00Z</published><updated>2010-10-02T23:03:00Z</updated><content type="html">&lt;p&gt;In my previous post I wrote about &lt;a href="/community/blogs/johnm/archive/2010/08/28/94224.aspx"&gt;using the OUTPUT clause&lt;/a&gt; of an INSERT statement to obtain the auto-generated identity value of a row. Quickly and easily obtaining the identity value will allow the application to immediately reference the new row or add rows to another table that use the identity value as a foreign key reference.&lt;/p&gt;  &lt;p&gt;A common, and simple, example of this use would be a stored procedure that issues an &lt;a href="http://msdn.microsoft.com/en-us/library/ms174335.aspx"&gt;INSERT&lt;/a&gt; statement and returns a result set that contains the identity value of the new row. Below is sample code that creates a table and an stored procedure to illustrate this process:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- creates the table        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;CREATE TABLE [dbo].[MyTable]        &lt;br /&gt;(         &lt;br /&gt;    [MyID] [int] IDENTITY(1,1) NOT NULL,         &lt;br /&gt;    [MyColumn] [varchar](50) NOT NULL         &lt;br /&gt;) ON [PRIMARY];         &lt;br /&gt;GO&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- creates the stored procedure        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;CREATE PROCEDURE [dbo].[InsertMyTable]        &lt;br /&gt;(         &lt;br /&gt;    @MyColumn varchar(50)         &lt;br /&gt;)         &lt;br /&gt;AS         &lt;br /&gt;BEGIN         &lt;br /&gt;    -- declare table varaible to capture the identity value         &lt;br /&gt;    DECLARE @MyTableVar TABLE (MyID INT);         &lt;br /&gt;    -- insert the record         &lt;br /&gt;    INSERT INTO [dbo].[MyTable]         &lt;br /&gt;    ([MyColumn])         &lt;br /&gt;    OUTPUT INSERTED.MyID INTO @MyTableVar         &lt;br /&gt;    VALUES (@MyColumn);         &lt;br /&gt;    -- return the identity value         &lt;br /&gt;    SELECT MyID FROM @MyTableVar;    &lt;br /&gt;END         &lt;br /&gt;GO&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- execute the stored procedure adding a row and returning the new identity value        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;EXEC [dbo].[InsertMyTable] 'This is the first test row';&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;All is well and good in regard to this sample; but imagine a more complicated scenario: There are two databases. The first database contained stored procedure that formerly wrote to a table; but as a second database was created there was a need to seamlessly integrate them. The simple use of the OUTPUT clause alone just wasn't enough to meet the need. To accomplish the seamlessness of this integration the table was moved to the second database and a view was created in the first database to simulate the former table's existence. In order to accomplish some other integration functionality, such as creating a &lt;a href="http://msdn.microsoft.com/en-us/library/bb522893.aspx"&gt;Service Broker&lt;/a&gt; message, "&lt;a href="http://msdn.microsoft.com/en-us/library/ms178134.aspx"&gt;instead of triggers&lt;/a&gt;" were added to the view. To simulate this environment, I have provided the following sample code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- rename the original table to simulate the move to another database        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;EXEC sp_RENAME [MyTable] , 'MyTable2';&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- create a view to represent the prior table        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;CREATE VIEW [dbo].[MyTable]        &lt;br /&gt;AS         &lt;br /&gt;    SELECT    &lt;br /&gt;        MyID, MyColumn         &lt;br /&gt;    FROM         &lt;br /&gt;        dbo.MyTable2;         &lt;br /&gt;GO&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- create the instead of trigger to write to new table        &lt;br /&gt;-- Please note that the "other integration functionality" noted above is not included for simplicity         &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;CREATE TRIGGER [dbo].[MyTable_InsteadOfInsert]        &lt;br /&gt;ON [dbo].[MyTable]         &lt;br /&gt;INSTEAD OF INSERT         &lt;br /&gt;AS         &lt;br /&gt;BEGIN  &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;    -- nocount was added so that this insert is not reflected in the records affected        &lt;br /&gt;    SET NOCOUNT ON;         &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;    -- declare table varaible to capture the identity value        &lt;br /&gt;    DECLARE @MyTableVar TABLE (MyID INT);         &lt;br /&gt;    -- insert the record         &lt;br /&gt;    INSERT INTO [dbo].[MyTable2]         &lt;br /&gt;    ([MyColumn])         &lt;br /&gt;    OUTPUT INSERTED.MyID INTO @MyTableVar         &lt;br /&gt;    SELECT         &lt;br /&gt;        [MyColumn]         &lt;br /&gt;    FROM inserted;         &lt;br /&gt;    -- return the identity value         &lt;br /&gt;    SELECT MyID FROM @MyTableVar;         &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;END        &lt;br /&gt;GO&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- modify the InsertMyTable stored procedure so that two sets are not returned        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;ALTER PROCEDURE [dbo].[InsertMyTable]        &lt;br /&gt;(         &lt;br /&gt;    @MyColumn varchar(50)         &lt;br /&gt;)         &lt;br /&gt;AS         &lt;br /&gt;BEGIN         &lt;br /&gt;    -- insert the record         &lt;br /&gt;    INSERT INTO [dbo].[MyTable]         &lt;br /&gt;    ([MyColumn])         &lt;br /&gt;    VALUES (@MyColumn);         &lt;br /&gt;END         &lt;br /&gt;GO&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- execute the stored procedure adding a row and returning the new identity value        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;EXEC [dbo].[InsertMyTable] 'This is the second test row';&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;After the execution of the InsertMyTable stored procedure, the identity value that was generated in the new table is returned. You can also run the following SELECT statements and see that the view reflects the same records as the new table:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;SELECT * FROM dbo.MyTable;        &lt;br /&gt;SELECT * FROM dbo.MyTable2;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Recently, I encountered a bit of a "&lt;a href="http://www.phrases.org.uk/meanings/fly-in-the-ointment.html"&gt;fly in the ointment&lt;/a&gt;" when I read the updated MSDN article for "&lt;a href="http://msdn.microsoft.com/en-us/library/ms189799.aspx"&gt;Create Trigger&lt;/a&gt;" which states: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;&lt;font color="#0000ff"&gt;"The ability to return results from triggers will be removed in a future version of SQL Server. Triggers that return result sets may cause unexpected behavior in applications that are not designed to work with them. Avoid returning result sets from triggers in new development work, and plan to modify applications that currently do this. To prevent triggers from returning result sets, set the &lt;/font&gt;&lt;/em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms186337.aspx"&gt;&lt;em&gt;&lt;font color="#0000ff"&gt;disallow results from triggers option&lt;/font&gt;&lt;/em&gt;&lt;/a&gt;&lt;em&gt;&lt;font color="#0000ff"&gt; to 1."&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Yowza! In the aforementioned scenario we are depending on the "Instead of trigger" to return the result set from the &lt;a href="http://msdn.microsoft.com/en-us/library/ms177564.aspx"&gt;OUTPUT&lt;/a&gt; clause. If the "disallow results from triggers option" is already set to the value of 1 on your instance; you certainly had a head scratching moment with the sample code above and experienced this challenge first-hand.&lt;/p&gt;  &lt;p&gt;One solution that I would like to offer would be the following: Create a column in the table that would store a globally unique identifier (&lt;a href="http://en.wikipedia.org/wiki/Globally_unique_identifier"&gt;GUID&lt;/a&gt;) value that is generated by the stored procedure and passed as part of the INSERT statement. Once the new record is inserted, it could be recalled by the GUID to obtain the identity value that is generated. To demonstrate this make the following modifications to our simulated environment:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- add a new column to the table to capture a GUID value        &lt;br /&gt;ALTER TABLE [dbo].[MyTable2]         &lt;br /&gt;ADD [IntegrationID] UNIQUEIDENTIFIER NULL;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- a reference to the new column is added to the view        &lt;br /&gt;ALTER VIEW [dbo].[MyTable]         &lt;br /&gt;AS         &lt;br /&gt;    SELECT    &lt;br /&gt;        MyID, MyColumn, IntegrationID         &lt;br /&gt;    FROM         &lt;br /&gt;        dbo.MyTable2;         &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;GO &lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- add the new column to the trigger and remove the use of the OUTPUT clause        &lt;br /&gt;ALTER TRIGGER [dbo].[MyTable_InsteadOfInsert]         &lt;br /&gt;ON [dbo].[MyTable]         &lt;br /&gt;INSTEAD OF INSERT         &lt;br /&gt;AS         &lt;br /&gt;BEGIN         &lt;br /&gt;    SET NOCOUNT ON;         &lt;br /&gt;    -- insert the record         &lt;br /&gt;    INSERT INTO [dbo].[MyTable2]         &lt;br /&gt;    ([MyColumn],[IntegrationID])         &lt;br /&gt;    SELECT         &lt;br /&gt;        [MyColumn], [IntegrationID]         &lt;br /&gt;    FROM inserted;         &lt;br /&gt;END         &lt;br /&gt;GO &lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- add code to generate the GUID to recall the new record        &lt;br /&gt;ALTER PROCEDURE [dbo].[InsertMyTable]         &lt;br /&gt;    (         &lt;br /&gt;        @MyColumn varchar(50)         &lt;br /&gt;    )         &lt;br /&gt;    AS         &lt;br /&gt;    BEGIN         &lt;br /&gt;        -- used to capture the identity value that is returned         &lt;br /&gt;        DECLARE @GUID UNIQUEIDENTIFIER;         &lt;br /&gt;        SET @GUID = NEWID();         &lt;br /&gt;        -- insert the record         &lt;br /&gt;        INSERT INTO [dbo].[MyTable]         &lt;br /&gt;        ([MyColumn],[IntegrationID])         &lt;br /&gt;        VALUES         &lt;br /&gt;        (@MyColumn,@GUID);         &lt;br /&gt;        -- return identity value         &lt;br /&gt;        SELECT [MyID]         &lt;br /&gt;        FROM [dbo].[MyTable]  with (nolock)         &lt;br /&gt;        WHERE [IntegrationID] = @GUID;         &lt;br /&gt;    END&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- execute the stored procedure adding a row and returning the new identity value        &lt;br /&gt;EXEC [dbo].[InsertMyTable] 'This is the third test row';&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;After the execution of this modified version of the InsertMyTable stored procedure, the newly generated identity value is returned without the need for the trigger to provide a return set; thus overcoming the reliance on a deprecated trigger feature.&lt;/p&gt;  &lt;p&gt;This scenario was one that I recently experienced first hand when integrating an older database that had many dependencies attached to the original version of a specific table. The goal in this integration was to keep the original database as close to untouched as it could be while achieving a near real-time synchronization with the new database. This specific aspect was only a small part of the overall integration solution; but it proved to be an interesting challenge to overcome. &lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=94871" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>OUTPUT Clause Saves The Day</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2010/08/28/94224.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2010/08/28/94224.aspx</id><published>2010-08-28T18:58:09Z</published><updated>2010-08-28T18:58:09Z</updated><content type="html">&lt;p&gt;Frank, the DBA, pecked at his keyboard with feverish rapidity. His tongue pointed from his lips caused his tense breathing to be audible to the entire department. His eyes were glazed with that "&lt;em&gt;don't bother me I am deep in code&lt;/em&gt;" look that staged off all but the bravest of co-workers. Amid the array of stored procedures that were spawned in Frank's day of zoning was one that was used to insert a row into a table and return the identity value that was just created so that other calls can utilize the value.&lt;/p&gt;  &lt;p&gt;In this stored procedure, Frank utilized the &lt;a href="http://msdn.microsoft.com/en-us/library/ms187342.aspx"&gt;@@IDENTITY&lt;/a&gt; system function to derive the new identity value:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;CREATE PROCEDURE [dbo].[InsertMyTable]     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; (      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; @ColumnValue [varchar] (50)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; )      &lt;br /&gt;AS      &lt;br /&gt;BEGIN &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160; -- insert new record&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160; INSERT INTO [Demo].[dbo].[MyTable]     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; (      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [MyColumn]      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; , [MyDate]      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; )      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; VALUES      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; (      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; @ColumnValue      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; , GETDATE()      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; );&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; -- declare variable to return     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; DECLARE @id BIGINT;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; -- set the value of the variable to @@IDENTITY     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt;SET @id = @@IDENTITY;&lt;/font&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;-- return the new identity value       &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt;SELECT @id; &lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;END     &lt;br /&gt;GO&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;In his unit testing he executed the following command and was satisfied that it was functioning as expected:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;EXEC [dbo].[InsertMyTable] 'MyTestValue';&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Although, later he was confounded by the fact that the stored procedure did not consistently return the identity value when utilized in conjunction with the application development environment. Frank scanned the Internet like a whale hunting for plankton. He read blogs, forums, technical articles and flipped through his mountain of books and magazines that somehow supported a rattling cage filled with hamsters at its peak. He could not identify any great explanation of why this inconsistency exists. &lt;/p&gt;  &lt;p&gt;He experimented with the alternative system functions of &lt;a href="http://msdn.microsoft.com/en-us/library/ms190315.aspx"&gt;SCOPE_IDENTITY&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/ms175098.aspx"&gt;IDENT_CURRENT&lt;/a&gt; to no avail. Frustrated, he wandered out of the office in a daze, scratching his head and having a fierce conversation to himself - which subsequently frightened and cut short the smoke breaks of all that were hanging around the exit door of the office building. &lt;/p&gt;  &lt;p&gt;It wasn't long before Frank found himself at the neighborhood pub sitting with his good friend and fellow data-geek, Kyle. While everyone else at the pub were ruing their latest blunder with their significant others, Frank and Kyle were commiserating about their latest coding challenges. With a significant air of resignation, Frank described his conundrum with @@IDENTITY - complete with dramatic use of waving hands and sound effects. Kyle, with cool confidence, took a sip of his tall glass of &lt;a href="http://www.samueladams.com/age-gate.aspx?ReturnUrl=/index.aspx"&gt;Sam Adams&lt;/a&gt; and said "&lt;em&gt;Did you try the &lt;a href="http://msdn.microsoft.com/en-us/library/ms177564.aspx"&gt;output clause&lt;/a&gt; of the &lt;/em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms174335.aspx"&gt;&lt;em&gt;INSERT&lt;/em&gt;&lt;/a&gt;&lt;em&gt; statement&lt;/em&gt;?" - All drew quiet.&lt;/p&gt;  &lt;p&gt;Frank's eyes lit up like a neon sign in the dark. It was as if the weight of the world was lifted from his shoulders. Frank swigged down the remainder of his beverage, patted Kyle on the shoulder and said "&lt;em&gt;Order me another, I will be right back&lt;/em&gt;!". Frank raced back to the office so quickly he was not sure that he actually opened the door. He quickly revised his stored procedure:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;CREATE PROCEDURE [dbo].[InsertMyTable]     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; (      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; @ColumnValue [varchar] (50)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; )      &lt;br /&gt;AS      &lt;br /&gt;BEGIN &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160; -- declaration of table variable     &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160; DECLARE @MyTableVar TABLE (IdentityColumn BIGINT);     &lt;br /&gt;&amp;#160;&amp;#160; &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt; -- performs the insert     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; INSERT INTO [Demo].[dbo].[MyTable]      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; (      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [MyColumn]      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; , [MyDate]      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; )      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; OUTPUT INSERTED.IdentityColumn INTO @MyTableVar      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; VALUES      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; (      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; @ColumnValue      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; , GETDATE()      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; );&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; -- returns the new identity value as a dataset&lt;/font&gt;&lt;font color="#008000" face="Courier New"&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; SELECT IdentityColumn FROM @MyTableVar; &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;END     &lt;br /&gt;GO&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Further testing proved that Frank's modification was effective and reliable. This moment of enlightenment was so inspiring that the cleaning lady of the office was later heard describing something that looked like a halo was emitting from Frank's head. With a hop and a kick of his heels, Frank sprinted back to the pub and, in his great appreciation, bought his friend Kyle a steak dinner. At that moment, Frank was deeply grateful for his network of friends and a deeper appreciation for the subtleties of Transact-SQL. Although, the behavior of @@IDENTITY still baffles him, he hasn't lost any sleep over it.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=94224" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>The Database Artist</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2010/07/31/93692.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2010/07/31/93692.aspx</id><published>2010-07-31T21:04:53Z</published><updated>2010-07-31T21:04:53Z</updated><content type="html">&lt;p&gt;This past Friday I journeyed to the local bookstore and picked up a copy of &lt;a href="http://sethgodin.typepad.com/"&gt;Seth Godin's&lt;/a&gt;&amp;#160; latest book titled "&lt;a href="http://www.amazon.com/Linchpin-Are-Indispensable-Seth-Godin/dp/1591843162"&gt;Linchpin&lt;/a&gt;". This book explores the concept of work and how we can become truly valuable. In this book Seth encourages us to become artists; to recognize the difference between doing a job and creating art. &lt;/p&gt;  &lt;p&gt;The book offers a simple definition of art: "&lt;em&gt;Art is a personal gift that changes the recipient&lt;/em&gt;." He further explains that the essence of art is not a measurement of a person's skills or the quality of the end result; but in the gift and change aspect. This prompted me to think about how I and others approach our roles as database professionals.&lt;/p&gt;  &lt;p&gt;Majority of us were hired as DBAs (or the many variants of that role) with specific tasks and responsibilities in mind. If asked what we are paid for many of us would have no problem identifying these items. This would be what we define as our "job". We were hired to protect the confidentiality, integrity and accessibility of the data that is stored within the many databases throughout our companies. We were hired to backup these same databases and restore them when needed. We were hired to maximize and preserve the performance of these databases. We were hired to architect and build data storage systems to which data is efficiently maintained.&lt;/p&gt;  &lt;p&gt;In general, the grand majority of us fulfill our job with a high level of skill, effectiveness and consistently. It is what is expected when our employers cut that paycheck with our name on the "pay to the order of" line. It is when we exceed our obligatory fulfillment of duty in a fashion that changes those around us to which we truly become valuable. It is when these activities are sprung from our passion rather than through expectation of financial or positional reciprocation that we discover the artist in ourselves. &lt;/p&gt;  &lt;p&gt;Imagine Frank, the DBA, being invited to a Marketing project meeting. It is clear that he has been invited specifically for their understanding of the existing databases and how the data that they need to complete the project can be gleaned. Frank confidently and competently answers their questions. Upon the meeting's conclusion the Marketing department is satisfied. Frank met their expectations and the project was completed as it was originally planned. &lt;/p&gt;  &lt;p&gt;Now Imagine Chuck, the DBA, being invited to the same Marketing project meeting. He too was invited for his understanding of the databases and how the data can be gleaned to complete the project. Chuck confidently and competently answered their questions. In addition, Chuck identifies an overlooked aspect of the project and presents the issue in non-technical terms. The Marketing department is elated. The project, and the business, was changed for the better due to Chuck's contribution.&lt;/p&gt;  &lt;p&gt;What differentiated Frank from Chuck? Chuck regularly takes the time to visit the Marketing department. He gets to know the employees of the department, the tasks that they perform and the challenges that they face. Through his semi-casual conversations with the Marketing Director he learns of the department's visions and constraints. Not only is Chuck a more knowledgeable DBA because of these practices, he has established a trusting collaborative relationship. While Frank performs his job very well, Chuck masterfully performs his art. &lt;/p&gt;  &lt;p&gt;Albert Einstein once said "&lt;em&gt;Try not to become a man of success, rather try to become a man of value&lt;/em&gt;." I believe that this quote expresses the gist of Seth Godin's message through his excellent book. Are we satisfied with the letters DBA meaning "Database Administrator" or should it be "Database Artist"? In the age of the expendable employee I contend that it is a critical change in title.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=93692" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>EncryptByKey in Large Quantities</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2010/07/05/93351.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2010/07/05/93351.aspx</id><published>2010-07-04T23:56:14Z</published><updated>2010-07-04T23:56:14Z</updated><content type="html">&lt;p&gt;Most publications that discuss encryption, including my &lt;a href="http://www.amazon.com/Protecting-Server-Data-John-Magnabosco/dp/1906434271/ref=sr_1_5?ie=UTF8&amp;amp;s=books&amp;amp;qid=1278280654&amp;amp;sr=8-5"&gt;own book&lt;/a&gt;, demonstrate the use of the &lt;a href="http://technet.microsoft.com/en-us/library/ms174361.aspx"&gt;EncryptByKey&lt;/a&gt; function as follows:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- Opens the symmetric key with certificate        &lt;br /&gt;OPEN SYMMETRIC KEY SampleSymKey         &lt;br /&gt;&amp;#160;&amp;#160; DECRYPTION BY CERTIFICATE SampleCertificate         &lt;br /&gt;&amp;#160;&amp;#160; WITH PASSWORD = &lt;/font&gt;&lt;a href="mailto:'MyStr0ngP@ssw0rD'"&gt;&lt;font color="#008000"&gt;'MyStr0ngP@ssw0rD'&lt;/font&gt;&lt;/a&gt;&lt;font color="#008000"&gt;;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- Perform encryption on plain text value and capture in a variable        &lt;br /&gt;DECLARE @EncVal varbinary(max);         &lt;br /&gt;SET @EncVal = EncryptByKey(Key_GUID('SampleSymKey'), 'TestValue'); &lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- Use the encrypted value that is captured in the variable        &lt;br /&gt;INSERT INTO dbo.SampleEncTable (PlainVal, EncVal)         &lt;br /&gt;VALUES ('TestValue', @EncVal); &lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- Close the symmetric key        &lt;br /&gt;CLOSE SYMMETRIC KEY SampleSymKey;         &lt;br /&gt;GO&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Execute a query that utilizes the &lt;a href="http://technet.microsoft.com/en-us/library/ms182559.aspx"&gt;DecryptByKeyAutoCert&lt;/a&gt; and you can see that the EncryptByKey function performs very well:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;SELECT        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; CONVERT(varchar,DECRYPTBYKEYAUTOCERT(         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Cert_ID('SampleCertificate'),         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; N'MyStr0ngP@ssw0rD',         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; EncVal)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ) as DecryptedVal         &lt;br /&gt;FROM         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; dbo.SampleEncTable;         &lt;br /&gt;GO&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The challenge with these examples are that, while they effectively demonstrate the functionality of these cryptographic functions, they represent only the encryption and decryption of a singular value.&lt;/p&gt;  &lt;p&gt;If you were faced with a mass encryption effort, such as the conversion of a legacy database containing plain text sensitive data to a new database in which the converted sensitive data is encrypted, the utilization of a cursor to perform the above sample for each record is very tempting and excruciatingly expensive. Below is a sample of such an attempt:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- Opens the symmetric key with certificate        &lt;br /&gt;OPEN SYMMETRIC KEY SampleSymKey         &lt;br /&gt;&amp;#160;&amp;#160; DECRYPTION BY CERTIFICATE SampleCertificate         &lt;br /&gt;&amp;#160;&amp;#160; WITH PASSWORD = 'MyStr0ngP@ssw0rD'; &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000"&gt;-- Creating a cursor (oooh, you desperate coder, you. ;D)        &lt;br /&gt;DECLARE @LegVal varchar(9);         &lt;br /&gt;DECLARE EncCur CURSOR         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; FOR SELECT         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; LegacyVal         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; FROM         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; dbo.SampleLegacyTable; &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000"&gt;-- Open Cursor (screeeeeeech)        &lt;br /&gt;&lt;/font&gt;&lt;font color="#008000"&gt;OPEN EncCur;        &lt;br /&gt;FETCH NEXT FROM EncCur INTO @LegVal; &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000"&gt;-- Loop through cursor (mommy, I want off this ride!)        &lt;br /&gt;WHILE @@FETCH_STATUS = 0         &lt;br /&gt;BEGIN&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000"&gt;&amp;#160;&amp;#160;&amp;#160; -- Perform encryption on plain text value and capture in a variable        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; DECLARE @EncVal varbinary(max);         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SET @EncVal = EncryptByKey(Key_GUID('SampleSymKey'), @LegVal); &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000"&gt;&amp;#160;&amp;#160;&amp;#160; -- Use the encrypted value that is captured in the variable        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; INSERT INTO dbo.SampleEncTable (PlainVal, EncVal)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; VALUES ('TestValue', @EncVal);&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000"&gt;&amp;#160;&amp;#160;&amp;#160; FETCH NEXT FROM EncCur INTO @LegVal;        &lt;br /&gt;END&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000"&gt;-- Close Cursor (bang!)        &lt;br /&gt;CLOSE EncCur;         &lt;br /&gt;DEALLOCATE EncCur;&amp;#160;&amp;#160;&amp;#160; &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000"&gt;-- Close the symmetric key        &lt;br /&gt;CLOSE SYMMETRIC KEY SampleSymKey;         &lt;br /&gt;GO&lt;/font&gt;&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms180169.aspx"&gt;Cursors&lt;/a&gt; are a &lt;a href="http://en.wikipedia.org/wiki/Procedural_programming"&gt;procedural programming&lt;/a&gt; concept which deals with data in a row-by-row method. One row is retrieved and processed at a time. T-SQL is a set based, or &lt;a href="http://en.wikipedia.org/wiki/Declarative_programming"&gt;declarative&lt;/a&gt;, programming language and works best when set based commands are used to process data. An example of using the EncryptByKey function in a set based fashion, and without the dreaded cursor, the statement would appear something like the following:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#008000"&gt;-- Opens the symmetric key with certificate        &lt;br /&gt;OPEN SYMMETRIC KEY SampleSymKey         &lt;br /&gt;&amp;#160;&amp;#160; DECRYPTION BY CERTIFICATE SampleCertificate         &lt;br /&gt;&amp;#160;&amp;#160; WITH PASSWORD = 'MyStr0ngP@ssw0rD'; &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000"&gt;-- Encrypt legacy data as a set (zing!)        &lt;br /&gt;INSERT INTO dbo.SampleEncTable         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; (         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; PlainVal,         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; EncVal         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; )         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SELECT         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; LegacyVal,         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; EncryptByKey(Key_GUID('SampleSymKey'), LegacyVal)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; FROM         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; dbo.SampleLegacyTable;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#008000"&gt;-- Close the symmetric key        &lt;br /&gt;CLOSE SYMMETRIC KEY SampleSymKey;         &lt;br /&gt;GO&lt;/font&gt;&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;With the use of the above example, your legacy data has found its new home in a highly efficient manner. The sensitive data has been encrypted and is ready to be disclosed is a safe manner.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=93351" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>What If TDE Was Available In Standard Edition?</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2010/06/21/93146.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2010/06/21/93146.aspx</id><published>2010-06-21T04:30:26Z</published><updated>2010-06-21T04:30:26Z</updated><content type="html">&lt;p&gt;Imagine a database that contained information about a company's customers. Many employees depend upon this information to perform their daily duties. This information flows into this database like a waterfall of data. Reports are pulled to gain insight on the latest product sales. Automated processes kick off on regular intervals to feed other databases or send the information to a third party.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Getting Sensitive&lt;/strong&gt;     &lt;br /&gt;Among this information resides pieces of data that is considered sensitive. A customer's credit card number that was used to order the latest widget, a customer's federal identification number used for obtaining their credit rating to qualify for reoccurring payments, a customer's bank account and routing number to process a check payment for their order. This is data that you can find just about anywhere in the data landscape around the world.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;There Are No Small Businesses, Just Small Budgets      &lt;br /&gt;&lt;/strong&gt;Now imagine that this database contains less than 2 million records. The company itself is rather small; but keeping itself in the black, financially, on a regular basis. The data mining activities at this company primarily consist of basic queries and reports. The size of the data file is hardly worth the consideration of data compression. Performance is average and acceptable; but it's primary performance bottleneck resides in the processing power of the glorified desktop that resides in a closet. Hardly the candidate for purchasing a license of SQL Server 2008 Enterprise Edition.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The Incredible Disappearing Backup Tape&lt;/strong&gt;     &lt;br /&gt;The day ends and everyone packs away their day's work to begin their travels toward their loved ones, be it family, friends or beer. One employee who is in arm's reach of the latest backup tape throws it into their bag and leaves the building. At that point the sensitive data contained on that tape can easily be restored into another instance and gleaned for dastardly purposes. This threat is not unique to large businesses with enterprise applications. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;TDE To The Rescue      &lt;br /&gt;&lt;/strong&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb934049.aspx"&gt;Transparent Data Encryption&lt;/a&gt; (TDE) is a security feature that was designed to aid in the protection of sensitive data by encrypting the physical files of a database. This level of protection makes a database restoration on another instance extremely difficult without the appropriate &lt;a href="http://msdn.microsoft.com/en-us/library/ms189586.aspx"&gt;key hierarchy&lt;/a&gt; in place. Unfortunately, this feature is not available in SQL Server 2008 Standard Edition.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Imagine If You Will      &lt;br /&gt;&lt;/strong&gt;What if TDE was available in Standard Edition? The soon to be ex-employee who has stolen the backup tape will make the attempt to restore the database. Instead of getting a slew of credit card numbers they receive an error. The company is protected, the customers are protected. Our global data environment is a much safer place. &lt;/p&gt;  &lt;p&gt;You shouldn't have to be a large company with a large budget to create a secure environment. TDE should be considered a basic security feature and therefore included in Standard Edition. Not to mention that it would also offer a slight advantage over the competition. Enterprise Edition features have trickled down to Standard Edition as recently as SQL Server 2008 R2 with the &lt;a href="http://technet.microsoft.com/en-us/library/bb964719.aspx"&gt;backup compression&lt;/a&gt; feature. It is my hope that TDE will soon follow suit.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=93146" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry><entry><title>Database Owner Conundrum</title><link rel="alternate" type="text/html" href="http://www.simple-talk.com/community/blogs/johnm/archive/2010/06/05/92917.aspx" /><id>http://www.simple-talk.com/community/blogs/johnm/archive/2010/06/05/92917.aspx</id><published>2010-06-05T13:30:14Z</published><updated>2010-06-05T13:30:14Z</updated><content type="html">&lt;p&gt;Have you ever restored a database from a production environment on Server A into a development environment on Server B and had some items, such as &lt;a href="http://msdn.microsoft.com/en-us/library/bb522893.aspx"&gt;Service Broker&lt;/a&gt;, mysteriously cease functioning? You might want to consider reviewing the &lt;a href="http://msdn.microsoft.com/en-us/library/aa905208(SQL.80).aspx"&gt;database owner&lt;/a&gt; property of the database.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The Scenario      &lt;br /&gt;&lt;/strong&gt;Recently, I was developing some messaging functionality that utilized the Service Broker feature of SQL Server in a development environment. Within the instance of the development environment resided two databases: One was a restored version of a production database that we will call "RestoreDB". The second database was a brand new database that has yet to exist in the production environment that we will call "DevDB". The goal is to setup a communication path between RestoreDB and DevDB that will later be implemented into the production database.&lt;/p&gt;  &lt;p&gt;After implementing all of the Service Broker objects that are required to &lt;a href="http://msdn.microsoft.com/en-us/library/bb839495.aspx"&gt;communicate within a database&lt;/a&gt; as well as &lt;a href="http://msdn.microsoft.com/en-us/library/bb839498.aspx"&gt;between two databases on the same instance&lt;/a&gt; I found myself a bit confounded. My testing was showing that the communication was successful when it was occurring internally within DevDB; but the communication between RestoreDB and DevDB did not appear to be working. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Profiler to the rescue      &lt;br /&gt;&lt;/strong&gt;After carefully reviewing my code for any misspellings, missing commas or any other minor items that might be a syntactical cause of failure, I decided to launch &lt;a href="http://msdn.microsoft.com/en-us/library/ms181091.aspx"&gt;Profiler&lt;/a&gt; to aid in the troubleshooting. After simulating the cross database messaging, I noticed the following error appearing in Profiler:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;An exception occurred while enqueueing a message in the target queue. Error: 33009, State: 2. The database owner SID recorded in the master database differs from the database owner SID recorded in database '[Database Name Here]'. You should correct this situation by resetting the owner of database '[Database Name Here]' using the ALTER AUTHORIZATION statement.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Now, this error message is a helpful one. Not only does it identify the issue in plain language, it also provides a potential solution. An execution of the following query that utilizes the catalog view &lt;a href="http://msdn.microsoft.com/en-us/library/ms190336.aspx"&gt;sys.transmission_queue&lt;/a&gt; revealed the same error message for each communication attempt:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;SELECT     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; *      &lt;br /&gt;FROM&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; sys.transmission_queue;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Seeing the situation as a learning opportunity I dove a bit deeper.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Reviewing the database properties&lt;/strong&gt;&amp;#160; &lt;br /&gt;The owner of a specific database can be easily viewed by right-clicking the database in &lt;a href="http://msdn.microsoft.com/en-us/library/ms174173.aspx"&gt;SQL Server Management Studio&lt;/a&gt; and selecting the "properties" option. The owner is listed on the "General" page of the properties screen. In my scenario, the database in the production server was created by Frank the DBA; therefore his server login appeared as the owner: "ServerName\Frank". While this is interesting information, it certainly doesn't tell me much in regard to the &lt;a href="http://msdn.microsoft.com/en-us/library/ms403629.aspx"&gt;SID&lt;/a&gt; (security identifier) and its existence, or lack thereof, in the master database as the error suggested.&lt;/p&gt;  &lt;p&gt;I pulled together the following query to gather more interesting information:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;SELECT      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; a.name      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; , a.owner_sid      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; , b.sid      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; , b.name      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; , b.type_desc      &lt;br /&gt;FROM&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; master.sys.databases a      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; LEFT OUTER JOIN master.sys.server_principals b      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ON a.owner_sid = b.sid      &lt;br /&gt;WHERE      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; a.name not in ('master','tempdb','model','msdb');&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;This query also helped identify how many other user databases in the instance were experiencing the same issue. In this scenario, I saw that there were no matching SIDs in &lt;a href="http://technet.microsoft.com/en-us/library/ms188786.aspx"&gt;server_principals&lt;/a&gt; to the owner SID for my database. What login should be used as the database owner instead of Frank's? The system stored procedure &lt;a href="http://technet.microsoft.com/en-us/library/ms190304.aspx"&gt;sp_helplogins&lt;/a&gt; will provide a list of the valid logins that can be used. Here is an example of its use, revealing all available logins: &lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;EXEC sp_helplogins;&lt;/font&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Fixing a hole     &lt;br /&gt;&lt;/strong&gt;The error message stated that the recommended solution was to execute the &lt;a href="http://technet.microsoft.com/en-us/library/ms187359.aspx"&gt;ALTER AUTHORIZATION&lt;/a&gt; statement. The full statement for this scenario would appear as follows:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;ALTER AUTHORIZATION ON DATABASE:: [Database Name Here] TO [Login Name];     &lt;br /&gt;&lt;/font&gt;    &lt;br /&gt;Another option is to execute the following statement using the &lt;a href="http://msdn.microsoft.com/en-us/library/ms178630.aspx"&gt;sp_changedbowner&lt;/a&gt; system stored procedure; but please keep in mind that this stored procedure has been &lt;a href="http://dictionary.reference.com/browse/deprecate"&gt;deprecated&lt;/a&gt; and will likely disappear in future versions of SQL Server:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;EXEC dbo.sp_changedbowner @loginname = [Login Name];&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;.And They Lived Happily Ever After&lt;/strong&gt;    &lt;br /&gt;Upon changing the database owner to an existing login and simulating the inner and cross database messaging the errors have ceased. More importantly, all messages sent through this feature now successfully complete their journey. I have added the ownership change to my restoration script for the development environment.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=92917" width="1" height="1"&gt;</content><author><name>Johnm</name><uri>http://www.simple-talk.com/community/user/Profile.aspx?UserID=13712</uri></author></entry></feed>
