SQL:WHERE句内のIF句


203

MS SQLのWHERE句内でIF句を使用することは可能ですか?

例:

WHERE
    IF IsNumeric(@OrderNumber) = 1
        OrderNumber = @OrderNumber
    ELSE
        OrderNumber LIKE '%' + @OrderNumber + '%'

回答:


212

CASEステートメント
UPDATEを使用します。以前の構文(数人が指摘したとおり)は機能しません。CASEは次のように使用できます。

WHERE OrderNumber LIKE
  CASE WHEN IsNumeric(@OrderNumber) = 1 THEN 
    @OrderNumber 
  ELSE
    '%' + @OrderNumber
  END

または、@ NJ Reedが指摘するようなIFステートメントを使用できます。


[作成者によるUPDATE後の注意]:これは機能しますが、一致が見つかるように両側をTRIM()する必要があります。一致しない稀なケースがまだあるという直感があります。
ユーロミセリ2008

1
CASEほとんどの場合、を使用するのが適切なソリューションです。私の場合、比較演算子を変更したかったので、次のアプローチを使用しました。
Birla、2014年

142

IFまたはCASEなしでこれを実行できるはずです。

 WHERE 
   (IsNumeric(@OrderNumber) AND
      (CAST OrderNumber AS VARCHAR) = (CAST @OrderNumber AS VARCHAR)
 OR
   (NOT IsNumeric(@OrderNumber) AND
       OrderNumber LIKE ('%' + @OrderNumber))

SQLの種類によっては、暗黙的キャストがサポートされているかどうかに応じて、注文番号のキャストをINTまたはVARCHARに微調整する必要がある場合があります。

これは、WHERE句で非常に一般的な手法です。WHERE句に「IF」ロジックを適用する場合は、適用する必要のあるセクションにブールANDを使用して条件を追加するだけです。


2
CASEソリューションよりもパフォーマンスが少し低下すると思いますが、これらすべての条件が評価されるため、違いますか?
ケビンフェアチャイルド

SQLでは、条件付きステートメントをそのようなブール論理で置き換えることができることをいつも忘れています。リマインダーをありがとう、それは非常に便利なテクニックです!
CodexArcanum

1
SQLサーバーがブールロジックを処理する方法により、このソリューションは実際には最良のソリューションです。where句のCASEステートメントは、最初のチェックが失敗した場合、SQLは行の処理を停止して続行するため、ブール値の場合よりも効率が悪くなります。これにより、処理時間を節約できます。また、ブール値チェックの反対側には常に、よりコストのかかるステートメントを入れてください。
Steve

非常にエレガントな解決策をありがとう。人々に役立つかもしれないあなたが使った方法に関するチュートリアルを見つけました。 weblogs.sqlteam.com/jeffs/archive/2003/11/14/513.aspx
Rich

1
@Kashあなたが提供したリンクは登録して読むものですが、あなたが言っていることを説明する公開されているドキュメントはありますか?
Steve

29

IFステートメントはまったく必要ありません。

WHERE
    (IsNumeric(@OrderNumber) = 1 AND OrderNumber = @OrderNumber)
OR (IsNumeric(@OrderNumber) = 0 AND OrderNumber LIKE '%' + @OrderNumber + '%')

2
私はこのアプローチが本当に好きです。代替使用:AdmUseIdに値がある場合where (@AdmUserId is null or CurrentOrder.CustomerAdmUserId = @AdmUserId) のみフィルター:またはIncludeDeleted = 0の場合のみフィルター: where (@IncludeDeleted = 1 or ItemObject.DeletedFlag = 0)
Kasper Halvas Jensen

これは、WHERE句内でINフィルターを使用する場合にうまく機能します。COALESCEを使用する必要があり、読みにくいので、CASEでこれを行うとめちゃくちゃになりますが、これは読みやすいロジックです。NOT INまたはINフィルターのWHERE句のTSQL CASEステートメント
pholcroft

14

SQLでこれを行う良い方法はありません。私が見たいくつかのアプローチ:

1)CASEとブール演算子を組み合わせて使用​​します。

WHERE
    OrderNumber = CASE 
        WHEN (IsNumeric(@OrderNumber) = 1)
        THEN CONVERT(INT, @OrderNumber)
        ELSE -9999 -- Some numeric value that just cannot exist in the column
    END
    OR 
    FirstName LIKE CASE
        WHEN (IsNumeric(@OrderNumber) = 0)
        THEN '%' + @OrderNumber
        ELSE ''
    END

2)SELECTの外でIFを使用する

IF (IsNumeric(@OrderNumber)) = 1
BEGIN
    SELECT * FROM Table
    WHERE @OrderNumber = OrderNumber
END ELSE BEGIN
    SELECT * FROM Table
    WHERE OrderNumber LIKE '%' + @OrderNumber
END

3)長い文字列を使用して、SQLステートメントを条件付きで作成し、EXECを使用します

3番目のアプローチは恐ろしいですが、そのような多数の可変条件がある場合に機能するのは、ほぼ唯一の考え方です。


4番目のアプローチは、上記の@ njr101の回答のように、すべてのIF...ELSE...条件文をブール値ANDのとに変換することORです。短所^このアプローチは、多数IFのがある場合、または多数のがネストされている場合、頭を痛めるほど難しい場合がある
Don Cheadle



3

私は、... like / = ... case ... then ... then ...がBooleansで機能できると思います。T-SQLを使用しています。

シナリオ:boolがfalseの場合はPerson-30の趣味を取得し、boolがtrueの場合はPerson-42の趣味を取得するとします。(一部によると、趣味ルックアップはビジネス計算サイクルの90%以上を占めるため、細心の注意を払ってください。)

CREATE PROCEDURE sp_Case
@bool   bit
AS
SELECT Person.Hobbies
FROM Person
WHERE Person.ID = 
    case @bool 
        when 0 
            then 30
        when 1
            then 42
    end;

2
WHERE(IsNumeric(@OrderNumber)<> 1 OR OrderNumber = @OrderNumber) 
             AND(IsNumber(@OrderNumber)= 1 OR OrderNumber LIKE '%' 
                                              + @OrderNumber + '%')

連言正規形書き換え規則:IF P THEN Q ELSE R <=> ( ( NOT P ) OR Q ) AND ( P OR R )
16

1

CASEステートメントは、常にIFよりも優れたオプションです。

  WHERE  vfl.CreatedDate >= CASE WHEN @FromDate IS NULL THEN vfl.CreatedDate ELSE  @FromDate END
    AND vfl.CreatedDate<=CASE WHEN @ToDate IS NULL THEN vfl.CreatedDate ELSE @ToDate END 

1
    WHERE OrderNumber LIKE CASE WHEN IsNumeric(@OrderNumber) = 1 THEN @OrderNumber ELSE  '%' + @OrderNumber END

ラインの場合、条件は適切に機能します。


0

次の例では、ブール式の一部としてクエリを実行し、ブール式の結果に基づいてわずかに異なるステートメントブロックを実行します。各ステートメントブロックはBEGINで始まり、ENDで終わります。

USE AdventureWorks2012;
GO
DECLARE @AvgWeight decimal(8,2), @BikeCount int
IF 
(SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
BEGIN
   SET @BikeCount = 
        (SELECT COUNT(*) 
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%');
   SET @AvgWeight = 
        (SELECT AVG(Weight) 
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%');
   PRINT 'There are ' + CAST(@BikeCount AS varchar(3)) + ' Touring-3000 bikes.'
   PRINT 'The average weight of the top 5 Touring-3000 bikes is ' + CAST(@AvgWeight AS varchar(8)) + '.';
END
ELSE 
BEGIN
SET @AvgWeight = 
        (SELECT AVG(Weight)
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%' );
   PRINT 'Average weight of the Touring-3000 bikes is ' + CAST(@AvgWeight AS varchar(8)) + '.' ;
END ;
GO

ネストされたIF ... ELSEステートメントの使用次の例は、IF…ELSEステートメントを別のステートメント内にネストする方法を示しています。@Number変数を5、50、および500に設定して、各ステートメントをテストします。

DECLARE @Number int
SET @Number = 50
IF @Number > 100
   PRINT 'The number is large.'
ELSE 
   BEGIN
      IF @Number < 10
      PRINT 'The number is small'
   ELSE
      PRINT 'The number is medium'
   END ;
GO

2
これは関連がないようです。WHERE句でIF(または条件コード)を使用しません。
Vince Bowdren 2013

0

SQLサーバーでは同じ問題がありましたが、パラメーターがfalseの場合にのみandステートメントを使用し、trueの場合はtrueとfalseの両方の値を表示する必要があるため、このように使用しました

(T.IsPublic = @ShowPublic or  @ShowPublic = 1)

-1
If @LstTransDt is Null
                begin
                    Set @OpenQty=0
                end
            else
                begin
                   Select   @OpenQty=IsNull(Sum(ClosingQty),0)  
                   From  ProductAndDepotWiseMonitoring  
                   Where   Pcd=@PCd And PtpCd=@PTpCd And TransDt=@LstTransDt      
                end 

これが役立つかどうかを確認します。


-6
USE AdventureWorks2012;
GO
IF 
(SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
PRINT 'There are more than 5 Touring-3000 bicycles.'
ELSE PRINT 'There are 5 or less Touring-3000 bicycles.' ;
GO

これは関連がないようです。WHERE句でIF(または条件コード)を使用しません。
Vince Bowdren 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.