Comutarea SQL în clauza ‘where’ (Programare, Sql, Declarație De Comutare, Caz)

Miles a intrebat.

Am încercat să caut prin jur, dar nu am găsit nimic care să mă ajute.

Încerc să fac acest lucru în 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

Știu că nu ar trebui să pun ‘= @locationID’ la sfârșitul fiecăruia, dar nu reușesc să obțin o sintaxă nici măcar aproape de a fi corectă. SQL continuă să se plângă de ‘=’ de pe prima linie WHEN…

Cum pot să fac acest lucru?

13 răspunsuri
Bob Probst
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

Comentarii

  • După cum a observat TomH în comentariul la răspunsul dvs. de mai jos, ați format SQL incorect. Eu l-am testat pe al meu în SQLServer 2005 și a funcționat bine. –  > Por Bob Probst.
  • De ce este nevoie de @? Ce fac ele? –  > Por Tadej.
  • @ indică variabile în t-sql, fără @ , @locationID ar fi interpretat ca un nume de coloană. –  > Por Christian Sloper.
Lukek

fără o declarație case…

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)

Comentarii

  • Aceasta va da un rezultat ușor diferit, deoarece instrucțiunea Case iese după ce o condiție este îndeplinită – dar sintaxa OR va evalua toate posibilitățile –  > Por tember.
  • @tember Chiar dacă SQL ar fi un limbaj procedural, dacă primul OR este adevărat, atunci restul expresiei nu este evaluat. Din moment ce SQL este un limbaj declarativ, de unde știți că DBM va evalua toate OR-urile? Întrebare sinceră, nu înțeleg. –  > Por ArturoTena.
  • În SQL, restul expresiei este evaluat în sintaxa OR. Încearcă asta (nu m-a lăsat să includ simbolul @ – va trebui să o corectezi dacă vrei să o testezi): declare var varchar(5) set var = ‘0’ select 2 / var where var <> 0 or ISNUMERIC(var) = 1 . Vreau ca condiția să iasă pentru că var ESTE egal cu 0, dar merge mai departe pentru a verifica dacă este numeric, ceea ce este, și prin urmare declarația returnează o eroare. –  > Por tember.
  • acesta m-a ajutat în cazul meu în care aveam un operator de comparare diferit pentru fiecare valoare de tip. –  > Por Alex.
  • și mai bine 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 –  > Por Lukek.
Pittsburgh DBA

Poftiți.

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

Comentarii

  • Ei bine, aș fi scris asta ca 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) –  > Por Jan de Vos.
  • aceasta este o pace mare de exemplu, ce zici de planul de execuție a interogării cu cel mai bun răspuns ( personal prefer această metodă codul este clar și curat ) – –  > Por PEO.
  • într-adevăr minunat dacă doriți să utilizați diferite clauze where cu tipuri diferite, cum ar fi int pe prima clauză și nvarchar pe a doua. cu soluția lui Bob Probst nu funcționează. mulțumesc – –  > Por Julian50.
Mark S. Rasmussen

Aș spune că acesta este un indicator al unei structuri de tabel defectuoase. Poate că diferitele tipuri de locații ar trebui separate în tabele diferite, permițându-vă să faceți interogări mult mai bogate și, de asemenea, să evitați să aveți coloane superflue în jur.

Dacă nu puteți schimba structura, ar putea funcționa ceva de genul celor de mai jos:

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 așa mai departe… Nu putem schimba structura interogării din mers, dar putem să o suprascriem făcând ca predicatele să se egaleze între ele.

EDIT: Sugestiile de mai sus sunt, desigur, mult mai bune, ignorați-o pe a mea.

Comentarii

  • Nu cred că este vorba de o structură defectuoasă a tabelului. Tabelul a fost configurat în acest fel astfel încât să fie auto-referințe pentru a avea o cantitate infinită de relații părinte/copil. Credeți-mă, a fost intenționat. Nu cred că vreau să-mi schimb structura tabelului pentru a folosi doar o instrucțiune de comutare. nu este atât de importantă.  > Por Miles.
Dillie-O

Problema este că, atunci când motorul SQL evaluează expresia, verifică porțiunea FROM pentru a extrage tabelele corespunzătoare și apoi porțiunea WHERE pentru a furniza unele criterii de bază, astfel încât nu poate evalua corect o condiție dinamică privind coloana care trebuie verificată.

Puteți utiliza o clauză WHERE atunci când verificați criteriile WHERE din predicat, cum ar fi

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

deci, în cazul dvs. particular, va trebui să introduceți interogarea într-o procedură stocată sau să creați trei interogări separate.

atik sarker

Operatorul OR poate fi o alternativă a cazului când în condiția 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

Durre Najaf

Vă rugăm să încercați această interogare. răspuns la postul de mai sus:

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

Comentarii

  • Pentru oricine citește acest lucru în viitor: este același lucru cu răspunsul acceptat de @bob-prost de mai sus: stackoverflow.com/a/206500/264786 –  > Por ArturoTena.
shah134pk

Încearcă asta:

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

Comentarii

  • Downvoted pentru că nu înțeleg cum ar putea alege între șirurile date (de exemplu, „location”, „area”, „division”) –  > Por ArturoTena.
Darshan Balar
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

Omid Karamei

Încercați această interogare, este foarte ușoară și utilă: Este gata de execuție!

USE tempdb
GO

IF NOT OBJECT_ID('Tempdb..Contacts') IS NULL
    DROP TABLE Contacts

CREATE TABLE Contacts(ID INT, FirstName VARCHAR(100), LastName VARCHAR(100))
INSERT INTO Contacts (ID, FirstName, LastName)
SELECT 1, 'Omid', 'Karami'
UNION ALL
SELECT 2, 'Alen', 'Fars'
UNION ALL
SELECT 3, 'Sharon', 'b'
UNION ALL
SELECT 4, 'Poja', 'Kar'
UNION ALL
SELECT 5, 'Ryan', 'Lasr'
GO
 
DECLARE @FirstName VARCHAR(100)
SET @FirstName = 'Omid'
 
DECLARE @LastName VARCHAR(100)
SET @LastName = '' 
 
SELECT FirstName, LastName
FROM Contacts
WHERE  
    FirstName = CASE
    WHEN LEN(@FirstName) > 0 THEN  @FirstName 
    ELSE FirstName 
    END
AND
    LastName = CASE
    WHEN LEN(@LastName) > 0 THEN  @LastName 
    ELSE LastName
    END
GO

Mark Longmire

Acest lucru a funcționat pentru mine.


CREATE TABLE PER_CAL ( CAL_YEAR INT, CAL_PER INT )
INSERT INTO PER_CAL( CAL_YEAR, CAL_PER ) VALUES ( 20,1 ), ( 20,2 ), ( 20,3 ), ( 20,4 ), ( 20,5 ), ( 20,6 ), ( 20,7 ), ( 20,8 ), ( 20,9 ), ( 20,10 ), ( 20,11 ), ( 20,12 ),
( 99,1 ), ( 99,2 ), ( 99,3 ), ( 99,4 ), ( 99,5 ), ( 99,6 ), ( 99,7 ), ( 99,8 ), ( 99,9 ), ( 99,10 ), ( 99,11 ), ( 99,12 )

Secolul de 4 cifre este determinat de regula, dacă anul este de 50 sau mai mult, secolul este 1900, altfel 2000.

Având în vedere două perioade de 6 cifre care marchează perioada de început și de sfârșit, cum ar fi un trimestru, returnează rândurile care se încadrează în acest interval.


-- 1st quarter of 2020
SELECT * FROM PER_CAL WHERE (( CASE WHEN CAL_YEAR > 50 THEN 1900 ELSE 2000 END + CAL_YEAR ) * 100 + CAL_PER ) BETWEEN 202001 AND 202003
-- 4th quarter of 1999
SELECT * FROM PER_CAL WHERE (( CASE WHEN CAL_YEAR > 50 THEN 1900 ELSE 2000 END + CAL_YEAR ) * 100 + CAL_PER ) BETWEEN 199910 AND 199912

kavitha Reddy
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;

Comentarii

  • Downvoted pentru că acest answser nu are legătură cu întrebarea. Întrebarea a fost cum să utilizați CASE pe clauza WHERE, nu cum să utilizați CASE pe o coloană SELECTED. –  > Por ArturoTena.
Mike Clark

Încercați această interogare. Este foarte ușor de înțeles:

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

Comentarii

  • Pentru oricine citește acest răspuns: este același cu răspunsul acceptat de @bob-prost de mai sus: stackoverflow.com/a/206500/264786 Downvoted din acest motiv. –  > Por ArturoTena.