web-dev-qa-db-ja.com

T-SQL条件付きWHERE句

ここで同様の質問をいくつか見つけましたが、私のシナリオにどのように適用するかわかりませんでした。

私の関数には@ IncludeBelowというパラメーターがあります。値は0または1(BIT)です。

私はこのクエリを持っています:

SELECT p.*
FROM Locations l
INNER JOIN Posts p
on l.LocationId = p.LocationId
WHERE l.Condition1 = @Value1
AND   l.SomeOtherCondition = @SomeOtherValue

@IncludeBelowが0の場合、次のようなクエリが必要です。

SELECT p.*
FROM Locations l
INNER JOIN Posts p
on l.LocationId = p.LocationId
WHERE l.Condition1 = @Value1
AND   l.SomeOtherCondition = @SomeOtherValue
AND   p.LocationType = @LocationType -- additional filter to only include level.

@IncludeBelowが1の場合、その最後の行を除外する必要があります。 (つまり、フィルターを適用しません)。

CASEステートメントである必要があると思いますが、構文を理解できません。

これが私が試したものです:

SELECT p.*
FROM Locations l
INNER JOIN Posts p
on l.LocationId = p.LocationId
WHERE l.Condition1 = @Value1
AND   l.SomeOtherCondition = @SomeOtherValue
AND (CASE @IncludeBelow WHEN 0 THEN p.LocationTypeId = @LocationType ELSE 1 = 1)

明らかにそれは正しくありません。

正しい構文は何ですか?

28
RPM1984

EXISTSを使用するようにクエリを変更しました。POSTに関連付けられている場所が複数ある場合、重複したPOSTレコードが存在するため、DISTINCTまたはGROUP BY句を削除する必要があるためです。 ..

引数をとらない

これにより、考えられる最悪のソリューションが実行されます。

SELECT p.*
  FROM POSTS p
 WHERE EXISTS(SELECT NULL
                FROM LOCATIONS l
               WHERE l.LocationId = p.LocationId
                 AND l.Condition1 = @Value1
                 AND l.SomeOtherCondition = @SomeOtherValue)
   AND (@IncludeBelow = 1 OR p.LocationTypeId = @LocationType)

検索可能な非動的バージョン

自己説明...

BEGIN
  IF @IncludeBelow = 0 THEN
    SELECT p.*
      FROM POSTS p
     WHERE EXISTS(SELECT NULL
                    FROM LOCATIONS l
                   WHERE l.LocationId = p.LocationId
                     AND l.Condition1 = @Value1
                     AND l.SomeOtherCondition = @SomeOtherValue)
       AND p.LocationTypeId = @LocationType
  ELSE
    SELECT p.*
      FROM POSTS p
     WHERE EXISTS(SELECT NULL
                    FROM LOCATIONS l
                   WHERE l.LocationId = p.LocationId
                     AND l.Condition1 = @Value1
                     AND l.SomeOtherCondition = @SomeOtherValue) 
END

検索可能な動的バージョン(SQL Server 2005以降):

それが好きか嫌いか、動的SQLではクエリを1回だけ記述できます。 SQL ServerのEXECとは異なり、sp_executesqlはクエリプランをキャッシュすることに注意してください。 SQL Serverで動的SQLを検討する前に、 動的SQLの呪いと祝福 を読むことを強くお勧めします...

DECLARE @SQL VARCHAR(MAX)
    SET @SQL = 'SELECT p.*
                  FROM POSTS p
                 WHERE EXISTS(SELECT NULL
                                FROM LOCATIONS l
                               WHERE l.LocationId = p.LocationId
                                 AND l.Condition1 = @Value1
                                 AND l.SomeOtherCondition = @SomeOtherValue)'

    SET @SQL = @SQL + CASE 
                        WHEN @IncludeBelow = 0 THEN
                         ' AND p.LocationTypeId = @LocationType '
                        ELSE ''
                      END   

BEGIN 

  EXEC sp_executesql @SQL, 
                     N'@Value1 INT, @SomeOtherValue VARCHAR(40), @LocationType INT',
                     @Value1, @SomeOtherValue, @LocationType

END
38
OMG Ponies

あなたはそれを次のように書くことができます

SELECT  p.*
  FROM  Locations l
INNER JOIN Posts p
    ON  l.LocationId = p.LocationId
  WHERE l.Condition1 = @Value1
    AND l.SomeOtherCondition = @SomeOtherValue
    AND ((@IncludeBelow = 1) OR (p.LocationTypeId = @LocationType))

これはよく目にするパターンです。オプションの検索パラメータ用。しかし、IIRCはクエリ実行プランを混乱させる可能性があるため、これを行うためのより良い方法があるかもしれません。

これはほんの少しだけなので、チェックの有無にかかわらず、SQLの2つのブロック間で決定する価値があるかもしれません。ストアドプロシージャでIFを使用したり、ビットに基づいて呼び出しコードで異なるコマンド文字列を使用したりしますか?

11
Rup

CASEステートメントをこれに変更できます。クエリプランナーはこれを別の方法で認識しますが、ORを使用するよりも効率的ではありません。

(p.LocationTypeId = CASE @IncludeBelow WHEN 0 THEN p.LocationTypeId ELSE @LocationType END)
3
Hai Phan

次のようにsqlステートメントを編集します。

SELECT p.*
FROM Locations l
    INNER JOIN Posts p
    on l.LocationId = p.LocationId
WHERE l.Condition1 = @Value1
    AND l.SomeOtherCondition = @SomeOtherValue
    AND l.LocationType like @LocationType

@IncludeBelow変数は必要ありません

すべての場所の種類を含めるには、@ LocationType = '%'を設定します。

クエリによって返される場所の種類を制限するにはSet @LocationType = '[A Specific Location Type]'

上記のSetステートメントは、@ LocationType変数が文字データ型であることを前提としています

0
Rich Capp