{"id":583,"date":"2007-05-23T19:58:38","date_gmt":"2007-05-23T17:58:38","guid":{"rendered":"http:\/\/www.glorf.it\/blog\/2007\/05\/23\/sql-talk\/sql-server-trailings-blanks"},"modified":"2007-05-23T19:58:38","modified_gmt":"2007-05-23T17:58:38","slug":"sql-server-trailings-blanks","status":"publish","type":"post","link":"http:\/\/www.glorf.it\/blog\/2007\/05\/23\/sql-talk\/sql-server-trailings-blanks","title":{"rendered":"SQL Server: Trailings blanks"},"content":{"rendered":"<p>When SQL Server compares two strings, it makes a comparison from left to right and treats the shorter expression as though it was padded with spaces to equal the length of the longer string.<br \/>\nFor most people the result is unexpected: padded blanks are ignored!<\/p>\n<p>Lets see some samples:<\/p>\n<p><code>'Hello ' = 'Hello' --> true<\/code><\/p>\n<p>The same applies for unicode:<\/p>\n<p><code>N'Hello ' = N'Hello' --> true<\/code><\/p>\n<p>LIKE behaves a little different. Firstly comparing unicode results different:<\/p>\n<p><code> 'Hello ' LIKE  'Hello'  --> true<br \/>\nN&#x0027;Hello &#x0027; LIKE N&#x0027;Hello&#x0027;  &#8211;> false<\/code><\/p>\n<p>And second blanks in the pattern are allways significant:<\/p>\n<p><code> 'Hello' LIKE  'Hello ' --> false<br \/>\nN&#x0027;Hello&#x0027; LIKE N&#x0027;Hello &#x0027; &#8211;> false<\/code><\/p>\n<p>What about LEN? It behaves consistent to the test for equality: padding blanks are ignored.<\/p>\n<p><code>LEN('Hello')     --> 5<br \/>\nLEN(&#x0027;Hello &#x0027;)    &#8211;> 5<br \/>\nLEN(N&#x0027;Hello&#x0027;)    &#8211;> 5<br \/>\nLEN(N&#x0027;Hello &#x0027;)   &#8211;> 5 <\/code><\/p>\n<p><code>DATALENGTH('Hello')   -->  5<br \/>\nDATALENGTH(&#x0027;Hello &#x0027;)  &#8211;>  6<br \/>\nDATALENGTH(N&#x0027;Hello&#x0027;)  &#8211;> 10<br \/>\nDATALENGTH(N&#x0027;Hello &#x0027;) &#8211;> 12<\/code><\/p>\n<p>So we have some possible solutions, if we neeed to check for equality with blank awareness:<\/p>\n<p>1. Use allways unicode and LIKE<br \/>\n2. add some dummy character at the end:<br \/>\n<code lang=\"sql\"> 'Hello'+ '#'= 'Hello '+ '#'<br \/>\nN&#x0027;Hello&#x0027;+N&#x0027;#'=N&#x0027;Hello &#x0027;+N&#x0027;#&#x0027;<\/code><br \/>\n3. convert to varbinary:<br \/>\n<code lang=\"sql\">cast( 'Hello ' as varbinary(10)) = cast( 'Hello' as varbinary(10))<br \/>\ncast(N&#x0027;Hello &#x0027; as varbinary(20)) = cast(N&#x0027;Hello&#x0027; as varbinary(20))<\/code><br \/>\n4. compare datalength:<br \/>\n<code lang=\"sql\">'Hello'= 'Hello ' AND DATALENGTH( 'Hello')=DATALENGTH( 'Hello ')<br \/>\nN&#x0027;Hello&#x0027;=N&#x0027;Hello &#x0027; AND DATALENGTH(N&#x0027;Hello&#x0027;)=DATALENGTH(N&#x0027;Hello &#x0027;)<\/code><\/p>\n<p>P.S.<br \/>\nPlease be aware that the described behavior applies only to varchar and nvarchar, not char\/nchar!<br \/>\nCHAR\/NCHAR are always filled with blanks.<br \/>\nIf you use ANSI_PADDING OFF trailing blanks are trimmed when inserted in a table.<\/p>\n<p><code lang=\"sql\">-- ANSI<br \/>\ndeclare @vchar1 varchar(10),<br \/>\n\t\t@vchar2 varchar(10);<\/p>\n<p>set @vchar1 = &#x0027;Hello &#x0027;;<br \/>\nset @vchar2 = &#x0027;Hello&#x0027;;<\/p>\n<p>select<br \/>\n\t&#x0027;&quot;&#x0027;+@vchar1+&#x0027;&quot;&#x0027; as &quot;@vchar1&quot;,<br \/>\n\t&#x0027;&quot;&#x0027;+@vchar2+&#x0027;&quot;&#x0027; as &quot;@vchar1&quot;,<br \/>\n\tcase when @vchar1=@vchar2<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;@vchar1=@vchar2&quot;,<br \/>\n\tcase when @vchar1 like @vchar2<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;@vchar1 like @vchar2&quot;,<br \/>\n\tcase when @vchar2 like @vchar1<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;@vchar2 like @vchar1&quot;, &#8211;> false<br \/>\n\tcase when @vchar1+&#x0027;#'=@vchar2+&#x0027;#&#x0027;<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;@vchar1+&#x0027;#'=@vchar2+&#x0027;#'&quot;, &#8211;> false<br \/>\n\tcase when cast(@vchar1 as varbinary(10)) = cast(@vchar2 as varbinary(10))<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;cast(@vchar1 as varbinary(10)) = cast(@vchar2 as varbinary(10))&quot;,<br \/>\n\tcase when @vchar1=@vchar2 AND DATALENGTH(@vchar1)=DATALENGTH(@vchar2)<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;@vchar1=@vchar2 AND DATALENGTH(@vchar1)=DATALENGTH(@vchar2)&quot;;<br \/>\ngo<\/p>\n<p>&#8211; Unicode<br \/>\ndeclare @nvchar1 nvarchar(10),<br \/>\n\t\t@nvchar2 nvarchar(10);<\/p>\n<p>set @nvchar1 = &#x0027;Hello &#x0027;;<br \/>\nset @nvchar2 = &#x0027;Hello&#x0027;;<\/p>\n<p>select<br \/>\n\t&#x0027;&quot;&#x0027;+@nvchar1+&#x0027;&quot;&#x0027; as &quot;@nvchar1&quot;,<br \/>\n\t&#x0027;&quot;&#x0027;+@nvchar2+&#x0027;&quot;&#x0027; as &quot;@nvchar1&quot;,<br \/>\n\tcase when @nvchar1=@nvchar2<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;@nvchar1=@nvchar2&quot;,<br \/>\n\tcase when @nvchar1 like @nvchar2<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;@nvchar1 like @nvchar2&quot;,<br \/>\n\tcase when @nvchar2 like @nvchar1<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;@nvchar2 like @nvchar1&quot;,<br \/>\n\tcase when @nvchar1+&#x0027;#'=@nvchar2+&#x0027;#&#x0027;<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;@nvchar1+&#x0027;#'=@nvchar2+&#x0027;#'&quot;,<br \/>\n\tcase when cast(@nvchar1 as varbinary(20)) = cast(@nvchar2 as varbinary(20))<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;cast(@nvchar1 as varbinary(20)) = cast(@nvchar2 as varbinary(20))&quot;,<br \/>\n\tcase when @nvchar1=@nvchar2 AND DATALENGTH(@nvchar1)=DATALENGTH(@nvchar2)<br \/>\n\t\tthen &#x0027;true&#x0027;<br \/>\n\t\telse &#x0027;false&#x0027; end as &quot;@nvchar1=@nvchar2 AND DATALENGTH(@nvchar1)=DATALENGTH(@nvchar2)&quot;;<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>When SQL Server compares two strings, it makes a comparison from left to right and treats the shorter expression as though it was padded with spaces to equal the length of the longer string. For most people the result is unexpected: padded blanks are ignored! Lets see some samples: &#x0027;Hello &#x0027; = &#x0027;Hello&#x0027; &#8211;> true [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[],"_links":{"self":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts\/583"}],"collection":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/comments?post=583"}],"version-history":[{"count":0,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts\/583\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/media?parent=583"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/categories?post=583"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/tags?post=583"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}