'where'句のSQLスイッチ/ケース


146

あちこち探してみたが、助けになるものが見つからなかった。

私はこれをSQLでやろうとしています:

declare @locationType varchar(50);
declare @locationID int;

SELECT column1, column2
FROM viewWhatever
WHERE
CASE @locationType
    WHEN 'location' THEN account_location = @locationID
    WHEN 'area' THEN xxx_location_area = @locationID
    WHEN 'division' THEN xxx_location_division = @locationID

それぞれの末尾に '= @locationID'を付ける必要がないことはわかっていますが、構文が正しくても正確に取得できません。SQLは最初のWHEN行の '='について文句を言い続けます...

これどうやってするの?

回答:


191
declare @locationType varchar(50);
declare @locationID int;

SELECT column1, column2
FROM viewWhatever
WHERE
@locationID = 
  CASE @locationType
      WHEN 'location' THEN account_location
      WHEN 'area' THEN xxx_location_area 
      WHEN 'division' THEN xxx_location_division 
  END

1
TomHが以下の返信へのコメントで指摘しているように、SQLの形式が正しくありません。私はSQLServer 2005でテストしましたが、問題なく動作しました。
Bob Probst、

@が必要なのはなぜですか?彼らは何をしますか?
Tadej

2
@はt-sqlの変数を示します。@がない場合、@ locationIDは列名として解釈されます。
クリスチャンスローパー2018年

70

ケースステートメントなし...

SELECT column1, column2
FROM viewWhatever
WHERE
    (@locationType = 'location' AND account_location = @locationID)
    OR
    (@locationType = 'area' AND xxx_location_area = @locationID)
    OR
    (@locationType = 'division' AND xxx_location_division = @locationID)

2
しかし、OR構文あらゆる可能性を評価します-条件が満たされた後、これは、Caseステートメントの終了とわずかに異なる結果を与えるです
tember

1
@tember SQLが手続き型言語であっても、最初のORがtrueの場合、式の残りの部分は評価されません。SQLは宣言型言語なので、DBMがすべてのORを評価することをどのようにして知っていますか?誠実な質問、わかりません。
ArturoTena 2015年

SQLでは、式の残りの部分はOR構文で評価されます。これを試してください(@記号を含めることはできません-テストしたい場合は修正する必要があります):declare var varchar(5)set var = '0' select 2 / var where var <> 0またはISNUMERIC(var)= 1。var ISが0に等しいので条件を終了したいのですが、それが数値であるかどうかをチェックします。つまり、数値であるため、ステートメントはエラーを返します。
2015年

これは、型の値ごとに異なる比較演算子があった私の場合に役立ちました。
Alex

さらに良い DECLARE @locationType NVARCHAR(50) = 'youchoose' IF @locationType = 'location' BEGIN SELECT column1, column2 FROM viewWhatever WHERE (account_location = @locationID) END IF @locationType = 'area' BEGIN SELECT column1, column2 FROM viewWhatever WHERE (xxx_location_area = @locationID) END IF @locationType = 'division' BEGIN SELECT column1, column2 FROM viewWhatever WHERE (xxx_location_division = @locationID) END
ルーク

35

どうぞ。

SELECT
   column1, 
   column2
FROM
   viewWhatever
WHERE
CASE 
    WHEN @locationType = 'location' AND account_location = @locationID THEN 1
    WHEN @locationType = 'area' AND xxx_location_area = @locationID THEN 1
    WHEN @locationType = 'division' AND xxx_location_division = @locationID THEN 1
    ELSE 0
END = 1

5
まあ、私はそれをSELECT column1、column2 FROM viewWhatever WHERE(@locationType = 'location' AND account_location = @locationID)OR(@locationType = 'area' AND xxx_location_area = @locationID)OR(@locationType = 'division' AND xxx_location_division = @locationID)
Jan de Vos

2
これはすばらしい例の平和です。最も良い回答済みのクエリ実行プランはどうですか(個人的には、このメソッドコードは明確でクリーンであることが望ましいです)
PEO

1
1番目の句にint、2番目にnvarcharのように、異なる型の異なるwhere句を使用する場合は、本当に素晴らしいです。Bob Probstソリューションでは機能しません。感謝
Julian50

6

これは、テーブル構造に欠陥があることを示すものだと思います。おそらく、さまざまな場所のタイプをさまざまなテーブルに分けて、より豊富なクエリを実行できるようにし、余分な列を配置しないようにする必要があります。

構造を変更できない場合は、次のようなものが機能する可能性があります。

SELECT
    *
FROM
    Test
WHERE
    Account_Location = (
        CASE LocationType
          WHEN 'location' THEN @locationID
          ELSE Account_Location
        END
    )
    AND
    Account_Location_Area = (
        CASE LocationType
          WHEN 'area' THEN @locationID
          ELSE Account_Location_Area
        END
    )

など...クエリの構造をその場で変更することはできませんが、述語を同じにすることでオーバーライドできます。

編集:上記の提案はもちろんはるかに優れています、私のものを無視してください。


これは欠陥のあるテーブル構造ではないと思います。テーブルはこのように設定されたため、親子関係が無限にあるのは自己参照でした。私を信じて、それは意図的でした。switchステートメントだけを使用するようにテーブル構造を変更したくないと思います。そのntoが重要
マイル

5

この問題は、SQLエンジンが式を評価するときに、FROM部分をチェックして適切なテーブルをプルし、次にWHERE部分でいくつかの基本条件を提供するため、どの列の動的条件を適切に評価できないかです。チェックしてください。

次のように、述語のWHERE条件をチェックするときにWHERE句を使用できます。

WHERE account_location = CASE @locationType
                              WHEN 'business' THEN 45
                              WHEN 'area' THEN 52
                         END

したがって、特定のケースでは、クエリをストアドプロシージャに入れるか、3つの個別のクエリを作成する必要があります。


5

OR演算子は、where条件の場合、大文字小文字の代わりになることができます

ALTER PROCEDURE [dbo].[RPT_340bClinicDrugInventorySummary]
    -- Add the parameters for the stored procedure here
     @ClinicId BIGINT = 0,
     @selecttype int,
     @selectedValue varchar (50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT
    drugstock_drugname.n_cur_bal,drugname.cdrugname,clinic.cclinicname

FROM drugstock_drugname
INNER JOIN drugname ON drugstock_drugname.drugnameid_FK = drugname.drugnameid_PK
INNER JOIN drugstock_drugndc ON drugname.drugnameid_PK = drugstock_drugndc.drugnameid_FK
INNER JOIN drugndc ON drugstock_drugndc.drugndcid_FK = drugndc.drugid_PK
LEFT JOIN clinic ON drugstock_drugname.clinicid_FK = clinic.clinicid_PK

WHERE   (@ClinicId = 0 AND 1 = 1)
    OR  (@ClinicId != 0 AND drugstock_drugname.clinicid_FK = @ClinicId)

    -- Alternative Case When You can use OR
    AND ((@selecttype = 1 AND 1 = 1)
    OR  (@selecttype = 2 AND drugname.drugnameid_PK = @selectedValue)
    OR  (@selecttype = 3 AND drugndc.drugid_PK = @selectedValue)
    OR  (@selecttype = 4 AND drugname.cdrugclass = 'C2')
    OR  (@selecttype = 5 AND LEFT(drugname.cdrugclass, 1) = 'C'))

ORDER BY clinic.cclinicname, drugname.cdrugname
END

3

このクエリを試してください。上記の投稿への回答:

select @msgID, account_id
    from viewMailAccountsHeirachy
    where 
    CASE @smartLocationType
        WHEN 'store' THEN account_location
        WHEN 'area' THEN xxx_location_area 
        WHEN 'division' THEN xxx_location_division 
        WHEN 'company' THEN xxx_location_company 
    END  = @smartLocation

2
将来これを読む人には:上記の@ bob-
prost

2

これを試して:

WHERE (
    @smartLocationType IS NULL 
    OR account_location = (
         CASE
            WHEN @smartLocationType IS NOT NULL 
                 THEN @smartLocationType
            ELSE account_location 
         END
    )
)

1
これが与えられた文字列(つまり、 'location'、 'area'、 'division')の間でどのように選択できるか理解していないため、反対票を投じました
ArturoTena

0
CREATE PROCEDURE [dbo].[Temp_Proc_Select_City]
    @StateId INT
AS  
        BEGIN       
            SELECT * FROM tbl_City 
                WHERE 
                @StateID = CASE WHEN ISNULL(@StateId,0) = 0 THEN 0 ELSE StateId END ORDER BY CityName
        END

-1
Case Statement in SQL Server Example

Syntax

CASE [ expression ]

   WHEN condition_1 THEN result_1
   WHEN condition_2 THEN result_2
   ...
   WHEN condition_n THEN result_n

   ELSE result

END

Example

SELECT contact_id,
CASE website_id
  WHEN 1 THEN 'TechOnTheNet.com'
  WHEN 2 THEN 'CheckYourMath.com'
  ELSE 'BigActivities.com'
END
FROM contacts;

OR

SELECT contact_id,
CASE
  WHEN website_id = 1 THEN 'TechOnTheNet.com'
  WHEN website_id = 2 THEN 'CheckYourMath.com'
  ELSE 'BigActivities.com'
END
FROM contacts;

4
この回答は質問に関連していないため、反対票が入りました。問題は、SELECTされた列でCASEを使用する方法ではなく、WHERE句でCASEを使用する方法でした。
ArturoTena 2015年

-2

このクエリを試してください。非常に理解しやすい:

CREATE TABLE PersonsDetail(FirstName nvarchar(20), LastName nvarchar(20), GenderID int);
GO

INSERT INTO PersonsDetail VALUES(N'Gourav', N'Bhatia', 2),
              (N'Ramesh', N'Kumar', 1),
              (N'Ram', N'Lal', 2),
              (N'Sunil', N'Kumar', 3),
              (N'Sunny', N'Sehgal', 1),
              (N'Malkeet', N'Shaoul', 3),
              (N'Jassy', N'Sohal', 2);
GO

SELECT FirstName, LastName, Gender =
    CASE GenderID
    WHEN 1 THEN 'Male'
    WHEN 2 THEN 'Female'
    ELSE 'Unknown'
    END
FROM PersonsDetail

1
この回答を読む人には、上記の@ bob- prost から受け入れられた回答と同じです。この理由により、stackoverflow.com / a / 206500/264786 Downvoted。
ArturoTena 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.