In Microsoft SQL Server 2005 Transact-SQL (and prior versions), you can make a dynamic ORDER BY based on a variable like so:
DECLARE @OrderBy varchar (50)
SELECT * FROM Customer
ORDER BY
CASE @OrderBy
WHEN ‘CustomerID‘ THEN Customer.CustomerID –CustomerID is an integer column
WHEN ‘MemberSince‘ THEN Customer.MemberSince –MemberSince is smalldatetime colum
WHEN ‘FullName‘ THEN Customer.FullName – FullName is a varchar colum
WHEN ‘Category‘ THEN Customer.Category – Category is a char column
WHEN ‘Rating‘ THEN Customer.Rating –Rating is a float column
END ASC
You can
SET @OrderBy = ‘CustomerID‘
or
SET @OrderBy = ‘Rating‘
, sorting will fail with SQL error similar to the following:
Conversion failed when converting character string to smalldatetime data type.
in the first case
and
Msg 8115, Level 16, State 2, Line 3
Arithmetic overflow error converting expression to data type smalldatetime.
in the second if the optimizer encounters data that can’t be converted to integer.
The explanation is found in the SQL Server books online:
[The CASE statement] returns the highest precedence type from the set of types in result_expressions and the optional else_result_expression.
This means that you cannot mix types in your CASE statement which cannot be implicitly converted into the types with higher precedence according to the following list (also found in Books Online):
- user-defined data types (highest)
- sql_variant
- xml
- datetime
- smalldatetime
- float
- real
- decimal
- money
- smallmoney
- bigint
- int
- smallint
- tinyint
- bit
- ntext
- text
- image
- timestamp
- uniqueidentifier
- nvarchar
- nchar
- varchar
- char
- varbinary
- binary (lowest)
Because datetime and smalldatetime with their high precedence are internally stored as 4-byte and 2-byte integers respectively, you can almost always mix integers with datetime or smalldatetime. Floating numbers don’t mix unless they can be cleanly converted to integers.
As a workaround you could use table variables or Common Table Expressions (CTE, new in SQL Server 2005), insert the ordered data, and query these instead.
The better solution with less overhead might be to group the CASE statements according to data types. The above example would look like this:
DECLARE @OrderBy varchar (50)
SELECT * FROM Customer
ORDER BY
CASE @OrderBy –“integer data” first
WHEN ‘CustomerID‘ THEN Customer.CustomerID –CustomerID is numeric column
WHEN ‘MemberSince‘ THEN Customer.MemberSince –MemberSince is smalldatetime colum
END, CASE @OrderBy –now the char and varchar
WHEN ‘FullName‘ THEN Customer.FullName – FullName is a varchar colum
WHEN ‘Category‘ THEN Customer.Category – Category is a char column
END ASC, CASE @OrderBy –finally the float data and non-int numeric columns
WHEN ‘Rating‘ THEN Customer.Rating – Rating is a float column
END ASC
Note that you can change the sort order (ASC,DESC) for each CASE statement. Also, don’t forget the comma after each statement.
Another approach you can “upconvert” everything to varchar like so:
DECLARE @OrderBy varchar (50)
SELECT * FROM Customer
ORDER BY
CASE @OrderBy
WHEN ‘CustomerID‘ THEN CONVERT (varchar, Customer.CustomerID)
WHEN ‘MemberSince‘ THEN CONVERT (varchar, Customer.MemberSince)
WHEN ‘FullName‘ THEN CONVERT (varchar, Customer.FullName)
WHEN ‘Category‘ THEN CONVERT (varchar, Customer.Category)
WHEN ‘Rating‘ THEN CONVERT (varchar, Customer.Rating)
END ASC
You can find a discussion of these topics at http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=5…
This discussion has been running for almost six years which must be some kind of record. This post is meant to give a short gist of it.
Recent Comments