Along with JNK's answer, you could also consider:
DECLARE @Example TABLE
(
first_name NVARCHAR(50) NOT NULL,
last_name NVARCHAR(50) NOT NULL,
cert_end_date DATE NOT NULL,
other_columns NCHAR(100) NOT NULL DEFAULT (N'')
UNIQUE (cert_end_date ASC, first_name, last_name),
UNIQUE (cert_end_date DESC, first_name, last_name)
)
INSERT @Example
(first_name, last_name, cert_end_date)
VALUES
('a', 'w', '2008-12-31'),
('b', 'x', '2009-12-31'),
('c', 'y', '2010-12-31'),
('d', 'z', '2011-12-31')
DECLARE
@order_date_ascending BIT = CONVERT(BIT, 'true')
-- 1. May require an explicit sort despite useful indexes
SELECT
e.first_name,
e.last_name,
e.cert_end_date
FROM @Example AS e
ORDER BY
CASE WHEN @order_date_ascending = 1 THEN e.cert_end_date END ASC,
CASE WHEN @order_date_ascending = 0 THEN e.cert_end_date END DESC,
e.first_name ASC,
e.last_name ASC
-- 2. Conditional statements
IF @order_date_ascending = CONVERT(BIT, 'true')
BEGIN
SELECT
e.first_name,
e.last_name,
e.cert_end_date
FROM @Example AS e
ORDER BY
e.cert_end_date ASC,
e.first_name ASC,
e.last_name ASC
END
ELSE IF @order_date_ascending = CONVERT(BIT, 'false')
BEGIN
SELECT
e.first_name,
e.last_name,
e.cert_end_date
FROM @Example AS e
ORDER BY
e.cert_end_date DESC,
e.first_name ASC,
e.last_name ASC
END
-- 3. Union All & Start-up Filters
SELECT * FROM
(
SELECT TOP (9223372036854775807)
e.first_name,
e.last_name,
e.cert_end_date
FROM @Example AS e
WHERE
@order_date_ascending = CONVERT(BIT, 'true')
ORDER BY
e.cert_end_date ASC,
e.first_name ASC,
e.last_name ASC
) AS sort_asc
UNION ALL
SELECT * FROM
(
SELECT TOP (9223372036854775807)
e.first_name,
e.last_name,
e.cert_end_date
FROM @Example AS e
WHERE
@order_date_ascending = CONVERT(BIT, 'false')
ORDER BY
e.cert_end_date DESC,
e.first_name ASC,
e.last_name ASC
) AS sort_desc
The first and third methods can benefit from the Parameter Embedding Optimization available on SQL Server 2008 SP1 CU5 if a statement-level compilation occurs, or is forced to occur using the OPTION (RECOMPILE)
query hint. See this MSDN blog entry for details.
The third method does not require a compilation each time, since the Filter operators in the plan have a Start-Up Expression. The plan sub-tree below each Filter is only executed if the condition evaluates to true.