5

I have this query :

select '[' + p.Firstname + ']' from Person p
where p.Firstname = 'Johanne'

In the table, I have multiple personne who have this firstname, and some have a trailing space on the value (bad insertion of the values, it will be corrected).

Why then does this query bring me this result (I inserted the brackets to visualize the spaces) :

[Johanne]
[Johanne ]
[Johanne ]
[Johanne]

Is this a configuration thing ? The real query comes from entity framework 6, but this example does it also. How can I prevent it ?

Thanks !

Edit: I could make it work using EF6 and the System.Data.Entity.SqlServer.SqlFunctions.DataLength method like this:

ctx.Person.FirstOrDefault(p => p.FirstName == "Johanne" && SqlFunctions.DataLength(p.FirstName) == "Johanne".Length);
Shimrod
  • 3,115
  • 2
  • 36
  • 56
  • I noticed that if my value in the where clause is `'Johanne '` (with a space at the end), i still get the same result. – Shimrod Feb 23 '15 at 20:19
  • Correct but by default in Sql Server if you have a leading space then it will NOT match ie. ' Johanne' would not come back with any results in your where clause. – Igor Feb 23 '15 at 20:23
  • 1
    Does it work if you use `N'string here'`, e.g. `where p.Firstname = N'Johanne'`? The `N` tells it to use Unicode, which will match the type of the column. – Andrew Morton Feb 23 '15 at 20:24
  • @Igor I just tested it and I can confirm that a leading space will prevent the query to return values – Shimrod Feb 23 '15 at 20:24
  • @AndrewMorton, I just tested it, and it produces the same output. – Shimrod Feb 23 '15 at 20:25
  • See this existing post for details on why Sql Server ignores spaces: http://stackoverflow.com/a/4166186/1260204 – Igor Feb 23 '15 at 20:29
  • You could also/additionally test for length. – Anthony Horne Feb 23 '15 at 20:32

3 Answers3

5

SQL Server follows the ANSI/ISO SQL-92 specification (Section 8.2, , General rules #3) on how to compare strings with spaces. The ANSI standard requires padding for the character strings used in comparisons so that their lengths match before comparing them. The padding directly affects the semantics of WHERE and HAVING clause predicates and other Transact-SQL string comparisons. For example, Transact-SQL considers the strings 'abc' and 'abc ' to be equivalent for most comparison operations.

The only exception to this rule is the LIKE predicate. When the right side of a LIKE predicate expression features a value with a trailing space, SQL Server does not pad the two values to the same length before the comparison occurs. Because the purpose of the LIKE predicate, by definition, is to facilitate pattern searches rather than simple string equality tests, this does not violate the section of the ANSI SQL-92 specification mentioned earlier.

See: https://support.microsoft.com/en-us/topic/inf-how-sql-server-compares-strings-with-trailing-spaces-b62b1a2d-27d3-4260-216d-a605719003b0

Anthony Horne
  • 2,522
  • 2
  • 29
  • 51
  • Also see: http://richarddingwall.name/2007/12/28/t-sql-equality-operator-ignores-trailing-spaces/ – Anthony Horne Feb 23 '15 at 20:31
  • Thanks for the explanation Anthony ! Any idea how I can overcome this using EF6 ? i mean if I search on value `'Johanne '` (with the space), I don't want to see the values without the spaces. – Shimrod Feb 23 '15 at 20:47
  • You should, based on what I have read, be able to use like (read all the way), but as per the articles, be very aware of the performance knock. I have also read that EF "contains" is of some consequence in cases as this and operates much along the lines of like. See "implementation" of like in EF at http://stackoverflow.com/a/11371822/1662973 – Anthony Horne Feb 24 '15 at 19:20
  • I tried that and this doesn't work in my case, what Jon Skeet proposes in his answer translates to `LIKE %value%` when using EF6, so the same value with either a leading or a trailing space is matched. – Shimrod Feb 24 '15 at 19:38
  • What about .TrimEnd()? – Anthony Horne Feb 24 '15 at 19:45
  • Sorry - saw you had resolved it already. Learning exp for me too. Only using EF for oData right now. – Anthony Horne Feb 24 '15 at 19:47
  • 1
    The support article link is dead. – Zikato Sep 07 '21 at 13:27
2

I am not sure in EF but in TSQL I use DataLength

DataLength

DataLength will return the length including trailing blanks
Len will return the the length not including the trailing blanks

and DataLength(p.Firstname) = Len('Johanne')  
paparazzo
  • 44,497
  • 23
  • 105
  • 176
  • Yeah I did try `DataLength` (with success) in TSQL. However, When I use `string.Length` in EF6, it only converts to `LEN`, I don't know how to ask EF6 to use `DataLength` – Shimrod Feb 23 '15 at 23:03
  • where '[' + p.Firstname + ']' = '[Johanne]' – paparazzo Feb 24 '15 at 00:49
2

You could create a new view in Sql and map that view back to an EF object. The view could contain the length of the field(s), in the select using DataLength, you know you want to match against and then you could filter on that in your where clause when you use EF. Alternatively you could create a Sql Stored Proc that does a comparison using LIKE without wild cards (which produces the desired result) and map that back to your code and call it in your Where statement in EF.


Using View

Create View MyCustomView
AS
SELECT [column1,column2,etc], DATALENGTH(FirstName) AS FirstNameLength
FROM Person
GO

Then your EF would be:

Persons.Where(p => p.FirstNameLength == "Johanne".Length && p.FirstName == "Johanne");

To use a Stored Proc

CREATE PROCEDURE [dbo].[GetPersons]
firstName int = null
AS
BEGIN
SET NOCOUNT ON;
select [your fields here]
from persons
where FirstName like @firstName
END

In C# make sure your mapping is correct and then

this.Database.SqlQuery<Person>("GetPersons","Johanne");

EF6 also supports directly editing the sql in the DbContext before it is executed. You could develop some custom code that replaces the = with like under specific circumstances but maybe easier to try the above first before you do that.

Igor
  • 60,821
  • 10
  • 100
  • 175
  • I found an easier way to do it using `SqlFunctions` class, see my edit. But thanks a lot for your solutions, they are good replacements ! – Shimrod Feb 24 '15 at 14:04