1

私は2つのパラメータを渡しています:

@Column と @Direction、どちらも nvarchar(50) です

パラメータ内の値から選択クエリの順序を変更したい。

例えば、

if @Column = Name and @Direction = 'Desc' then order by Name desc
if @Column = Name and @Direction = 'Asc'  then order by Name asc
if @Column = Type and @Direction = 'Desc' then order by Type desc
if @Column = Type and @Direction = 'Asc'  then order by Type asc

私のテーブルは Cars と呼ばれています。

CarId、Name、Type の 3 つの列があります。

これを実行しようとしましたが、正しい結果が返されません (order by が無視されたかのように)

select * from Cars
order by        
case 
when @SortColumn = 'Type' and @SortDir = 'Desc' then 1
when @SortColumn = 'Type' and @SortDir = 'Desc' then 1
when @SortColumn = 'Name' and @SortDir = 'Asc'  then 3
when @SortColumn = 'Name' and @SortDir = 'Asc'  then 3, end asc
4

2 に答える 2

1

このアプローチを試すことができます:

WITH ranked AS (
  SELECT
    ...
    rnk = ROW_NUMBER() OVER (
      ORDER BY
        CASE @SortColumn
          WHEN 'Type' THEN Type
          WHEN 'Name' THEN Name
        END
    ) * CASE @Direction WHEN 'DESC' THEN -1 ELSE 1 END
  FROM ...
)
SELECT
  ...
FROM ranked
ORDER BY rnk

この関数は、パラメーターでROW_NUMBER()指定された列でランキングを生成し、 @Aaron Bertrand の answer のように CASE 式を使用して名前を解決します。別の CASE 式を使用して、ランキングにif isを掛けて順序を元に戻します。結果のランク列は、調整なしでメイン クエリの句で使用する準備ができています。@SortColumn-1@Direction'DESC'ORDER BY

于 2012-07-03T21:35:14.367 に答える
1

CASE単一の値を生成する式です。他の言語で行ったり、 で試したりするようなフローの制御には使用できませんIFIFクエリ内でも使用できません。

以下では、各条件を個別に扱います。条件が一致しない場合、その式の結果は NULL になり、どの順序でも無視されます。したがって、すべての条件が真である句のみが観察されるため、これらの句の順序は関係ありません。

ORDER BY 
  CASE WHEN @SortColumn = 'Type' AND @SortDir = 'DESC' THEN Type END DESC,
  CASE WHEN @SortColumn = 'Name' AND @SortDir = 'DESC' THEN Name END DESC,
  CASE WHEN @SortColumn = 'Type' AND @SortDir = 'ASC'  THEN Type END,
  CASE WHEN @SortColumn = 'Name' AND @SortDir = 'ASC'  THEN Name END;

これらはおそらくある程度組み合わせることができますが、データ型がわからないので、これがおそらく最も安全です。データ型が同じ場合は、次のようになります。

ORDER BY 
  CASE WHEN @SortDir = 'DESC' THEN 
    CASE WHEN @SortColumn = 'Type' THEN Type ELSE Name END 
  END DESC,
  CASE WHEN @SortDir = 'ASC' THEN
    CASE WHEN @SortColumn = 'Type' THEN Type ELSE Name END
  END;

ASC条件付き対DESC1 つの式で実行できないため、これ以上折りたたむことはできません。ただし、他の方法で単純化することもできます。たとえば、次のクエリは上記と同じ結果をもたらしますが、場合によっては order by が実行しようとします (たとえば) ORDER BY Type DESC, Type DESC- オプティマイザーがそれを冗長として単純化するかどうかは 100% わかりませんただし、単一の並べ替え演算子に折りたたむ必要があります (必要な場合 - このクエリは、クエリを満たすために使用されるインデックスに基づいて固有の並べ替えを生成する場合があります)。

ORDER BY 
  CASE WHEN @SortColumn = 'Type' AND @SortDir = 'DESC' THEN Type END DESC,
  CASE WHEN @SortColumn = 'Name' AND @SortDir = 'DESC' THEN Name END DESC,
  CASE WHEN @SortColumn = 'Type' THEN Type END,
  CASE WHEN @SortColumn = 'Name' THEN Name END;

...また...

ORDER BY 
  CASE WHEN @SortDir = 'DESC' THEN 
    CASE WHEN @SortColumn = 'Type' THEN Type ELSE Name END 
  END DESC,
  CASE WHEN @SortColumn = 'Type' THEN Type ELSE Name END;

動的 SQL を検討することもできます。これがさらに複雑になると、ここで多くのメンテナンスが必要になるからです。

DECLARE @sql NVARCHAR(MAX);
SET @sql = N'SELECT ... ORDER BY ' + @SortColumn + ' ' + @SortDir;
PRINT @sql;
-- EXEC sp_executesql @sql;

もちろん、これにより他の問題が発生する可能性があります (残りのクエリの保守性、プラン キャッシュの肥大化など)。

于 2012-07-03T18:00:06.920 に答える