2014-07-16 13 views
1

У меня есть хранимая процедура, которая будет принимать 2 разных параметра. Первый параметр определяет, какой столбец я хочу, чтобы отсортировать дальше, второй параметр будет определять, является ли он ASC или DESCSQL-код с двумя условиями

Create Procedure Some_SP 
    @sortcolumn varchar(10) 
    @sortorder varchar(10) 
AS 
    Select * from empTable 
    Order by 
     CASE @sortcolumn WHEN 'First_Name' THEN fname END, 
     CASE @sortcolumn WHEN 'Last_Name' THEN lname END, 
     CASE @sortcolumn WHEN 'ID' THEN empID END, 
     CASE @sortorder WHEN 'ascending' THEN ASC END, 
     CASE @sortorder WHEN 'descending' THEN DESC END 

Это дает мне синтаксическую ошибку. Как я могу исправить это, чтобы у меня могло быть 2 условия в моем заявлении CASE?

+0

Я бы сделал это с динамическим SQL я думаю ... –

+1

@TonyHopkinson я не был 't разрешено использовать динамический SQL, это часть нашего контрактного соглашения с клиентом. –

+0

Невозможно понять, почему в этом случае неправильные аргументы, SP будет падать на его задницу в любом случае. –

ответ

5

Ниже будет работать:

Select * from empTable 
Order by 
CASE WHEN @sortcolumn = 'First_Name' AND @SortOrder = 'ascending' THEN fname END ASC, 
CASE WHEN @sortcolumn = 'First_Name' AND @SortOrder = 'descending' THEN fname END DESC 

и т.д ...

Для того, чтобы не вводить каждый из этих утверждений дела вручную, вы могли бы написать «генератор» сценарий, который используется для создания это (особенно хорошо, если определение таблицы изменится):

SELECT 
    'CASE WHEN @SortColumn = ''' + C.name + ''' AND @SortOrder = ''ascending'' THEN ' + C.name + ' END ASC,' + CHAR(13) + CHAR(10) + 
    'CASE WHEN @SortColumn = ''' + C.name + ''' AND @SortOrder = ''descending'' THEN ' + C.name + ' END DESC,' 
FROM sys.columns C 
WHERE C.object_id = object_id('[Schema].[Table]') 
+0

Есть много etcetraing там :( –

+0

Означает ли это, если у меня есть 5 разных вариантов «столбцов», у меня будет 10 случаев? –

+0

@Tony Да, но, как вы сказали в своем комментарии к OP, Dynamic SQL был бы лучшим путем.Если это то, чего нужно избегать, вот как я это сделаю. – Jon

2

Если вы хотите, чтобы избежать динамического SQL и используя 2x ваши условия, вы можете использовать row_number

например:

declare @t table (string varchar(50), number int) 

insert @t values ('a',9),('f',2),('c',1) 

declare 
    @sc varchar(10) = 'number', -- or 'string', etc 
    @so varchar(10) = 'desc' -- or 'asc' 

select * 
from 
(
    select 
     *, 
     case @sc when 'string' then ROW_NUMBER() over (order by string) 
       when 'number' then ROW_NUMBER() over (order by number) 
     end rn 
    from @t 
) v 
order by 
case @so when 'desc' then -rn else rn end 
+0

Этот метод, хотя и интересен, обладает огромной производительностью если задействовано несколько столбцов. В конечном счете, вам лучше использовать sys.columns для генерации моего скрипта, если вам действительно нужно избегать использования динамического SQL. Мой метод был примерно в 24 раза более эффективен для таблицы с 50 столбцами, чем этот метод. – Jon

1

Вы можете просто скопировать и вставить и запустить это. Я ненавижу динамический SQL, не делайте этого.

К сожалению, вам придется дублировать запрос .... но он решает вашу конкретную проблему.

DECLARE 
    @sortcolumn varchar(10), 
    @sortorder varchar(10) 

SET @sortcolumn = 'fname' 
SET @sortorder = 'DESC' 

DECLARE 
    @Data TABLE 
     (
     fname nvarchar(10), 
     lname nvarchar(10), 
     empID int 
     ) 
INSERT INTO @Data VALUES ('BBB', 'BBB', 2) 
INSERT INTO @Data VALUES ('AAA', 'AAA', 1) 


IF @sortorder = 'DESC' BEGIN 

    SELECT 
     * 
    FROM 
     @Data 
    ORDER BY 
     CASE 
      WHEN @sortcolumn = 'fname' THEN fname 
      WHEN @sortcolumn = 'lname' THEN lname 
     END 
     DESC 

END ELSE BEGIN 

    SELECT 
     * 
    FROM 
     @Data 
    ORDER BY 
     CASE 
      WHEN @sortcolumn = 'fname' THEN fname 
      WHEN @sortcolumn = 'lname' THEN lname 
     END 

END 
1

Изменение ответ Джона в довершение ORDER BY список на только 2 вместо 2 * #columns

SELECT * 
FROM MyTable 
CROSS APPLY (VALUES 
    ('First_Name',fname), 
    ('Last_Name' ,lname), 
    ('Id'  ,ID ) 
) sort(SortColumn, SortValue) 
WHERE SortColumn = @SortColumn 
ORDER BY 
    CASE @SortOrder WHEN 'ascending' THEN SortValue END ASC, 
    CASE @SortOrder WHEN 'descending' THEN SortValue END DESC 
+0

Интересная идея, однако, эффективность удара для креста применима, возможно, не останется незамеченной. Я попробовал это на столе с 50 столбцами (все из которых были отсортированы - вы могли бы улучшить это, имея меньше столбцов для сортировки), и просто глядя на производительность партии, этот метод составлял 75% от стоимости, 25%. Применение креста добавляет узел «постоянного сканирования» в план выполнения запроса, дополнительное внутреннее соединение и дополнительный фильтр. Стоимость моего запроса почти полностью зависит от того, что сканирование таблицы/индекса происходит и сортировка. – Jon

Смежные вопросы