'Where' yan tümcesinde SQL Switch / Case


146

Etrafta arama yapmayı denedim, ama bana yardımcı olacak hiçbir şey bulamadım.

SQL'de bunu yapmaya çalışıyorum:

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

Ben her birinin sonuna '= @locationID' koymak zorunda gerektiğini biliyorum, ama sözdizimi doğru olmak yakın bile alamıyorum. SQL, ilk WHEN satırındaki '=' ile ilgili şikayet etmeye devam ediyor ...

Bunu nasıl yapabilirim?

Yanıtlar:


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'un aşağıdaki cevabınıza yaptığı açıklamada belirttiği gibi, SQL'i yanlış oluşturdunuz. SQLServer 2005'te benimkini test ettim ve işe yaradı.
Bob Probst

@ İçin neden gereklidir? Onlar ne yapar?
Tadej

2
@, @, @locationID değeri sütun adı olarak yorumlanmadan, t-sql'deki değişkenleri belirtir.
Christian Sloper

70

vaka bildirimi olmadan ...

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
Bu, bir koşul karşılandıktan sonra Case ifadesinin çıkmasıyla biraz farklı bir sonuç verecektir - ancak OR sözdizimi tüm olasılıkları değerlendirecektir
tember

1
@tember SQL yordamsal bir dil olsa bile, ilk OR doğruysa ifadenin geri kalanı değerlendirilmez. SQL bildirici bir dil olduğundan, DBM'nin tüm OR'leri değerlendireceğini nasıl anlarsınız? Samimi bir soru, anlamıyorum.
ArturoTena

SQL'de ifadenin geri kalanı OR sözdiziminde değerlendirilir. Bunu deneyin (@ sembolünü eklememe izin vermez - test etmek istiyorsanız düzeltmeniz gerekir): declare var varchar (5) set var = '0' select 2 / var burada var <> 0 veya ISNUMERIC (var) = 1. Var IS 0 eşittir, çünkü koşulu çıkmak istiyorum, ancak sayısal olup olmadığını denetlemek için devam ediyor ve bu nedenle ifade bir hata döndürür.
tember

bu benim durumumda türün her değeri için farklı bir karşılaştırma operatörü vardı yardımcı oldu.
Alex

daha iyi 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
Lukek

35

Hadi bakalım.

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
Peki, SELECT sütun1, sütun2 FROM viewWhatever WHERE (@locationType = 'location' AND account_location = @locationID) VEYA (@locationType = 'alan' VE xxx_location_area = @locationID) VEYA (@locationType = 'alan' VE AND xxx_location_division = @locationID)
Jan de Vos

2
Bu büyük bir barış örneğidir, en iyi Cevaplı yürütme planı hakkında ne dersiniz (şahsen ben bu yöntem kodunun açık ve temiz olmasını tercih ediyorum)
PEO

1
Eğer gerçekten 1. maddede int ve 2'de nvarchar gibi farklı türde yan tümce farklı kullanmak istiyorsanız harika. Bob Probst çözümü ile çalışmıyor. teşekkürler
Julian50

6

Bunun kusurlu bir masa yapısının bir göstergesi olduğunu söyleyebilirim. Belki de farklı konum türleri farklı tablolarda ayrılmalı, böylece daha zengin sorgulamalar yapmanıza ve etrafta gereksiz sütunlara sahip olmanıza engel olmalısınız.

Yapıyı değiştiremiyorsanız, aşağıdakine benzer bir şey işe yarayabilir:

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
    )

Ve böylece ... Sorgunun yapısını anında değiştiremeyiz, ancak tahminleri eşit kılarak bunu geçersiz kılabiliriz.

EDIT: Yukarıdaki öneriler elbette çok daha iyi, sadece benim göz ardı.


Bunun kusurlu bir masa yapısı olduğunu düşünmüyorum. Tablo, sonsuz sayıda ebeveyn / çocuk ilişkisi olması için kendi referansları olacak şekilde bu şekilde oluşturulmuştur. İnan bana, bilerek yapıldı. Tablo yapımı bir switch deyimi kullanmak için değiştirmek istediğimi sanmıyorum. bu önemli
Miles

5

Buradaki sorun, SQL motoru ifadeyi değerlendirmeye gittiğinde, uygun tabloları çekmek için FROM bölümünü ve daha sonra bazı temel kriterleri sağlamak için WHERE bölümünü kontrol etmesidir, bu nedenle hangi sütunun hangi dinamik karşı kontrol etmek.

Yüklemdeki WHERE ölçütlerini kontrol ederken bir WHERE yantümcesi kullanabilirsiniz.

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

bu nedenle, özel durumunuzda, sorguyu saklı bir yordama koymanız veya üç ayrı sorgu oluşturmanız gerekir.


5

VEYA operatörü, durumun olduğu durumlarda duruma alternatif olabilir

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

Lütfen bu sorguyu deneyin. Yukarıdaki gönderiye cevap:

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
Gelecekte bunu kim okursa: yukarıdaki @ bob-
prost'un

2

Bunu dene:

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

1
Bunun verilen dizeler arasında nasıl seçim yapabileceğini anlamadığım için (yani 'konum', 'alan', 'bölüm')
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
Bu cevaplayıcı soru ile ilgili olmadığı için indirildi. Soru, SEÇİLEN bir sütunda CASE'in nasıl kullanılacağı değil, WHERE yan tümcesinde CASE'in nasıl kullanılacağıydı.
ArturoTena

-2

Bu sorguyu deneyin. Anlaması çok kolay:

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
Bu yanıtı kim okuyorsa : yukarıdaki @ bob- prost'un kabul edilen cevabı ile aynıdır: stackoverflow.com/a/206500/264786 Bu nedenle indirildi.
ArturoTena
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.