14

OK、条件付き列の第 1 番目の質問:

いくつかのフラグ列の 1 つにマップされた入力パラメーターを受け取るストアド プロシージャを作成しています。要求された列をフィルタリングする最良の方法は何ですか? 私は現在 SQL2000 を使用していますが、SQL2008 に移行しようとしているので、最新のソリューションが利用可能であれば採用します。

sproc でクエリされたテーブルは次のようになります

ID ...  fooFlag  barFlag  bazFlag  quuxFlag
--      -------  -------  -------  --------
01         1        0       0          1
02         0        1       0          0
03         0        0       1          1
04         1        0       0          0

そして、私は次のようなことをしたい

select ID, name, description, ...
from myTable
where (colname like @flag + 'Flag') = 1

したがって、sproc を呼び出すと、exec uspMyProc @flag = 'foo'行 1 と 4 が返されます。

括弧内の部分を SQL で直接実行できないことはわかっています。動的 SQL を実行するには、クエリ全体を文字列に詰め込み、WHERE 句で @flag パラメータを連結してから、文字列を実行する必要があります。動的 SQL を実行しているときに得られる汚れた感覚は別として、私のクエリはかなり大きい (数十のフィールドを選択し、5 つのテーブルを結合し、いくつかの関数を呼び出している) ため、すべてが 1 行であるため、非常に巨大な文字列になります。 3 行の WHERE フィルターで。

または、クエリのコピーを 4 つ用意し、CASE ステートメントでそれらの中から選択することもできます。これにより、SQL コードはそのまま実行可能になります (構文の強調表示などの対象となります) が、WHERE 句だけで CASE を使用できないため、大量のコードを繰り返すという犠牲が伴います。

他のオプションはありますか?適用できるトリッキーな結合や論理演算はありますか? それとも、それを乗り越えて動的 SQL を実行する必要がありますか?

4

6 に答える 6

21

これを行うにはいくつかの方法があります。

これは、case ステートメントで行うことができます。

select ID, name, description, ...
from myTable
where CASE
    WHEN @flag = 'foo' then fooFlag
    WHEN @flag = 'bar' then barFlag
END = 1

IF を使用できます。

IF (@flag = 'foo') BEGIN
    select ID, name, description, ...
    from myTable
    where fooFlag = 1
END ELSE IF (@flag = 'bar') BEGIN
    select ID, name, description, ...
    from myTable
    where barFlag = 1
END

....

多くの括弧を含む複雑な where 句を使用できます。

select ID, name, description, ...
from myTable
where (@flag = 'foo' and fooFlag = 1)
OR (@flag = 'bar' and barFlag = 1) OR ...

動的SQLでこれを行うことができます:

DECLARE @SQL nvarchar(4000)

SELECT @SQL = N'select ID, name, description, ...
from myTable
where (colname like ''' + @flag + 'Flag'') = 1'

EXECUTE sp_ExecuteSQL @SQL, N''

他にもありますが、そのうちの1つがあなたを動かすと思います。

于 2009-12-30T03:02:48.957 に答える
4

私がすることはCASE最初にいくつかの変数です。例:

DECLARE
    @fooFlag int,
    @barFlag int,
    @bazFlag int,
    @quuxFlag int

SET @fooFlag = CASE WHEN @flag = 'foo' THEN 1 ELSE NULL END
SET @barFlag = CASE WHEN @flag = 'bar' THEN 1 ELSE NULL END
SET @bazFlag = CASE WHEN @flag = 'baz' THEN 1 ELSE NULL END
SET @quuxFlag = CASE WHEN @flag = 'quux' THEN 1 ELSE NULL END

SELECT ID, name, description, ...
FROM myTable
WHERE (fooFlag >= ISNULL(@fooFlag, 0) AND fooFlag <= ISNULL(@fooFlag, 1))
AND (barFlag >= ISNULL(@barFlag, 0) AND barFlag <= ISNULL(@barFlag, 1))
AND (bazFlag >= ISNULL(@bazFlag, 0) AND bazFlag <= ISNULL(@bazFlag, 1))
AND (quuxFlag >= ISNULL(@quuxFlag, 0) AND quuxFlag <= ISNULL(@quuxFlag, 1))

このクエリの良いところは、「フラグ」の可能な値が制限されているため、列をラップする代わりに、すべての条件を前提条件として計算できることです。これにより、インデックスが作成された列での高性能インデックスシークが保証され、動的SQLを記述する必要がありません。そして、明らかな理由から、4つの別々のクエリを書くよりも優れています。

于 2009-12-30T03:06:06.613 に答える
1

可能なフラグ列ごとにパラメーターを設定し、パラメーターがnullであるか、列の値がパラメーターと等しいかどうかを確認できます。次に、チェックするフラグに1を渡し、他のフラグはnullのままにします。

select id, name, description, ...
from myTable
where (@fooFlag is null or fooFlag = @fooFlag) AND
      (@barFlag is null or barFlag = @barFlag) AND
      ...

ただし、正直なところ、これは動的LINQクエリを作成し、SQL2008に到達したらSPROCをスキップするための理想的な候補のようです。

于 2009-12-30T03:06:00.997 に答える
0
where
   case when @value<>0 then Field else 1 end
   =
   case when @value<>0 then @value else 1 end
于 2016-08-16T10:24:58.523 に答える