Puzzling SQL server behaviour - results in different formats if there is a 1<>2 expression in WHERE clause

StackOverflow https://stackoverflow.com/questions/22959084

  •  30-06-2023
  •  | 
  •  

문제

I have two almost identical SELECT statements. I am running them on a SQL Server 2012 with server collation Danish_Norwegian_CI_AS, and database collation Danish_Norwegian_CI_AS. The database runs in compatibility level set to SQL Server 2005 (90).

I run both of the queries on the same client via a SQL Server 2012 Management Studio. The client is a Windows 8.1 laptop.

The puzzling part is, although the statements are almost identical, the resultset is different as shown below (one returns 24-hour format time, the other with AM / PM, which gets truncated tpo P in this case). The only difference is the 'and 1<>2' expression in WHERE clause. I looked up and down, searched in google, digged as deep as I could, cannot find an explanation. Tried COLLATE to force conversion, did not help. If I use 108 to force formatting in CONVERT call, then the resultsets are alike. But not knowing the reason why this does not work is eating me alive.

Issue recreated on SqlFiddle, SQL Server 2008:

http://sqlfiddle.com/#!3/a97f8/1

Have someone an explain for this?

The SQL DDL and statements after results can be used to recreate the issue. The script creates a table with two columns, inserts some rows, and makes two selects.

On my machine the sql without the 1<>2 expression returns:

Id          StartTime
----------- ---------
2           2:00P
2           2:14P

The sql with the 1<>2 expression returns:

Id          StartTime
----------- ---------
2           14:00
2           14:14



if NOT EXISTS (Select * from sysobjects where name = 'timeVarchar')
begin
    create table timeVarchar (
        Id int not null,
        timeTest datetime not null
    )
end

if not exists (select * from timeVarchar) 
begin
    -- delete from timeVarchar
    print 'inserting'
    insert into timeVarchar (Id, timeTest) values (1, '2014-04-09 11:37:00')
    insert into timeVarchar (Id, timeTest) values (2, '1901-01-01 14:00:00')
    insert into timeVarchar (Id, timeTest) values (3, '2014-04-05 15:00:00')
    insert into timeVarchar (Id, timeTest) values (2, '1901-01-01 14:14:14')
end

select
        Id,
        convert ( varchar(5), convert ( time, timeTest)) as 'StartTime'
from
     timeVarchar
where
     Id = 2



select
     Id, 
        convert ( varchar(5), convert ( time, timeTest)) as 'StartTime'
from
     timeVarchar
where
     Id = 2 and
     1                       <>    2
도움이 되었습니까?

해결책

I can't answer why this is happening (at least not at the moment), but setting the conversion format explicitly does solve the issue:

select Id,
       convert (varchar(5), convert (time, timeTest), 14) as "StartTime"
from timeVarchar
where Id = 2;

select Id, 
       convert (varchar(5), convert (time, timeTest), 14) as "StartTime"
from timeVarchar
where Id = 2 
and  1 <> 2; 

Going through the execution plan, the two queries end up very different indeed.

The first one passes 2 as a parameter and (!) does CONVERT_IMPLICIT of the value. The second one passes it as a part of the query itself!

In the end, the actual query that gets to run in the first case actually explicitly does CONVERT(x, y, 0). For US locale, this is not a problem, since 0 is the invariant (~US) culture. But outside of the US, you're suddenly using 0 instead of e.g. 4 (for Germany).

So, definitely, one thing to take from this is that queries that look very much alike could execute completely differently.

The second thing is - always use convert with a specific format. The defaults don't seem to be entirely reliable.

EDIT: Ah, finally fished the thing out of the MSDN:

http://msdn.microsoft.com/en-us/library/ms187928.aspx

In earlier versions of SQL Server, the default style for CAST and CONVERT operations on time and datetime2 data types is 121 except when either type is used in a computed column expression. For computed columns, the default style is 0. This behavior impacts computed columns when they are created, used in queries involving auto-parameterization, or used in constraint definitions.

Since the first query is invoked as a parametrized query, it gets the default style 0, rather than 121. This behaviour is fixed in compatibility level 110+ (i.e. SQL SERVER 2012+) - on those servers, the default is always 121.

다른 팁

It seems the problem is solved in SQL2012

see this link http://sqlfiddle.com/#!6/a97f8/4

p.s Your mentioned url on sqlfiddle is running on SQL2008

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top