{"id":1837,"date":"2014-07-14T00:00:00","date_gmt":"2014-07-14T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/questions-about-sql-server-data-types-you-were-too-shy-to-ask\/"},"modified":"2021-09-29T16:21:35","modified_gmt":"2021-09-29T16:21:35","slug":"questions-about-sql-server-data-types-you-were-too-shy-to-ask","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/questions-about-sql-server-data-types-you-were-too-shy-to-ask\/","title":{"rendered":"Questions about SQL Server Data Types You were Too Shy to Ask"},"content":{"rendered":"<div id=\"pretty\">\n<h2>The Questions<\/h2>\n<ol>\n<li><a href=\"#first\">&#8220;Under what circumstances is character data truncated without triggering an error?&#8221;<\/a>.<\/li>\n<li><a href=\"#second\">&#8220;SQL Server&#8217;s implicit conversions sometimes lead to unexpected query results, such as a value being returned as a data type different from what I expect. How do implicit conversions work?&#8221;<\/a>.<\/li>\n<li><a href=\"#third\">&#8220;I&#8217;ve created a query that uses the ISNUMERIC function to verify whether a value is numeric and, if so, convert it to an integer. In some cases, however, the database engine generates an error because it&#8217;s trying to convert a value that&#8217;s not really a numeric. What&#8217;s going on?&#8221;<\/a><\/li>\n<li><a href=\"#fourth\">&#8220;I&#8217;m told I should use the BIT data type where possible to save space. Is it true that it saves space or is this just syntactic sugar?&#8221;<\/a><\/li>\n<li><a href=\"#fifth\">&#8220;When I use the DATALENGTH and LEN functions to calculate the size of a string, I often receive different results, even though I&#8217;d expect them to be the same. What&#8217;s the difference between the two functions?&#8221;<\/a>.<\/li>\n<li><a href=\"#sixth\">&#8220;I&#8217;m troubleshooting a stored procedure that uses a COALESCE expression to return the first non-NULL value from a set of columns. However the procedure often generates a conversion error, even if the expression returns is the first column listed. Any idea why this might be occurring?&#8221;<\/a>.<\/li>\n<li><a href=\"#seventh\">&#8220;I&#8217;m developing a query that contains a BETWEEN operator in the WHERE clause. The compared data includes a range of consecutive values that contain both letters and numbers, as in XYZ60 through XYZ700. Even when I specify the entire range, values are unexpectedly omitted from my query results. Any idea why this is occurring?&#8221;<\/a><\/li>\n<li><a href=\"#eighth\">&#8220;I&#8217;ve seen some T-SQL code that contains &#8216;national character varying(max)&#8217; listed as that data type, rather than one of the normal types, yet everything seems to work fine. Is this something new?&#8221;<\/a>.<\/li>\n<li><a href=\"#ninth\">&#8220;When is it best to use the CHAR date type rather than VARCHAR?&#8221;<\/a>.<\/li>\n<li><a href=\"#tenth\">&#8220;I&#8217;m building a query that joins a FLOAT column to a REAL column, but when I run the statement, it returns no results, even though I can see the matching values in the two columns. Why is this happening?&#8221;<\/a>.<\/li>\n<li><a href=\"#eleventh\">&#8220;I have a table that includes a VARCHAR column and a stored procedure that accesses data from the table, based on values in that column. The procedure includes an NVARCHAR parameter used to qualify the WHERE clause, which references the VARCHAR column. Does it matter that the data types are different between the parameter and the column?&#8221;<\/a>.<\/li>\n<li><a href=\"#twelveth\">&#8220;My query needs to calculate past and future dates based on an existing date as well as calculate the time difference between two dates. I&#8217;ve tried using arithmetic operators to perform the calculations, but the results are never right. How do I go about working with dates?&#8221;<\/a>.<\/li>\n<li><a href=\"#thirteenth\">&#8220;I&#8217;m told never to use SQL_VARIANT data type inappropriately. What is an appropriate use for this data type?&#8221;<\/a><\/li>\n<\/ol>\n<h3 id=\"first\">&#8220;Under  what circumstances is character data truncated without triggering an error?&#8221;<\/h3>\n<div class=\"indented\">\n<p>Never, one might hope. But SQL Server is a sneaky devil, preventing truncation some of the  time, but not all the time. Sure, if you try to insert too large a value into a column, the database engine baulks, just  like it would for the following table:  \t \t<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tIF OBJECT_ID('OurStuff', 'U') IS NOT NULL\n\tDROP TABLE OurStuff;\n\tGO\n\t\n\tCREATE TABLE OurStuff\n\t(\n\t&#160; StuffID INT NOT NULL IDENTITY PRIMARY KEY,\n\t&#160; StuffName VARCHAR(10) NOT NULL\n\t);\n\tGO\n\t\n<\/pre>\n<p>The <code>StuffID<\/code> column, the primary key, is  configured with the <code>INT<\/code> data type, and the  \t<code>StuffName<\/code>  column is configured as <code>VARCHAR(10)<\/code>. All very basic. And just as basic is the following  \t<code>INSERT<\/code> statement:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tINSERT INTO OurStuff(StuffName)\n\tVALUES('Really Big Thing');\n<\/pre>\n<p> \tWhat we&#8217;re trying to do is here is insert a value into the  \t<code>StuffName<\/code>  column that exceeds the data type&#8217;s specified length. Not surprisingly, SQL Server kicks out an error:<\/p>\n<pre>\tMsg 8152, Level 16, State 14, Line 1\n\tString or binary data would be truncated.\n\tThe statement has been terminated.\n<\/pre>\n<p>&#160;Everything just as we&#8217;d expect. The value being inserted is too big, so the database engine  jumps to the rescue, preventing any values from being truncating and, consequently, ensuring integrity of the data. \t \t<\/p>\n<p>Unfortunately, SQL Server is not quite so protective with its variables and parameters.  Consider the following T-SQL script, which declares the <code>@stuff<\/code> variable and sets its value to a  string that exceeds the data type&#8217;s specified length:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @stuff VARCHAR(10) = 'Really Big Thing';\n\tPRINT @stuff;\n<\/pre>\n<p> \tThe database engine doesn&#8217;t blink. It simply inserts the string&#8217;s first 10 characters (<code>Really<\/code> \t<code>Big<\/code>)  and goes about its business, pretending that all is well, when in fact our variable must limp along with a truncated  value. The <code>PRINT<\/code>  statement merely confirms our suspicions and returns the really wrong <code>Really<\/code>  \t<code>Big<\/code>.<\/p>\n<p>It gets worse. Imagine you&#8217;re using an <code>ISNULL<\/code> function to compare two variables,  as in the following example:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE\n\t&#160; @stuff1 VARCHAR(5) = NULL,\n\t&#160; @stuff2 VARCHAR(10) = 'Big Thing';\n\tPRINT ISNULL(@stuff1, @stuff2);\n\t<\/pre>\n<p> \tThe first variable is defined as <code>VARCHAR(5)<\/code> and assigned a value of  \t<code>NULL<\/code>.  The second is defined as <code>VARCHAR(10)<\/code> and assigned the string value  \t<code>Big<\/code> \t<code>Thing<\/code>.  So far so good. Now we get to <code>ISNULL<\/code>. The thing with this  function is that the first expression (in this case, <code>@stuff1<\/code>) determines the outputted data  type, even if that expression returns a <code>NULL<\/code>. That means the  \t<code>@stuff2<\/code>  value is confined by <code>@stuff1<\/code> data type constraints. As a result, our  \t<code>PRINT<\/code>  statement, rather than returning <code>Big<\/code>  \t<code>Thing<\/code>,  gives us <code>Big<\/code> \t<code>T<\/code>,  which sounds more like a mob boss than a credible data item.<\/p>\n<p>Parameters too can fall victim to truncation without warning. Suppose we create the following  stored procedure:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tIF OBJECT_ID('AddStuff', 'P') IS NOT NULL\n\tDROP PROCEDURE AddStuff;\n\tGO\n\t\n\tCREATE PROCEDURE AddStuff \n\t@stuff VARCHAR(10)\n\tAS\n\tINSERT INTO OurStuff(StuffName) VALUES(@stuff);\n\tGO\n\t<\/pre>\n<p>A simple example, of course, but it demonstrates an important concept. Notice that the  \t<code>@stuff<\/code>  parameter is defined as <code>VARCHAR(10)<\/code>. Now suppose we pass in a value longer than 10 characters:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tEXEC AddStuff 'Really Big Thing';\n<\/pre>\n<p> \tThe database engine runs the procedure without a hitch and returns a message saying that one  row is affected (the row inserted into the <code>OurStuff<\/code> table). We can verify this by  running a simple <code>SELECT<\/code>  statement:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff;<\/pre>\n<p> \tThe results, shown in the following table, indicate that the value has indeed been truncated,  although not once did SQL Server raise an exception.<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffName<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Really Big<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tSo be aware of what can happen when working with variables and parameters. You&#8217;ll likely want  to include in your T-SQL code the logic necessary to catch values that might be faulty. Obviously, you can&#8217;t rely on the  database engine to do it for you.<\/p>\n<\/p><\/div>\n<h3 id=\"second\">&#8220;SQL  Server&#8217;s implicit conversions sometimes lead to unexpected query results, such as a value being returned as a data type  different from what I expect. How do implicit conversions work?&#8221;<\/h3>\n<div class=\"indented\">\n<p>SQL Server is great at surreptitiously converting values from one type to another:  \t<code>CHAR<\/code>  to <code>VARCHAR<\/code>, \t<code>FLOAT<\/code>  to <code>NCHAR<\/code>, \t<code>BIGINT<\/code>  to <code>MONEY<\/code>.  You get the picture. As long as the values are compatible with the target type, the database engine does all the work,  and you get to kick back and reap the rewards.<\/p>\n<p>Sort of.<\/p>\n<p>Imagine the following scenario, in which we add a  \t<code>CHAR<\/code>  variable to an <code>INT<\/code>  variable:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE\n\t&#160; @stuff1 CHAR(2) = '22',\n\t&#160; @stuff2 INT = 33;\n\tSELECT @stuff1 + @stuff2 AS AllStuff,\n\t&#160; SQL_VARIANT_PROPERTY(@stuff1 + @stuff2, 'basetype') AS BaseType;\n\t<\/pre>\n<p> \tWe declare the variables, assign values, and add them together. We also pull the base type of  the returned value, just so we know what&#8217;s going on. The following table shows us the results of our  \t<code>SELECT<\/code>  statement:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>AllStuff<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>BaseType<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">55<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">int<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tAll looks fine on the surface. We add our <code>INT<\/code> value to our  \t<code>CHAR<\/code>  value and come up with the total (55), returned as an <code>INT<\/code> value. The database engine has  implicitly converted the <code>CHAR<\/code> value to an  \t<code>INT<\/code> value. The  \t<code>INT<\/code>  data type is used because <code>INT<\/code> takes precedence over  \t<code>CHAR<\/code>. SQL Server is quite explicit when it  comes to data type precedence. <code>INT<\/code> wins out over  \t<code>CHAR<\/code>  and <code>VARCHAR<\/code>  every time. If a <code>DATETIME<\/code>  value is tossed into the mix, it will beat out <code>INT<\/code> and just about all other types.  (You can find details about precedence rules in the MSDN topic &#8220;<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms190309.aspx\">Data  Type Precedence<\/a>.&#8221;)<\/p>\n<p>Returning to our example, SQL Server converts the  \t<code>CHAR<\/code>  value to <code>INT<\/code>  and then proceeds to add the two integers together, giving us a result of <code>55<\/code>. But what if we didn&#8217;t want to add the  values together but concatenate them instead? In that case, we&#8217;d have to explicitly convert the  \t<code>INT<\/code>  value:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE\n\t&#160; @stuff1 CHAR(2) = '22',\n\t&#160; @stuff2 INT = 33;\n\tSELECT @stuff1 + CAST(@stuff2 AS CHAR(2)) AS AllStuff,\n\t&#160; SQL_VARIANT_PROPERTY(@stuff1 + CAST(@stuff2 AS CHAR(2)), \n\t&#160;&#160;&#160; 'basetype') AS BaseType;\n\t\n<\/pre>\n<p>Now our results look quite different. Not only are the two values concatenated, but the value  is also returned as a <code>CHAR<\/code>  type:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>AllStuff<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>BaseType<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2233<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">char<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tYou should also be aware of how SQL Server handles implicit conversions for numerical data.  For example, suppose this time around, we create a <code>DECIMAL<\/code> variable and an  \t<code>INT<\/code>  variable, assign a value to the <code>DECIMAL<\/code> variable, and then set the  \t<code>INT<\/code>  variable to equal the <code>DECIMAL<\/code> variable:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE\n\t&#160; @stuff1 DECIMAL(8,4) = 1234.9999,\n\t&#160; @stuff2 INT;\n\tSET @stuff2 = @stuff1;\n\tSELECT @stuff1 AS Stuff1, @stuff2 AS Stuff2;\n\t<\/pre>\n<p>The <code>SELECT<\/code> statement now returns these results:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Stuff1<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Stuff2<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1234.9999<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1234<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tNotice what the database engine has done. Rather than rounding the value up, as might be  expected, it simply truncates the value, giving us our integer, without too great a concern for the original value. And  the problem isn&#8217;t limited to <code>DECIMAL<\/code>&#8211;<code>INT<\/code>  conversions. Check out what happens when we go from <code>INT<\/code> to  \t<code>REAL<\/code>  and back again:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE \n\t&#160; @stuff1 INT = 1080000000,\n\t&#160; @stuff2 INT = 1080000016,\n\t&#160; @stuff3 REAL;\n\tSET @stuff3 = @stuff2;\n\tSELECT \n\t&#160; @stuff3 AS Stuff3,\n\t&#160; CAST(@stuff3 AS INT) AS Stuff3int,\n\t&#160; CASE\n\t&#160;&#160;&#160; WHEN @stuff3 = @stuff1\n\t&#160;&#160;&#160; THEN 'yes'\n\t&#160;&#160;&#160; ELSE 'no'\n\t&#160; END AS IsEqual;\n\t<\/pre>\n<p> \tWe declare the <code>INT<\/code> variables and set their values,  and then declare a <code>REAL<\/code>  variable and set its value to equal the second <code>INT<\/code> variable. In our  \t<code>SELECT<\/code>  statement, we then retrieve the <code>REAL<\/code> variable as it is stored, convert it  to an <code>INT<\/code>, and then check whether the  first and third variables are equal. The following table shows our results:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Stuff3<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Stuff3in<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>IsEqual<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1.08E+09<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1080000000<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">yes<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tNotice that the <code>Stuff3<\/code> value appears as scientific  notation because the <code>@stuff3<\/code> variable had insufficient precision to hold the original integer. In addition,  when the variable is converted to an integer, it returns a value different from what it was assigned. Instead, it now  equals the value stored in <code>@stuff1<\/code>.  \t \t<\/p>\n<p>In many cases, you shouldn&#8217;t leave it up to the database engine to do your conversions, no  matter how tempting that might be. In fact, some developers insist that all conversions should be explicit. At the very  least, be sure that whenever the integrity of the data could be brought into question, error on the side of converting  the data explicitly.<\/p>\n<\/p><\/div>\n<h3 id=\"third\">&#8220;I&#8217;ve  created a query that uses the <code>ISNUMERIC<\/code> function to verify whether a value is numeric and, if so, convert it to an integer. In some cases, however, the database  engine generates an error because it&#8217;s trying to convert a value that&#8217;s not really a numeric. What&#8217;s going on?&#8221;<\/h3>\n<div class=\"indented\">\n<p>The <code>ISNUMERIC<\/code> function can be a slippery one.  On the surface, its purpose appears only to determine whether the submitted value is indeed a valid numeric type. But  looks can be deceiving. Take the following T-SQL script. It creates a table with a  \t<code>VARCHAR<\/code>  column and then adds a mix of values to that column:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tIF OBJECT_ID('OurStuff', 'U') IS NOT NULL\n\tDROP TABLE OurStuff;\n\tGO\n\t\n\tCREATE TABLE OurStuff\n\t(\n\t&#160; StuffID INT NOT NULL IDENTITY PRIMARY KEY,\n\t&#160; StuffName VARCHAR(10) NOT NULL\n\t);\n\tGO\n\t\n\tINSERT INTO OurStuff(StuffName)\n\tVALUES('abc'), ('def123'), ('456'), ('$789'), ('1d1'), (','), ('.'), ('$.,');\n\t\n\t<\/pre>\n<p>Nothing extraordinary, just your run-of-the-mill alphanumeric hodgepodge. But now let&#8217;s look  at what happens when we apply the <code>ISNUMERIC<\/code> function to the  \t<code>StuffName<\/code>  column:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT StuffID, StuffName, ISNUMERIC(StuffName) AS IsNumber\n\tFROM OurStuff;\n<\/pre>\n<p>All we&#8217;re doing is pulling the table&#8217;s two columns, as well as returning a third column to  test each value&#8217;s numeric status. The <code>ISNUMERIC<\/code> function returns a  \t<code>1<\/code> if  the tested value appears to be a numeric data type, otherwise returns a <code>0<\/code>. Here&#8217;s what we get:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>IsNumber<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">abc<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">def123<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">456<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">$789<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1d1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">6<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">,<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">7<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">.<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">$.,<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tIt should come as no surprise that the first two values are considered non-numeric and the  third value is. However, the function also considers <code>$789<\/code> to be numeric, despite the dollar sign  (or more precisely, because of the dollar sign), and <code>1d1<\/code> to be numeric because of its  resemblance to scientific notation, whether or not that is the intent.<\/p>\n<p>The sky might not fall because of these interpretations, but they could cause problems if you  want to perform other operations based on the output of the <code>ISNUMERIC<\/code> function. For example,  suppose we want to explicitly convert each value to an <code>INT<\/code> based on whether we think that value is  numeric:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT StuffID, StuffName,\n\t&#160; CASE \n\t&#160;&#160;&#160; WHEN ISNUMERIC(StuffName) = 1  \n\t&#160;&#160;&#160; THEN CAST(StuffName AS INT)\n\t&#160;&#160;&#160; ELSE NULL \n\t&#160; END AS CaseResult\n\tFROM OurStuff\n\tWHERE StuffID BETWEEN 1 AND 3;\n<\/pre>\n<p>In this case, we&#8217;re retrieving only the first three rows from our table. If the  \t<code>ISNUMERIC<\/code>  function returns a <code>1<\/code>,  we convert the value to the <code>INT<\/code> type; otherwise, we return a  \t<code>NULL<\/code>  value. As to be expected, the first two rows each return a <code>NULL<\/code> and the third row returns the  value <code>456<\/code> as an  \t<code>INT<\/code>,  as shown in the following results:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>CaseResult<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">abc<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">NULL<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">def123<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">NULL<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">456<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">456<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tNow let&#8217;s retrieve the fourth row from the table:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT StuffID, StuffName,\n\t&#160; CASE \n\t&#160;&#160;&#160; WHEN ISNUMERIC(StuffName) = 1  \n\t&#160;&#160;&#160; THEN CAST(StuffName AS INT)\n\t&#160;&#160;&#160; ELSE NULL \n\t&#160; END AS CaseResult\n\tFROM OurStuff\n\tWHERE StuffID = 4;\n\t<\/pre>\n<p>This time around, we receive the following error message, indicating that we cannot convert  that value to an <code>INT<\/code>:<\/p>\n<pre>\tMsg 245, Level 16, State 1, Line 1\n\tConversion failed when converting the varchar value '$789' to data type int.\n<\/pre>\n<p>This shouldn&#8217;t come as too big of a surprise. The  \t<code>INT<\/code>  data type has never been fond of dollar signs. &#160;The same goes for scientific  notation. If we were to try to run the query against the last row in our table, we would receive a similar error.<\/p>\n<p>And it&#8217;s not just dollar signs and possible scientific notation that can elicit problems. The \t<code>ISNUMERIC<\/code> function recognizes an  assortment of characters as being numeric (in addition to actual numbers), such as plus signs and minus signs and  periods and tabs and commas. Take a look at the following example, in which we assign a tab to the  \t<code>@tab<\/code>  variable:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @tab VARCHAR(10) = '&#160;&#160;&#160;&#160;&#160; ';\n\tPRINT ISNUMERIC(@tab);\n<\/pre>\n<p>As odd as this might seem, the <code>ISNUMERIC<\/code> function returns a  \t<code>1<\/code>,  as it will in the next example, in which we pass in a plus sign:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @plus NVARCHAR(10) = '+';\n\tPRINT ISNUMERIC(@plus);\n\t<\/pre>\n<p>If you&#8217;re working with a version of SQL Server prior to 2012, you&#8217;ll have to come up with  some sort of workaround to check for those circumstances in which the apparent numeric value would generate an error.  You might, for example, create a function or add a <code>CASE<\/code> statement to setup complex  test conditions.  \t \t<\/p>\n<p>For those of you working with SQL Server 2012 or later, you have a better alternative-the \t<code>TRY_CONVERT<\/code>  \t function:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT StuffID, StuffName,\n\t&#160; CASE \n\t&#160;&#160;&#160; WHEN ISNUMERIC(StuffName) = 1  \n\t&#160;&#160;&#160; THEN TRY_CONVERT(INT, StuffName)\n\t&#160;&#160; ELSE NULL \n\t&#160; END AS CaseResult\n\tFROM OurStuff;\n\t\n<\/pre>\n<p>The function first tests whether the requested conversion will work. If so, it converts the  data to the target data type. If not, it returns a <code>NULL<\/code>:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>CaseResult<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">abc<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">NULL<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">def123<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">NULL<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">456<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">456<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">$789<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">NULL<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1d1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">NULL<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">,<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">NULL<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">.<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">NULL<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">$.,<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">NULL<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>As you can see, the only number that can be converted is  \t<code>456<\/code>.  The rest are there only to complicate the lives of overworked DBAs with nothing better to do than to search for wayward  numbers.<\/p>\n<\/p><\/div>\n<h3 id=\"fourth\">&#8220;I&#8217;m told I should use the \t \t<code>BIT<\/code> data type where possible to save  space. Is it true that it saves space or is this just syntactic sugar?&#8221;<\/h3>\n<div class=\"indent\">\n<p>Yes, the <code>BIT<\/code> data type can save space under certain  circumstances, and it undoubtedly has some advantages over an approach such as using  \t<code>CHAR(1)<\/code>, which requires a  \t<code>CHECK<\/code>  constraint to limit the values in the same way <code>BIT<\/code> already does. With the  \t<code>BIT<\/code>  data type, you can insert only the values <code>1<\/code> and  \t<code>0<\/code>,  as well as <code>NULL<\/code>  values, assuming the object is nullable.  \t \t<\/p>\n<p>That said, a <code>BIT<\/code> data type still uses a byte of  data, just like <code>CHAR(1)<\/code>  or <code>TINYINT<\/code>.  Some might have assumed that the <code>BIT<\/code> type translates into only one bit of  data, given the type&#8217;s tie-in to the <code>1<\/code> and  \t<code>0<\/code>  value limits. But that&#8217;s hardly the case. <code>BIT<\/code> is actually in integer data type and  consequently requires more legroom. Case in point:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @stuffed BIT = 0;\n\tSELECT\n\t&#160; @stuffed AS Stuffed,\n\t&#160; DATALENGTH(@stuffed) AS BitLength;\n\t<\/pre>\n<p>As you can see in the following results, the value does indeed use one byte:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Stuffed<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>BitLength<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">0<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tHowever, if you create a table with multiple <code>BIT<\/code> columns, the database engine is clever  enough to store the column data in a single byte, up to eight columns. If your table contains between 9 and 16  \t<code>BIT<\/code>  columns, SQL Server stores the data as two bytes. Between 17 and 24 <code>BIT<\/code> columns? Three bytes, and so  on. You get the picture.<\/p>\n<p>That said, you should still be wary about implementing  \t<code>BIT<\/code>.  It can have unexpected results when used in an expression, and it&#8217;s not necessarily well suited to masquerading as a bit  flag or bit mask. For an interesting take on the whole issue, check out Joe Celko&#8217;s excellent article &#8220;<a href=\"https:\/\/www.simple-talk.com\/sql\/t-sql-programming\/bit-of-a-problem\/\">BIT  of a Problem<\/a>.&#8221;<\/p>\n<\/p><\/div>\n<h3 id=\"fifth\">&#8220;When  I use the  \t<code>DATALENGTH<\/code> and  \t<code>LEN<\/code> functions to calculate the size of a  string, I often receive different results, even though I&#8217;d expect them to be the same. What&#8217;s the difference between the  two functions?&#8221;<\/h3>\n<div class=\"indent\">\n<p>The <code>DATALENGTH<\/code> function returns the number of  bytes used by an expression, and the <code>LEN<\/code> function returns the number of  characters contained in an expression. The <code>LEN<\/code> function is also limited to string  expressions; whereas, the <code>DATALENGTH<\/code> function supports  expressions of any type.  \t \t<\/p>\n<p>To better understand how they both work, let&#8217;s take a look at them in action. The following  T-SQL script creates a table with four columns, each configured with a character data type, and then inserts data into  those columns:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tIF OBJECT_ID('TestLength', 'U') IS NOT NULL\n\tDROP TABLE TestLength;\n\tGO\n\t\n\tCREATE TABLE TestLength\n\t(\n\t&#160; char1 CHAR(10),\n\t&#160; nchar2 NCHAR(10),\n\t&#160; varchar3 VARCHAR(10),\n\t&#160; nvarchar4 NVARCHAR(10)\n\t);\n\tGO\n\t\n\tINSERT INTO TestLength\n\tVALUES('stuff', 'stuff', 'stuff', 'stuff');\n\tINSERT INTO TestLength\n\tVALUES('stuff&#160;&#160; ', 'stuff&#160;&#160; ', 'stuff&#160;&#160; ', 'stuff&#160;&#160; ');\n\t<\/pre>\n<p>Notice that, in the final <code>INSERT<\/code> statement, I&#8217;ve added  several spaces after each value. You&#8217;ll see why in a moment. But first, let&#8217;s retrieve data from each of the columns,  applying both the <code>LEN<\/code>  and <code>DATALENGTH<\/code>  functions:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT \n\t&#160; LEN(char1) AS len1,\n\t&#160; DATALENGTH(char1) AS datalength1,\n\t&#160; LEN(nchar2) AS len2,\n\t&#160; DATALENGTH(nchar2) AS datalength2,\n\t&#160; LEN(varchar3) AS len3,\n\t&#160; DATALENGTH(varchar3) AS datalength3,\n\t&#160; LEN(nvarchar4) AS len4,\n\t&#160; DATALENGTH(nvarchar4) AS datalength4\n\tFROM TestLength;\n\t\n<\/pre>\n<p>The following table shows the statement&#8217;s output:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>len1<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>datalength1<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>len2<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>datalength2<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>len3<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>datalength3<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>len4<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>datalength4<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">10<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">20<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">10<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">10<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">20<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">16<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tThe <code>len1<\/code> and  \t<code>datalength1<\/code>  columns in the resultset refer to the <code>char1<\/code> column in the  \t<code>TestLength<\/code>  table. The column is configured as <code>CHAR(10)<\/code>. The  \t<code>LEN<\/code>  function provides of the actual number of characters being used (<code>5<\/code>), not including the trailing  spaces. The <code>DATALENGTH<\/code>  function indicates that 10 bytes are being used, despite the actual number of characters. This is because the column is  configured at a fixed width of <code>10<\/code>. As a result, the  \t<code>DATALENGTH<\/code>  function can provide us with a more accurate view of our storage requirements.<\/p>\n<p>The <code>len2<\/code> and  \t<code>datalength2<\/code>  columns in the resultset refer to the <code>nchar2<\/code> column and work much the  same way, except that it is a Unicode column configured as <code>NCHAR(10)<\/code>. The  \t<code>LEN<\/code>  function still shows that five characters are being used (not including spaces), but the  \t<code>DATALENGTH<\/code>  function indicates that the value actually requires 20 bytes, just like we&#8217;d expect.<\/p>\n<p>When we get to the <code>len3<\/code> and  \t<code>datalength3<\/code>  columns, the results get even more interesting. This data is based on the <code>varchar3<\/code> column, which is configured as \t<code>VARCHAR(10)<\/code>. Even so, the  \t<code>LEN<\/code>  function still indicates that only five characters are being used. However, because we&#8217;re working with a  \t<code>VARCHAR<\/code>  column, the <code>DATALENGTH<\/code>  function indicates that five bytes are being used by the value in the first row and eight bytes by the value in the  second row (to accommodate the trailing spaces). The <code>len4<\/code> and  \t<code>datalength4<\/code>  columns work in the same way, only the number of bytes is doubled in each case to account for the Unicode type.<\/p>\n<p>As mentioned earlier, although the <code>LEN<\/code> function is limited to string data, you  can use the <code>DATALENGTH<\/code>  function on an expression of any data type. For example, the following T-SQL declares an  \t<code>INT<\/code>  variable, assigns a value, and then checks the number of bytes the variable uses:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @int INT = 1234567;\n\tSELECT @int AS IntNew, DATALENGTH(@int) AS IntLength;\n\t<\/pre>\n<p> \tThe <code>SELECT<\/code> statement returns the results shown  in the following table, which indicate that the value uses four bytes, the expected length for the  \t<code>INT<\/code>  data type:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">IntNew<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">IntLength<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1234567<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tEven if our integer were made up of only two digits, the results would be the same. Same goes  for a <code>DATETIME<\/code> value, in terms of  consistency:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @now DATETIME = GETDATE();\n\tSELECT @now AS DateNow, DATALENGTH(@now) AS DateLength;\n<\/pre>\n<p> \tIn this case, the <code>DATALENGTH<\/code> function returns eight  bytes:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>DateNow<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>DateLength<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-05 21:32:23.507<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We would expect eight bytes because <code>DATETIME<\/code> values are stored as two integers,  one for the date and one for the time.<\/p>\n<\/p><\/div>\n<h3 id=\"sixth\">&#8220;I&#8217;m  troubleshooting a stored procedure that uses a  \t<code>COALESCE<\/code>  expression to return the first non-NULL  value from a set of columns. However the procedure often generates a conversion error, even if the expression returns is  the first column listed. Any idea why this might be occurring?&#8221;<\/h3>\n<div class=\"indent\">\n<p>A <code>COALESCE<\/code> expression can be a bit tricky to  get right at first. It is essentially shorthand for a type of <code>CASE<\/code> expression that evaluates a series of  expressions, often columns or variables, and returns the first one that does not evaluate to  \t<code>NULL<\/code>. Let&#8217;s look how it works. The  following T-SQL declares several variables and assigns values to them, based on their respective types:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE\n\t&#160; @stuffNull VARCHAR(5) = NULL,\n\t&#160; @stuffID INT = 1001,\n\t&#160; @stuffName VARCHAR(10) = 'Big Thing';\n\tSELECT \n\t&#160; COALESCE(@StuffNull, @StuffID, @StuffName) AS NotNullStuff,\n\t&#160; SQL_VARIANT_PROPERTY(COALESCE(@StuffNull, @StuffID, @StuffName), 'basetype') AS BaseType;\n\t<\/pre>\n<p>The <code>COALESCE<\/code> expression takes the three  variables as an argument. Because the <code>@StuffNull<\/code> variable contains a  \t<code>NULL<\/code>  value, it will be skipped and we&#8217;ll move to the next variable, <code>@StuffID<\/code>. This one contains a value, so the \t<code>SELECT<\/code> statement returns that value  in its results:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>NotNullStuff<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>BaseType<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1001<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">int<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tEverything seems in order here. The <code>@StuffID<\/code> variable does not contain a  \t<code>NULL<\/code>, so that value is returned,  and it is indeed an integer, just as we would expect. But what if we change the order of our variables:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE\n\t&#160; @stuffNull VARCHAR(5) = NULL,\n\t&#160; @stuffID INT = 1001,\n\t&#160; @stuffName VARCHAR(10) = 'Big Thing';\n\tSELECT \n\t&#160; COALESCE(@StuffNull, @StuffName, @StuffID) AS NotNullStuff,\n\t&#160; SQL_VARIANT_PROPERTY(COALESCE(@StuffNull, @StuffID, @StuffName), 'basetype') AS BaseType;\n\t<\/pre>\n<p> \tThe <code>@StuffName<\/code> variable does not contain a \t<code>NULL<\/code>  value, so that variable&#8217;s value should be returned. However, the statement instead generates the following error:<\/p>\n<pre>\tMsg 245, Level 16, State 1, Line 5\n\tConversion failed when converting the varchar value 'Big Thing' to data type int.\n<\/pre>\n<p> \tThe problem is that a <code>COALESCE<\/code> expression uses the data  type with the highest precedence. It does not matter what order the arguments are presented. Because  \t<code>INT<\/code>  has a higher precedence than <code>VARCHAR<\/code>, the returned type is an \t<code>INT<\/code>, which means the database  engine is trying to convert the <code>Big<\/code>  \t<code>Thing<\/code>  string to an integer. It just doesn&#8217;t work.<\/p>\n<p>Data type precedence also applies to a type&#8217;s length:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE\n\t&#160; @stuffNull VARCHAR(5) = NULL,\n\t&#160; @stuffName1 VARCHAR(10) = 'Big Thing',\n\t&#160; @stuffName2 VARCHAR(15) = 'Next Big Thing';\n\tSELECT \n\t&#160; COALESCE(@StuffNull, @StuffName1, @StuffName2) AS NotNullStuff,\n\t&#160; SQL_VARIANT_PROPERTY(COALESCE(@StuffNull, @StuffName1, @StuffName2), 'basetype') AS BaseType,\n\t&#160; SQL_VARIANT_PROPERTY(COALESCE(@StuffNull, @StuffName1, @StuffName2), 'maxlength') AS BaseLength;\n<\/pre>\n<p> \tBecause <code>@StuffName1<\/code> is the first variable to  contain a non-null value, that value is returned. However, because <code>@StuffName2<\/code> has a greater length (<code>15<\/code>  as opposed to <code>10<\/code>),  that is the data type of the returned value, as the following table shows:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>NotNullStuff<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>BaseType<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>BaseLength<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Big Thing<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">varchar<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">15<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tAlthough both variables are <code>VARCHAR<\/code>, the  \t<code>15<\/code>  length has precedence over the <code>10<\/code> length, just like  \t<code>INT<\/code>  has precedence over a <code>VARCHAR<\/code>.<\/p>\n<\/p><\/div>\n<h3 id=\"seventh\">&#8220;I&#8217;m developing a query that  contains a  \t<code>BETWEEN<\/code> operator in the  \t \t<code>WHERE<\/code> clause. The compared data includes  a range of consecutive values that contain both letters and numbers, as in  \t<code>XYZ60<\/code> through  \t<code>XYZ700<\/code>. Even when I specify the entire range, values are  unexpectedly omitted from my query results. Any idea why this is occurring?&#8221;<\/h3>\n<div class=\"indent\">\n<p>When you use the <code>BETWEEN<\/code> operator for non-numerical  data, you have to keep in mind how SQL Server sorts and searches for data. The example data you provide is considered  character data (non-numerical), so the returned range of values follow the rules of the database&#8217;s configured collation,  which specifies how character data is sorted and compared, based on language and usage norms.  \t \t<\/p>\n<p>The best way to understand this is to see it in action. The following T-SQL creates the \t<code>OurStuff<\/code> table, which includes a \t<code>VARCHAR<\/code>  column and <code>DATEIME<\/code>  column, and inserts a number of rows into those columns:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tIF OBJECT_ID('OurStuff', 'U') IS NOT NULL\n\tDROP TABLE OurStuff;\n\tGO\n\t\n\tCREATE TABLE OurStuff\n\t(\n\t&#160; StuffID INT NOT NULL IDENTITY PRIMARY KEY,\n\t&#160; StuffProdID VARCHAR(10) NOT NULL,\n\t&#160; StuffDate DATETIME NOT NULL\n\t);\n\tGO\n\t\n\tINSERT INTO OurStuff(StuffProdID, StuffDate) VALUES\n\t&#160; ('ab38', '2014-07-06 12:46:48.240'),\n\t&#160; ('ab39', '2014-07-08 10:46:48.240'),\n\t&#160; ('ab48', '2014-07-09 08:46:48.240'),\n\t&#160; ('ab49', '2014-07-10 06:46:48.240'),\n\t&#160; ('ab58', '2014-07-11 04:46:48.240'),\n\t&#160; ('ab59', '2014-07-12 02:46:48.240'),\n\t&#160; ('ab398', '2014-07-13 22:46:48.240'),\n\t&#160; ('ab399', '2014-07-14 20:46:48.240'),\n\t&#160; ('ab400', '2014-07-15 18:46:48.240'),\n\t&#160; ('cd38', '2014-07-16 16:46:48.240'),\n\t&#160; ('cd39', '2014-07-17 14:46:48.240'),\n\t&#160; ('cd48', '2014-07-18 12:46:48.240'),\n\t&#160; ('cd49', '2014-07-19 10:46:48.240'),\n\t&#160; ('cd58', '2014-07-20 11:46:48.240'),\n\t&#160; ('cd59', '2014-07-21 12:46:48.240'),\n\t&#160; ('cd398', '2014-07-22 13:46:48.240'),\n\t&#160; ('cd399', '2014-07-23 14:46:48.240'),\n\t&#160; ('cd400', '2014-07-24 15:46:48.240');\n<\/pre>\n<p> \tNow suppose we issue a simple query that retrieves the rows of data based on  \t<code>StuffID<\/code>  values <code>6<\/code>  through <code>16<\/code>:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff\n\tWHERE StuffID BETWEEN 6 AND 16;\n\t<\/pre>\n<p>Not surprisingly, the statement returns the results shown in the following table:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffProdID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">6<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab59<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-12 02:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">7<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab398<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-13 22:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab399<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-14 20:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">9<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab400<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-15 18:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">10<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-16 16:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">11<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd39<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-17 14:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">12<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-18 12:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">13<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd49<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-19 10:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">14<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd58<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-20 11:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">15<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd59<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-21 12:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">16<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd398<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-22 13:46:48.240<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \the <code>BETWEEN<\/code> operator does exactly what we  expect. It includes rows <code>6<\/code>  through <code>16<\/code>  and omits the rest. However, now suppose we modify the <code>BETWEEN<\/code> clause to retrieve data  based on the <code>StuffProdID<\/code> column:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff\n\tWHERE StuffProdID BETWEEN 'a' AND 'c';\n\t<\/pre>\n<p>Now our results include only the first nine rows:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffProdID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-06 12:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab39<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-08 10:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-09 08:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab49<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-10 06:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab58<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-11 04:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">6<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab59<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-12 02:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">7<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab398<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-13 22:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab399<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-14 20:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">9<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab400<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-15 18:46:48.240<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tAlthough we&#8217;ve specified that the letter <code>c<\/code> as the end of the range, no rows whose \t<code>StuffProdID<\/code> value starts with that  letter are included. They are not part of the acceptable range of values, based on the sort order defined by the  collation. In other words, all values that start with <code>c<\/code> include other characters, so they&#8217;re  considered out of range.  \t \t<\/p>\n<p>To help clarify this, let&#8217;s sort our table based on the  \t<code>StuffProdID<\/code>  column:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff\n\tORDER BY StuffProdID;\n\t<\/pre>\n<p>The data in the <code>StuffProdID<\/code> column is sorted based  on the rules of the database collation:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffProdID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-06 12:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab39<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-08 10:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">7<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab398<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-13 22:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab399<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-14 20:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">9<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab400<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-15 18:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-09 08:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab49<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-10 06:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab58<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-11 04:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">6<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab59<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-12 02:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">10<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-16 16:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">11<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd39<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-17 14:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">16<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd398<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-22 13:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">17<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd399<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-23 14:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">18<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd400<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-24 15:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">12<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-18 12:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">13<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd49<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-19 10:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">14<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd58<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-20 11:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">15<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd59<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-21 12:46:48.240<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tThe data is sorted first by the first character, then by the second character, within the  first-character grouping, next by the third character, within the second-character grouping, and so on. If we reconsider  our <code>BETWEEN<\/code>  clause (<code>BETWEEN<\/code> \t<code>'a'<\/code> \t<code>AND<\/code> \t<code>'c'<\/code>),  we&#8217;ll see that the range includes all the values that start with a, but none that start with  \t<code>c<\/code>.  If we had a <code>c<\/code>-only  value, that would be included, but in this case, all of our values that start with  \t<code>c<\/code>  include other characters as well and consequently are outside the range specified in the  \t<code>BETWEEN<\/code>  clause. Now let&#8217;s specify a more inclusive range:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff\n\tWHERE StuffProdID BETWEEN 'ab3' AND 'cd4';\n\t<\/pre>\n<p>Because our range includes all rows up to <code>cd4<\/code>, our resultset includes several more  rows then it did when we specified only <code>c<\/code> as the upper end of the range:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffProdID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-06 12:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab39<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-08 10:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-09 08:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab49<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-10 06:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab58<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-11 04:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">6<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab59<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-12 02:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">7<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab398<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-13 22:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab399<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-14 20:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">9<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab400<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-15 18:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">10<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-16 16:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">11<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd39<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-17 14:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">16<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd398<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-22 13:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">17<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">cd399<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-23 14:46:48.240<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tNote, however, we&#8217;re still missing any rows that start with  \t<code>cd4<\/code>  or <code>cd5<\/code>  because they fall outside the specified range. If you refer back to the fully sorted resultset, you&#8217;ll see that the  values <code>cd400<\/code>  through <code>cd59<\/code>  are at the end of the result set, after <code>cd4<\/code>.<\/p>\n<p>The following example demonstrates this concept further:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff\n\tWHERE StuffProdID BETWEEN 'ab38' AND 'ab400';\n\t<\/pre>\n<p>Now our results include only five rows, those that fall within the specified range. As you  can see in the following results, <code>ab400<\/code> is now included because we specified  the entire value, not just the first part of it:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffProdID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-06 12:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab39<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-08 10:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">7<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab398<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-13 22:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab399<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-14 20:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">9<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab400<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-15 18:46:48.240<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tIf you&#8217;re working with <code>DATETIME<\/code> values, you also need to  be aware of how the data is sorted and compared. The following example specifies a date range three days apart:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff\n\tWHERE StuffDate BETWEEN '20140710' AND '20140713';\n\t<\/pre>\n<p>Because the range specified in a <code>BETWEEN<\/code> clause is inclusive, we might  expect four rows to be returned, but instead we get only three:  \t \t<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffProdID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab49<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-10 06:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab58<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-11 04:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">6<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab59<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-12 02:46:48.240<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tWhen working with <code>DATETIME<\/code> values, keep in mind that  the value is always made up of the date <i>and<\/i> time, down to a thousandth of a  second. The time part is factored into the range calculations, so you must take that part into account when you&#8217;re  specifying your range. If you don&#8217;t specify a specific time, as is the case in our  \t<code>SELECT<\/code> statement, SQL Server  assumes the time is midnight-all zeroes.  \t \t<\/p>\n<p>One approach to dealing with this issue is to specify the entire  \t<code>DATETIME<\/code>  values:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff\n\tWHERE StuffDate BETWEEN '2014-07-10 06:46:48.240' \n\t&#160; AND '2014-07-13 22:46:48.240';\n<\/pre>\n<p> \tThis way, our results will include all rows whose  \t<code>DATETIME<\/code>  values fall within this very specific range:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffProdID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab49<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-10 06:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab58<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-11 04:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">6<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab59<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-12 02:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">7<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab398<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-13 22:46:48.240<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tThe trouble with this approach, however, is that it can get fairly cumbersome. Instead of  using the <code>BETWEEN<\/code> operator, you might  consider the greater than or equal to operator (<code>&gt;=<\/code>)  along with the lesser than operator (<code>&lt;<\/code>):<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff\n\tWHERE StuffDate &gt;= '20140710' \n\t&#160; AND StuffDate &lt; '20140714';\n\t<\/pre>\n<p>For the beginning of the range, we specify that the date be greater than or equal to the  specified date, which puts us right at midnight. We then use the lesser than operator to specify one day past our  intended date. Because it will also be set to midnight, it will pick up anything before midnight on the previous day.  The following table shows the results now returned by the <code>SELECT<\/code> statement:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffProdID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab49<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-10 06:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab58<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-11 04:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">6<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab59<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-12 02:46:48.240<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">7<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ab398<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-13 22:46:48.240<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<h3 id=\"eighth\">&#8220;I&#8217;ve seen some T-SQL code  that contains &#8216;<code>national<\/code>  \t<code>character<\/code>  \t<code>varying(max)<\/code>&#8216; listed as that data type, rather than one of the \t<i>normal<\/i> types, yet everything seems to work fine. Is this something new?&#8221;<\/h3>\n<div class=\"indent\">\n<p>There&#8217;s nothing new about national character data types such as  \t<code>NATIONAL<\/code> \t<code>CHARACTER<\/code> \t<code>VARYING<\/code>.  SQL Server includes them as synonyms to appease the ISO gods in order to conform to the international standards set by  that organization. In fact, many of the SQL Server data types include ISO synonyms. (The TechNet topic &#8220;<a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/ms177566.aspx\">Data  Type Synonyms<\/a>&#8221; lists all the ISO synonyms.)<\/p>\n<p>You can use the synonyms in place of the names of the base data types in your data definition  language (DDL) statements. However, once you create the object, the synonyms are no longer used. For example, the  following T-SQL script creates a table that includes columns configured with the  \t<code>NVARCHAR<\/code>  and <code>NATIONAL<\/code> \t<code>CHARACTER<\/code> \t<code>VARYING<\/code>  data types:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tIF OBJECT_ID('OurStuff', 'U') IS NOT NULL\n\tDROP TABLE OurStuff;\n\tGO\n\t\n\tCREATE TABLE OurStuff\n\t(\n\t&#160; StuffID INT NOT NULL IDENTITY PRIMARY KEY,\n\t&#160; StuffName1 NVARCHAR(MAX) NOT NULL,\n\t&#160; Stuffname2 NATIONAL CHARACTER VARYING(MAX) NOT NULL\n\t);\n\tGO\n\t\n\tINSERT INTO OurStuff(StuffName1, Stuffname2)\n\tVALUES('Really Big Thing', 'Amazingly Big Thing');\n<\/pre>\n<p>&#160;We can specify the national character type just like we do any other type. Plus, we can  insert and manipulate data just like any other type. But now let&#8217;s look at the column metadata:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT\n\t&#160; c.name AS ColumnName,\n\t&#160; t.name AS TypeName\n\tFROM sys.columns c INNER JOIN sys.types t \n\t&#160; ON c.user_type_id = t.user_type_id\n\tWHERE object_id = OBJECT_ID('OurStuff')\n\tORDER BY c.column_id;\n\t<\/pre>\n<p> \tAll we&#8217;re doing is pulling the column names and their data types, after we created our table.  The following results tell all:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>ColumnName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>TypeName<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">StuffID<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">int<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">StuffName1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">nvarchar<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Stuffname2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">nvarchar<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tAs you can see, both character columns have been created with the  \t<code>NVARCHAR<\/code>  data type. The <code>NATIONAL<\/code> \t<code>CHARACTER<\/code> \t<code>VARYING<\/code>  alias has disappeared altogether.<\/p>\n<\/p><\/div>\n<h3 id=\"ninth\">&#8220;When is it best to use the \t \t<code>CHAR<\/code> date type rather than  \t<code>VARCHAR<\/code>?&#8221;<\/h3>\n<div class=\"indent\">\n<p>The key to knowing when to use one over the other is to first understand the differences  between them. The <code>CHAR<\/code>  and <code>NCHAR<\/code>  data types store data at a fixed length. If an inserted value is less then that length, it is padded with trailing  spaces to ensure that every value is of equal length. The <code>VARCHAR<\/code> and  \t<code>NVARCHAR<\/code>  data types are variable length, which means the size depends on the inserted value, plus an additional couple of bytes  for overhead.<\/p>\n<p>The following example helps illustrate the differences between the data types:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE\n\t&#160; @stuff1 CHAR(7) = 'thing',\n\t&#160; @stuff2 NCHAR(7) = 'thing',\n\t&#160; @stuff3 VARCHAR(10) = 'thing',\n\t&#160; @stuff4 NVARCHAR(10) = 'thing';\n\tSELECT \n\t&#160; DATALENGTH(@stuff1) AS char1,\n\t&#160; DATALENGTH(@stuff2) AS nchar2,\n\t&#160; DATALENGTH(@stuff3) AS varchar3,\n\t&#160; DATALENGTH(@stuff4) AS nvarchar4;\n\t\n<\/pre>\n<p>All we&#8217;re doing here is using the <code>DATALENGTH<\/code> function to determine the size  of each variable, as shown in the following results:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>char1<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>nchar2<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>varchar3<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>nvarchar4<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">7<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">14<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">5<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">10<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tAlthough the value is only five characters long, the length of the  \t<code>CHAR<\/code>  value is seven bytes, because that was how the variable was defined. The  \t<code>NCHAR<\/code> value works the same way,  except that it&#8217;s doubled to account for the Unicode characters, so the <code>DATALENGTH<\/code> function returns  \t<code>14<\/code>.  On the other hand, the <code>VARCHAR<\/code> value requires only the bytes needed for the value (not including the overhead  bytes). The <code>NVARCHAR<\/code>  value merely doubles that.<\/p>\n<p>The choice, then, on whether to use <code>CHAR<\/code> or  \t<code>VARCHAR<\/code>  depends on how consistent the size of the values are and how small the values are. Microsoft recommends that you use \t<code>CHAR<\/code>  only when value lengths are consistent, and use <code>VARCHAR<\/code> when the lengths vary a  lot. Microsoft is noncommittal about the gray areas in between.  \t \t<\/p>\n<p>Small columns (fewer than five or six characters) often work well as  \t<code>CHAR<\/code>  columns when you take into account the overhead added to a <code>VARCHAR<\/code> column. Even so, some  developers would suggest that you use <code>CHAR<\/code> only if all values are exactly the  same length. If values are shorter than the designated length, they get padded with spaces, which can be annoying to deal  with and could potentially waste a lot of space if your values are mostly one-to-two characters but you&#8217;ve created a \t<code>CHAR(5)<\/code>  column to accommodate a relatively few five-digit values.  \t \t<\/p>\n<p>That said, if all your values are a comparable length, you don&#8217;t incur the storage penalty  for overhead that comes with <code>VARCHAR<\/code>, although storage has grown so  cheap, some of the concerns about the extra space have been mitigated. You might see some performance gains if you go  with <code>CHAR<\/code>,  but the significance of those gains can vary and are perhaps not worth the trade-off of having to deal with the trailing  spaces. Even so, <code>CHAR<\/code> is a useful option when your  data is consistent and small.<\/p>\n<\/p><\/div>\n<h3 id=\"tenth\">&#8220;I&#8217;m  building a query that joins a  \t<code>FLOAT<\/code>  column to a  \t<code>REAL<\/code>  column, but when I run the statement, it returns no results, even though I can see the matching values in the two  columns. Why is this happening?&#8221;<\/h3>\n<div class=\"indent\">\n<p>Welcome to the shifty world of approximate-number data types, in which floating-point data is  merely an approximation and the numbers you see might not be the real numbers at all. Let me demonstrate. The following  T-SQL declares a <code>FLOAT<\/code>  variable, sets its value, and retrieves the value as its represented in SQL Server Management Studio (SSMS) as well as  it actually exists in the database:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @StuffAvg FLOAT = 33.33;\n\tSELECT @StuffAvg AS StuffAvg, \n\t&#160; STR(@StuffAvg, 30, 15) AS RealStuff;\n\t<\/pre>\n<p>The <code>STR<\/code> function converts the numerical data to  character data and, in the process, gives us a glimpse of what&#8217;s really out there:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffAvg<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>RealStuff<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">33.33<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">33.329999999999998<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tSo here&#8217;s what&#8217;s happened. We assigned the value  \t<code>33.33<\/code>  to the variable, but the database engine actually stored it as <code>33.329999999999998<\/code>, thus the approximation  component. When SSMS retrieves that value, however, it sees fit to once again make it look nice and neat (a fact that  displeases more than a few in the SQL Server user community).<\/p>\n<p>On the surface, all this might not seem too big a deal-or perhaps it does. In any case, let&#8217;s  take a closer look. The following T-SQL creates a table that contains a <code>FLOAT<\/code> column and a  \t<code>REAL<\/code>  column and then populates those columns with a few choice values:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tIF OBJECT_ID('OurStuff', 'U') IS NOT NULL\n\tDROP TABLE OurStuff;\n\tGO\n\t\n\tCREATE TABLE OurStuff\n\t(\n\t&#160; StuffID INT NOT NULL IDENTITY PRIMARY KEY,\n\t&#160; StuffAvg1 FLOAT NOT NULL,\n\t&#160; StuffAvg2 REAL NOT NULL\n\t);\n\tGO\n\t\n\tINSERT INTO OurStuff(StuffAvg1, StuffAvg2)\n\tVALUES(33.33, 33.33), (66.66, 66.66), (99.99, 99.99);\n<\/pre>\n<p> \tNow let&#8217;s do what we did with our variable and retrieve the SSMS-enhanced values and the  actual values:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT\n\t&#160; StuffID,\n\t&#160; StuffAvg1, \n\t&#160; STR(StuffAvg1, 30, 15) AS RealStuff1,\n\t&#160; StuffAvg2, \n\t&#160; STR(StuffAvg2, 30, 15) AS RealStuff2\n\tFROM OurStuff;\n\t<\/pre>\n<p> \tOnce again, our trusty <code>STR<\/code> function comes to the rescue  and shows us what&#8217;s what:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffAvg1<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>RealStuff1<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffAvg2<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>RealStuff2<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">33.33<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">33.329999999999998<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">33.33<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">33.330001831054688<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">66.66<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">66.659999999999997<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">66.66<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">66.660003662109375<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">99.99<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">99.989999999999995<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">99.99<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">99.989997863769531<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tAs you can see, not only do the <code>FLOAT<\/code> and  \t<code>REAL<\/code>  data types like to approximate their values, they also like to do it differently. Yet according to the SSMS perspective,  each pair of values is exactly the same. What makes matters worse is that our references to the values also get somewhat  fuzzy. Check it out:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff\n\tWHERE StuffAvg1 = 33.33;\n\t<\/pre>\n<p>When we specify <code>33.33<\/code> in our  \t<code>WHERE<\/code>  clause, the applicable row is returned:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffAvg1<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffAvg2<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">33.33<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">33.33<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tNow let&#8217;s specify <code>33.329999999999998<\/code> in our  \t<code>WHERE<\/code>  clause:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurStuff\n\tWHERE StuffAvg1 = 33.329999999999998; \n\t<\/pre>\n<p> \tThe statement returns the exact results as the previous one. And it works the same way for  our <code>REAL<\/code> column. Either value will  return the same row.<\/p>\n<p>By all appearances, then, it would seem that we could specify either value or compare values  and everything would work out fine. Guess again. This time around, we&#8217;ll compare the values as they appear in SSMS,  without the benefit of <code>STR<\/code>:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @StuffAvg1 FLOAT = 33.33;\n\tDECLARE @StuffAvg2 REAL = 33.33;\n\tPRINT \n\t&#160; CASE \n\t&#160;&#160;&#160; WHEN @StuffAvg1 = @StuffAvg2 \n\t&#160;&#160;&#160; THEN 'equal' \n\t&#160;&#160;&#160; ELSE 'not equal'\n\t&#160; END;\n\t<\/pre>\n<p>It turns out that the statement returns a value of  \t<code>not<\/code> \t<code>equal<\/code>,  suggesting that, despite appearances, not all instances of <code>FLOAT<\/code> and  \t<code>REAL<\/code>  are anything close to equal. So what happens if we try to join a <code>FLOAT<\/code> column to a  \t<code>REAL<\/code>  column? To find out, let&#8217;s create a couple tables and add some data:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tIF OBJECT_ID('OurStuff', 'U') IS NOT NULL\n\tDROP TABLE OurStuff;\n\tGO\n\t\n\tIF OBJECT_ID('OurOtherStuff', 'U') IS NOT NULL\n\tDROP TABLE OurOtherStuff;\n\tGO\n\t\n\tCREATE TABLE OurStuff\n\t(\n\t&#160; StuffID INT NOT NULL IDENTITY PRIMARY KEY,\n\t&#160; StuffAvg1 FLOAT NOT NULL\n\t);\n\tGO\n\t\n\tCREATE TABLE OurOtherStuff\n\t(\n\t&#160; StuffID INT NOT NULL IDENTITY PRIMARY KEY,\n\t&#160; StuffAvg2 REAL NOT NULL\n\t);\n\tGO\n\t\n\tINSERT INTO OurStuff(StuffAvg1)\n\tVALUES(33.33), (66.66), (99.99);\n\t\n\tINSERT INTO OurOtherStuff(StuffAvg2)\n\tVALUES(33.33), (66.66), (99.99);\n\t<\/pre>\n<p>Now let&#8217;s retrieve the data in the <code>OurStuff<\/code> table:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT * FROM OurStuff;\n\t<\/pre>\n<p>Not surprisingly, our results look like this:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffAvg1<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">33.33<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">66.66<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">99.99<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tNext, let&#8217;s retrieve the data in the <code>OurOtherStuff<\/code> table:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT * FROM OurOtherStuff;<\/pre>\n<p> \tOnce again, no surprises:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffAvg2<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">33.33<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">66.66<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">99.99<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tSo with everything in place, let&#8217;s join these critters:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\t\tSELECT a.StuffID, a.StuffAvg1, b.StuffAvg2\n\tFROM OurStuff a INNER JOIN OurOtherStuff b\n\t&#160; ON a.StuffAvg1 = b.StuffAvg2;\n\t<\/pre>\n<p>As it turns out, the statement returns no rows, which is why Microsoft generally recommends  that you avoid&#160; using<code> FLOAT<\/code> or <code>REAL<\/code> in equality constructions in places such as joins or <code>WHERE<\/code> conditions. To make this work, you  would need to do some rounding or converting or creating calculated columns or something as equally clever. Just don&#8217;t  rely on <code>FLOAT<\/code>  and <code>REAL<\/code>  for any sort of precision. That&#8217;s not what they were designed to do. They offer a great deal of flexibility, but at a  price.<\/p>\n<\/p><\/div>\n<h3 id=\"eleventh\">&#8220;I have a table that  includes a  \t<code>VARCHAR<\/code> column and a stored procedure that accesses data from the  table, based on values in that column. The procedure includes an  \t<code>NVARCHAR<\/code>  parameter used to qualify the  \t<code>WHERE<\/code>  clause, which references the  \t<code>VARCHAR<\/code>  column. Does it matter that the data types are different between the parameter and the column?&#8221;<\/h3>\n<div class=\"indent\">\n<p>Yes, it matters, but let&#8217;s make sure we&#8217;re talking about the same thing. The following T-SQL  script creates a table, inserts data into that table, creates a procedure that retrieves data from that table, and then  executes the procedure, passing in the parameter value <code>Really<\/code>  \t<code>Big<\/code> \t<code>Thing<\/code>:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tIF OBJECT_ID('OurStuff', 'U') IS NOT NULL\n\tDROP TABLE OurStuff;\n\tGO\n\t\n\tCREATE TABLE OurStuff\n\t(\n\t&#160; StuffID INT NOT NULL IDENTITY PRIMARY KEY,\n\t&#160; StuffName VARCHAR(25) NOT NULL,\n\t&#160; StuffDate DATETIME NOT NULL DEFAULT GETDATE()\n\t);\n\tGO\n\t\n\tINSERT INTO OurStuff(StuffName)\n\tVALUES('Thing'), ('Big Thing'), ('Really Big Thing'), ('Amazingly Big Thing');\n\t\n\tIF OBJECT_ID('FindStuff', 'P') IS NOT NULL\n\tDROP PROCEDURE FindStuff;\n\tGO\n\t\n\tCREATE PROCEDURE FindStuff \n\t@stuff NVARCHAR(25)\n\tAS\n\tSELECT StuffID, StuffDate FROM OurStuff\n\tWHERE StuffName = @stuff;\n\tGO\n\t\n\tEXEC FindStuff 'Really Big Thing';\n\t<\/pre>\n<p>When you run the procedure, it returns the <code>StuffID<\/code> and  \t<code>StuffDate<\/code>  values, as the following results show:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-06 17:16:29.457<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tou might have noticed that the table&#8217;s <code>StuffName<\/code> column is configured as  \t<code>VARCHAR<\/code>  and the procedure&#8217;s <code>@stuff<\/code>  parameter is configured as <code>NVARCHAR<\/code>. The database engine implicitly converts the value without no apparent problem.  In the background, however, we might find a different story. Although the database engine can perform an implicit  conversion without a hiccup, the operation can result in a performance penalty, in part because it is preventing index  seeks. As a result, when you start adding millions-or billions-of rows to the equation, a minor data type mismatch can  have a significant impact. For more information about all this, check out my Simple Talk article &#8220;<a href=\"https:\/\/www.simple-talk.com\/sql\/t-sql-programming\/data-conversion-in-sql-server\/\">Data  Conversion in SQL Server<\/a>.&#8221;<\/p>\n<\/p><\/div>\n<h3 id=\"twelveth\">&#8220;My query needs to calculate  past and future dates based on an existing date as well as calculate the time difference between two dates. I&#8217;ve tried  using arithmetic operators to perform the calculations, but the results are never right. How do I go about working with  dates?&#8221;<\/h3>\n<div class=\"indent\">\n<p>The best two tools for achieving what you&#8217;re trying to do are the  \t<code>DATEADD<\/code>  and <code>DATEDIFF<\/code>  functions. <code>DATEADD<\/code>  subtracts or adds a specified interval of time to a date value, which can be any date or time data type.  \t<code>DATEDIFF<\/code>  returns the interval of time between two specified date values. Again, the values can be any of the date or time date  types.<\/p>\n<p>Let&#8217;s first look at how the <code>DATEADD<\/code> function works. The following T-SQL  declares a <code>DATETIME<\/code>  variable, uses the <code>GETDATE<\/code>  function to assign the current date and time values to the function, and then retrieves the dates 10 years forward and  10 years back:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @StuffDate DATETIME = GETDATE();\n\tSELECT \n\t&#160; @StuffDate AS StuffDate,\n\t&#160; DATEADD(yy, 10, @StuffDate) AS Plus10,\n\t&#160; DATEADD(yy, -10, @StuffDate) AS Less10;\n\t<\/pre>\n<p>The <code>DATEADD<\/code> function takes three arguments. The  first argument is the date part, such as day, week, month, or year. In this case, we&#8217;ve specified  \t<code>yy<\/code>  for year. The second argument is the number of years forward or backward we want to go. Finally, we specify our base  date. The <code>SELECT<\/code>  statement returns the following results:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Plus10<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Less10<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-07 19:03:50.183<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2024-07-07 19:03:50.183<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2004-07-07 19:03:50.183<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tIf we want to extract a specific date or time element, we can use the  \t<code>DATEPART<\/code>  function, as in the following example:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @StuffDate DATETIME = GETDATE();\n\tSELECT \n\t&#160; DATEPART(yy, @StuffDate) AS StuffDate,\n\t&#160; DATEPART(yy, DATEADD(yy, 10, @StuffDate)) AS Plus10,\n\t&#160; DATEPART(yy, DATEADD(yy, -10, @StuffDate)) AS Less10;\n\t<\/pre>\n<p>All we&#8217;ve done is specify that only the year should be extracted from the date, as shown in  the following results:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Plus10<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Less10<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2024<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2004<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tNow let&#8217;s use the <code>DATEDIFF<\/code> function to calculate the  number of months between two dates:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tDECLARE @StuffDate1 DATETIME = GETDATE();\n\tDECLARE @StuffDate2 DATETIME = DATEADD(yy, 10, @StuffDate1);\n\tSELECT \n\t&#160; DATEPART(yy, @StuffDate1) AS StuffDate1,\n\t&#160; DATEPART(yy, @StuffDate2) AS StuffDate2,\n\t&#160; DATEDIFF(mm, @StuffDate1, @StuffDate2) AS MonthDiff;\n\t<\/pre>\n<p>The <code>DATEDIFF<\/code> function also requires three  arguments. As with <code>DATEADD<\/code>, the first argument is the  date part. This time around we&#8217;re using <code>mm<\/code> for month. The next two arguments are  the dates we want to compare, in this case, our two <code>DATETIME<\/code> variables. As the following  results show, there are 120 months between the two dates:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate1<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffDate2<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>MonthDiff<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2024<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">120<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \tThe functions available in SQL Server for working with date and time values are definitely  ones worth getting to know. Date and time values are treated differently from other types of data and require special  consideration. You can find more about these functions in the MSDN topic &#8220;<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms186724.aspx\">Date  and Time Data Types and Functions<\/a>.&#8221;<\/p>\n<\/p><\/div>\n<h3 id=\"thirteenth\">&#8220;I&#8217;m told never to use \t \t<code>SQL_VARIANT<\/code> data type inappropriately. What is an appropriate use for  this data type?&#8221;<\/h3>\n<div class=\"indent\">\n<p>SQL_VARIANT is included in SQL Server mainly for system use. Although it is used within system procedures  \tand views, It has several important&#160; restrictions. It can only be used with great caution, and there is usually  \ta better way. It cannot be used in a relational table.&#160; However, there do exist some appropriate specialised  \tuses.<\/p>\n<p>An appropriate use is  one in which you have no other reasonable option or a reasonable option requires a workaround that causes more trouble  than using <code>SQL_VARIANT<\/code>.  In fact, under the right circumstances, the data type could prove a valuable tool. It supports most T-SQL base types all  within a single structure, such as a column or parameter. For example, if you define a column with  \t<code>SQL_VARIANT<\/code>, you can insert  character data and numerical data and data\/time data. Here&#8217;s proof. The following T-SQL script creates a table that  includes a <code>SQL_VARIANT<\/code>  column and then inserts into it an assortment of values:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tIF OBJECT_ID('OurStuff', 'U') IS NOT NULL\n\tDROP TABLE OurStuff;\n\tGO\n\t\n\tCREATE TABLE OurStuff\n\t(\n\t&#160; StuffID INT NOT NULL IDENTITY PRIMARY KEY,\n\t&#160; StuffName SQL_VARIANT NOT NULL\n\t);\n\tGO\n\t\n\tINSERT INTO OurStuff(StuffName) VALUES('Same Old Thing');\n\tINSERT INTO OurStuff(StuffName) VALUES(479);\n\tINSERT INTO OurStuff(StuffName) VALUES(GETDATE());\n\tINSERT INTO OurStuff(StuffName) VALUES(1e9);\n\tINSERT INTO OurStuff(StuffName) VALUES(453.66903438);\n\t<\/pre>\n<p>Sure, we can insert the same data into a <code>VARCHAR<\/code> column, but the values would all  come out <code>VARCHAR<\/code>  data. The <code>SQL_VARIANT<\/code>  data type, on the other hand, preserves the original type, which we can verify by using the  \t<code>SQL_VARIANT_PROPERTY<\/code>  function:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">\tSELECT\n\t&#160; StuffName,\n\t&#160; SQL_VARIANT_PROPERTY(StuffName, 'basetype') AS BaseType,\n\t&#160; SQL_VARIANT_PROPERTY(StuffName, 'maxlength') AS BaseLength,\n\t&#160; SQL_VARIANT_PROPERTY(StuffName, 'precision') AS BasePrecision\n\tFROM OurStuff;\n\t<\/pre>\n<p> \tAnd here are the results:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StuffName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>BaseType<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>BaseLength<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>BasePrecision<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Same Old Thing<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">varchar<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8000<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">479<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">int<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">10<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2014-07-08 09:06:34.440<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">datetime<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">23<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1000000000<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">float<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">8<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">53<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">453.66903438<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">numeric<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">9<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">11<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Notice that each type has been preserved. <code>SQL_VARIANT<\/code> was even able to pick up on the  scientific notation. So you can see why, in certain circumstances, such a data type could be useful. For example, you  might consider <code>SQL_VARIANT<\/code>  when defining a parameter in a stored procedure or function. This approach helps to maintain some of the precision you might otherwise lose when passing  in numeric or date\/time values through a <code>VARCHAR<\/code> parameter. Another example of how \t<code>SQL_VARIANT<\/code> might be useful is if  you&#8217;re supporting an application that allows users to define their own tables and fields.  \t<code>SQL_VARIANT<\/code> can help you avoid  having to set up extra structures to support each data type.<\/p>\n<p>You&#8217;ll have to decide on a case-by-case basis whether to use  \t<code>SQL_VARIANT<\/code>,  but know that the data type comes with a number of limitations. For instance, SQL Server converts  \t<code>SQL_VARIANT<\/code>  values to <code>NVARCHAR(4000)<\/code>  to support older versions of the OLE DB and ODBC providers. Same thing with many other external tools that don&#8217;t  recognize <code>SQL_VARIANT<\/code>.  In addition, using linked servers in conjunction with <code>SQL_VARIANT<\/code> can lead to potential memory  leaks. Plus, you can&#8217;t use the data type in statement elements such as <code>LIKE<\/code> expressions or computed columns. So  before you implement the <code>SQL_VARIANT<\/code> data type, do your homework. A good place to start with the TechNet topic &#8220;<a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/ms181071.aspx\">Using  sql_variant Data<\/a>.<\/p>\n<\/p><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p> Although SQL  Data Types seem to cause a lot of grief for database developers and can be tricky in their use, we seem to be expected to know all about them, and so it is embarrassing to ask questions about them in forums. Rob Sheldon continues in his mission to answer all those questions that we hesitate to ask.&hellip;<\/p>\n","protected":false},"author":221841,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143531],"tags":[4168,4150,4151,4252,5771],"coauthors":[],"class_list":["post-1837","post","type-post","status-publish","format-standard","hentry","category-t-sql-programming-sql-server","tag-database","tag-sql","tag-sql-server","tag-t-sql-programming","tag-too-shy"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1837","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221841"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1837"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1837\/revisions"}],"predecessor-version":[{"id":41052,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1837\/revisions\/41052"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1837"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1837"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1837"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1837"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}