Przełącznik SQL / wielkość liter w klauzuli „where”

146

Próbowałem się rozejrzeć, ale nie mogłem znaleźć niczego, co by mi pomogło.

Próbuję to zrobić w 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

Wiem, że nie powinienem umieszczać znaku „= @locationID” na końcu każdego z nich, ale nie mogę uzyskać nawet bliskiej poprawności składni. SQL ciągle narzeka na moje „=” w pierwszym wierszu WHEN ...

W jaki sposób mogę to zrobić?

Miles
źródło

Odpowiedzi:

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
Bob Probst
źródło
1
Jak TomH zauważył w komentarzu do Twojej odpowiedzi poniżej, nieprawidłowo utworzyłeś kod SQL. Przetestowałem mój w SQLServer 2005 i działał dobrze.
Bob Probst,
Dlaczego potrzebne są @? Co oni robią?
Tadej
2
@ wskazuje zmienne w t-sql, bez @, @locationID byłoby zinterpretowane jako nazwa kolumny.
Christian Sloper
70

bez opisu sprawy ...

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)
Lukek
źródło
2
To da nieco inny wynik, ponieważ instrukcja Case kończy działanie po spełnieniu warunku - ale składnia OR oceni wszystkie możliwości
tember
1
@tember Nawet jeśli SQL był językiem proceduralnym, jeśli pierwszy OR jest prawdziwy, reszta wyrażenia nie zostanie oceniona. Ponieważ SQL jest językiem deklaratywnym, skąd wiesz, że DBM oceni wszystkie OR? Szczere pytanie, nie rozumiem.
ArturoTena
W SQL reszta wyrażenia jest oceniana w składni OR. Spróbuj tego (nie pozwoliłoby mi dołączyć symbolu @ - będziesz musiał go poprawić, jeśli chcesz go przetestować): zadeklaruj var varchar (5) set var = '0' wybierz 2 / var gdzie var <> 0 lub ISNUMERIC (var) = 1. Chcę, aby warunek został zakończony, ponieważ var JEST równy 0, ale przechodzi dalej, aby sprawdzić, czy jest liczbowy, co jest, i dlatego instrukcja zwraca błąd.
tember
ten pomógł w moim przypadku, gdy miałem inny operator porównania dla każdej wartości typu.
Alex
jeszcze lepiej 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
Łukek
35

Proszę bardzo.

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
DBA w Pittsburghu
źródło
5
Cóż, napisałbym to jako SELECT kolumna1, kolumna2 FROM viewWhthing WHERE (@locationType = 'location' AND account_location = @locationID) LUB (@locationType = 'area' AND xxx_location_area = @locationID) LUB (@locationType = 'Division' AND xxx_location_division = @locationID)
Jan de Vos
2
to jest wielki spokój na przykład, co powiesz na plan wykonania zapytania z najlepszą odpowiedzią (osobiście wolę, aby ten kod metody był jasny i czysty)
PEO
1
naprawdę świetne, jeśli chcesz użyć innej klauzuli where z innym typem, jak int w pierwszej klauzuli i nvarchar w drugiej. z rozwiązaniem Bob Probst nie działa. dzięki
Julian50
6

Powiedziałbym, że jest to wskaźnik wadliwej struktury tabeli. Być może różne typy lokalizacji powinny być rozdzielone w różnych tabelach, umożliwiając wykonywanie znacznie bogatszych zapytań, a także unikanie niepotrzebnych kolumn.

Jeśli nie możesz zmienić struktury, może zadziałać coś podobnego do poniższego:

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
    )

I tak dalej ... Nie możemy zmienić struktury zapytania w locie, ale możemy to zmienić, zrównując predykaty.

EDYCJA: Powyższe sugestie są oczywiście znacznie lepsze, po prostu zignoruj ​​moje.

Mark S. Rasmussen
źródło
Nie sądzę, żeby to była błędna struktura tabeli. Tabela została skonfigurowana w ten sposób, aby odwoływać się do siebie, aby mieć nieskończoną liczbę relacji rodzic / dziecko. Uwierz mi, to było celowe. Myślę, że nie chcę zmieniać struktury mojej tabeli, aby po prostu użyć instrukcji switch. nie jest tak ważne
Miles
5

Problem polega na tym, że kiedy silnik SQL idzie do oceny wyrażenia, sprawdza część FROM, aby wyciągnąć odpowiednie tabele, a następnie część WHERE, aby podać jakieś podstawowe kryteria, więc nie może poprawnie ocenić dynamicznego warunku, w której kolumnie ma sprawdzić przeciwko.

Możesz użyć klauzuli WHERE podczas sprawdzania kryteriów WHERE w predykacie, takich jak

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

więc w twoim konkretnym przypadku będziesz musiał umieścić zapytanie w procedurze składowanej lub utworzyć trzy oddzielne zapytania.

Dillie-O
źródło
5

Operator OR może być alternatywą dla przypadku, gdy jest w stanie

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
atik sarker
źródło
3

Spróbuj tego zapytania. Odpowiedź na powyższy post:

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
Durre Najaf
źródło
2
Do każdego, kto czyta to w przyszłości: jest taka sama, jak zaakceptowana odpowiedź od @ bob-prost powyżej: stackoverflow.com/a/206500/264786
ArturoTena
2

Spróbuj tego:

WHERE (
    @smartLocationType IS NULL 
    OR account_location = (
         CASE
            WHEN @smartLocationType IS NOT NULL 
                 THEN @smartLocationType
            ELSE account_location 
         END
    )
)
shah134pk
źródło
1
Ocena negatywna, ponieważ nie rozumiem, w jaki sposób można wybrać między podanymi ciągami (tj. „Lokalizacja”, „obszar”, „podział”)
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
Darshan Balar
źródło
-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;
kavitha Reddy
źródło
4
Negocjowano, ponieważ ta osoba odpowiadająca nie jest związana z pytaniem. Pytanie brzmiało, jak używać CASE w klauzuli WHERE, a nie jak używać CASE w wybranej kolumnie.
ArturoTena
-2

Spróbuj tego zapytania. Bardzo łatwo to zrozumieć:

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
Mike Clark
źródło
1
Do każdego, kto czyta tę odpowiedź: jest taka sama, jak zaakceptowana odpowiedź od @ bob-prost powyżej: stackoverflow.com/a/206500/264786 Z tego powodu odrzucono.
ArturoTena