2008-10-15 15 views
127

Intenté buscar pero no pude encontrar nada que me ayudara.SQL Switch/Case in where clause

estoy tratando de hacer esto en 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 

sé que no debería tener que poner '= @locationID' al final de cada uno, pero no puedo obtener la sintaxis incluso cerca de ser correcto. SQL sigue quejándose de mi '=' en la primera línea WHEN ...

Help!

Respuesta

165
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

Como TomH señaló en el comentario a su respuesta a continuación, usted formó el SQL de forma incorrecta. Probé el mío en SQLServer 2005 y funcionó bien. –

+0

¿Por qué se necesita @? ¿Qué hacen? – JedatKinports

6

Yo diría que esto es un indicador de una estructura de mesa defectuosa. Tal vez los diferentes tipos de ubicación se deben separar en diferentes tablas, lo que le permite hacer consultas mucho más ricas y también evitar tener columnas superfluas alrededor.

Si no es capaz de cambiar la estructura, algo así como el siguiente podría funcionar:

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 
    ) 

Y así sucesivamente ... No podemos cambiar la estructura de la consulta sobre la marcha, pero puede anularlo haciendo que los predicados se igualen.

EDITAR: Las sugerencias anteriores son, por supuesto, mucho mejores, solo ignore las mías.

+0

No creo que sea una estructura de mesa defectuosa.La tabla se configuró de esta manera para que fuera una auto referencia para tener una cantidad infinita de relaciones padre/hijo. Créanme, fue a propósito. No creo que quiera cambiar la estructura de mi tabla para simplemente usar una declaración de cambio. su nto tan importante – Miles

4

El problema con esto es que cuando el motor SQL va a evaluar la expresión, comprueba la parte FROM para extraer las tablas adecuadas y luego la parte WHERE para proporcionar algunos criterios básicos, por lo que no puede evaluar correctamente una condición dinámica en qué columna verificar

Se puede utilizar una cláusula WHERE cuando se esté examinando los criterios en que parte del predicado, como

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

por lo que en su caso particular, vas a necesitar poner la consulta en un procedimiento almacenado o crea tres consultas separadas.

28

Aquí tienes.

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

Bueno, yo hubiera escrito que a medida que SELECCIONAR column1, columna2 DE viewWhatever DONDE (@locationType = 'ubicación' Y account_location = @locationID) O (@locationType = 'área' Y xxx_location_area = @locationID) O (@locationType = 'division' AND xxx_location_division = @locationID) –

+2

esto es una gran paz de ejemplo, ¿qué hay del plan de ejecución de consultas con la mejor respuesta? (personalmente prefiero este código de método es claro y limpio) – PEO

+1

realmente genial si quieres usar diferente cláusula where con un tipo diferente como int en la 1ra cláusula y nvarchar en la 2da. con la solución Bob Probst no funciona. gracias – Julian50

62

sin una declaración de caso ...

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) 
+1

Esto arrojará un resultado ligeramente diferente ya que la instrucción Case se cierra después de cumplirse una condición, pero la sintaxis OR evaluará todas las posibilidades – tember

+0

@tember Incluso si SQL fuera un lenguaje de procedimiento, si el primero O es verdadero, entonces el resto de la expresión no se evalúa. Como SQL es un lenguaje declarativo, ¿cómo sabe que el DBM evaluará todas las RUP? Pregunta sincera, no entiendo. –

+0

En SQL, el resto de la expresión se evalúa en la sintaxis OR. Prueba esto (que no me dejaría incluir el símbolo @ - que tendrá que corregirlo si quieres probarlo): varchar declarar var (5) conjunto var = '0' seleccione 2/var donde var <> 0 o ISNUMERIC (var) = 1 . Quiero que la condición salga porque var IS es igual a 0, pero sigue adelante para comprobar si es numérica, y por lo tanto, la declaración devuelve un error. – tember

3

Por favor, intente esta consulta. Para respuesta post anterior:

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 
+1

Para quien lea esto en el futuro: es lo mismo que la respuesta aceptada de @ bob-prost anterior: http://stackoverflow.com/a/206500/264786 –

2

Prueba esto:

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

Downvoted porque no entiendo cómo esto podría elegir entre el cadenas dadas (es decir, 'ubicación', 'área', 'división') –

-2

Intentar esta consulta. Es muy fácil de entender:

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 
+0

Para quien lea esta respuesta: es lo mismo que la respuesta aceptada de @ bob-prost anterior: http://stackoverflow.com/a/206500/264786 Downvoted por este motivo. –

-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; 
+2

Downvoted porque este contestador no está relacionado con la pregunta.La pregunta era cómo usar CASE en la cláusula WHERE, no cómo usar CASE en una columna SELECTed. –

4

operador O puede ser una alternativa de la funda cuando en donde la condición

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