Select the product you need help with
- Internet Explorer
- Windows Phone
- More products
The behavior is different when comparing between columns and constants with different data types in SQL Server 7.0 and later versions of SQL Server
Article ID: 271566 - View products that this article applies to.
This article was previously published under Q271566
SQL Server 2000 behavior differs from previous versions of SQL Server when queries that involve comparisons between columns and constants with different data types are run. You can expect results and performance differences because of the way data type conversions are determined compared to earlier releases of SQL Server.
In SQL Server versions 7.0 and earlier, whenever a query uses a comparison operator between a column and a literal, the data type of the column is used regardless of the precedence rules. That is, if the column and the literal have different data types, the latter is always converted to the data type of the column (as long as the conversion is valid). This behavior may lead to undesired precision reduction, string truncation, or other conversions.
In SQL Server 2000, this is no longer true. A conversion is performed according to data type precedence, as it is in any other comparison. In the case where a literal is positioned higher in the hierarchy, the comparison is made between the constant and the converted column (as opposed to previous versions) and therefore, results may differ. Consequently, existing indexes may not be useful, different execution plans may be chosen, and performance may be impacted negatively.
Note SQL Server 2005 and later versions of the program include improvements to handle numeric data type comparisons. Other than the varchar/nvarchar scenario, all other scenarios that are described in this article do not apply to SQL Server 2005 and later versions. However, Microsoft still recommends that you correctly match data types when you perform data comparisons and joins.
Although this new behavior provides consistency among comparisons in SQL Server, it may pose backward compatibility issues for applications that rely on the old semantics. You can force SQL Server 2000 to behave in the same way as earlier versions of SQL Server by doing either of the following:
Note Queries that used to be run with efficient index seeks may now use index scans or table scans. Higher CPU time, execution times, or I/O may be evidence that you are being negatively affected by the new behavior. Microsoft strongly recommends that you use explicit casts in these cases.
Note This behavior does not apply to the LIKE operator. It does apply to the comparison operators (equality, inequality, greater than, and so forth) IN and BETWEEN.
Behavior changes in SQL Server 2000 regarding the comparison of columns and constants have several implications on the expected results as compared to previous releases, such as:
Query resultsConsider the following scenario:
If you run the following query on SQL Server version 7.0 (or earlier) or on SQL Server 2000 with database compatibility level set to 70, you receive the following results:
If you run the same query on SQL Server 2000 using the default compatibility level (80), you receive the following results:
select * from T1 where col1=2.3 col1 ----------- 2 (1 row(s) affected)
In the first case, 2.3 is converted to an int value (yielding 2 as a result) and the query is executed as "...where col1=2," returning one row because constants are always converted to the data type column.
col1 ----------- (0 row(s) affected)
In the second case, the constant 2.3 is identified as an approximate number that is higher in the data type hierarchy than the column declared as int. Therefore, the query is evaluated as "convert(decimal(2,1), col1)=2.3" and no rows are returned. If you want SQL Server 2000 to behave as earlier versions did, then rewrite the query as:
The same situation applies to other data types as well. For example, a comparison between a column of char data type and a Unicode constant might generate different results on SQL Server 7.0 and SQL Server 2000.
Query execution plans, index selection, and performanceAs stated earlier, in some cases a column may be converted to another data type to perform the comparison depending on the data types being compared. This means that a query with a predicate such as "<column> = <literal>" is treated as "...convert<(other_data_type>, <column)> = <literal>" and the execution plan for such a variation might change significantly.
Consider the following scenario:
The following query on SQL Server version 7.0 or on SQL Server 2000 with a 70 database compatibility level is run by using an index seek for the particular value:
Under compatibility level 80, SQL Server 2000 uses an index scan, which results in higher I/O, CPU usage, and run time.
Consider another scenario:
The following query on SQL Server 7.0 or on SQL Server 2000 with a 70 database compatibility level gives us the query plan below.
Under compatibility level 80, SQL Server 2000 converts the literal 1 to the same data type as the Col1 column. Therefore, it is converted to an int.
The assumed base type of the literal 1 is tinyint. The tinyint data type is the lowest in the data type precedence in the integer family.
This allows you to convert the literal to the data type of the column without a loss in precision.
If the conversion happens between numeric data types, equality comparison is executed as a range seek followed by a comparison (of the returned range) with the constant. This has the negative consequence of disallowing the use of additional columns on composite indexes, as in the following scenario:
Running the following query with previous behavior yields an index seek on the two columns:
Under SQL Server 2000 with an 80 compatibility level, the plan includes an index range seek on the first column only, followed by a nested loops join with the constant to find the matching rows. (Note that the complete plan is not shown.)
Error conditionsThe new comparison behavior may also allow queries that used to fail on previous versions. Consider the following scenario:
If you run the following query, an error is raised under the previous behavior because SQL Server attempts to convert the constant 300 into a tinyint value:
Under SQL Server 2000 (set to a compatibility level 80), the query runs because the tinyint column is converted to a larger integer data type:
Result: Server: Msg 220, Level 16, State 2, Line 1 Arithmetic overflow error for data type tinyint, value = 300.
col1 ---- (0 row(s) affected)
Additional resourcesTo change the compatibility level of a database, use the sp_dbcmptlevel stored procedure. For more information, refer to the "sp_dbcmptlevel" and "Database Compatibility Level Option" topics in SQL Server Books Online.
For more information on data type precedence hierarchy, see the "Data Type Precedence" topic in SQL Server Books Online.
For more information on using literals on SQL Server, see the "Constants" topic in SQL Server Books Online.
Article ID: 271566 - Last Review: October 5, 2011 - Revision: 7.0