2010-07-09 10 views
7

Tengo el siguiente Db y la consulta. La consulta toma dos parámetros: la columna de clasificación y la dirección. Sin embargo, tengo que agregar una ordenación personalizada a la consulta (basado en que el Fuji debe estar primero y Gala el segundo, etc.). Esta parte también funciona pero crea código duplicado en mi consulta. Debido a eso, estoy bastante seguro de que la gente no me dejará verificar esto. Entonces mi pregunta es: ¿hay alguna manera de no duplicar la declaración CASE?Orden de clasificación personalizado: cómo no duplicar la instrucción Case

CREATE TABLE Fruits (
    [type] nvarchar(250), 
    [variety] nvarchar(250), 
    [price] money 
) 
GO 

INSERT INTO Fruits VALUES ('Apple', 'Gala', 2.79) 
INSERT INTO Fruits VALUES ('Apple', 'Fuji', 0.24) 
INSERT INTO Fruits VALUES ('Apple', 'Limbertwig', 2.87) 
INSERT INTO Fruits VALUES ('Orange', 'Valencia', 3.59) 
INSERT INTO Fruits VALUES ('Pear', 'Bradford', 6.05) 

DECLARE @sortColumnName nvarchar(MAX) = 'Variety' 
DECLARE @sortDirection nvarchar(MAX) = 'ASC' 

SELECT ROW_NUMBER() OVER (ORDER BY     
    CASE WHEN @sortColumnName = 'Variety' AND @sortDirection = 'ASC' 
     THEN 
      CASE f.Variety 
       WHEN 'Fuji' THEN 1 
       WHEN 'Gala' THEN 2 
       ELSE 3 
      END  
     END ASC, 
    CASE WHEN @sortColumnName = 'Variety' AND @sortDirection = 'DESC' 
     THEN 
      CASE f.Variety 
       WHEN 'Fuji' THEN 1 
       WHEN 'Gala' THEN 2 
       ELSE 3 
      END  
     END DESC), * 
FROM Fruits f 

¡Gracias!

Respuesta

5

Usted podría multiplicar la clave de clasificación, ya sea 1 o -1 dependiendo de si se solicita ASC o DESC:

SELECT ROW_NUMBER() OVER (ORDER BY     
    CASE WHEN @sortColumnName = 'Variety' 
     THEN 
      (CASE f.Variety 
       WHEN 'Fuji' THEN 1 
       WHEN 'Gala' THEN 2 
       ELSE 3 
      END)  
    END 
    * (CASE WHEN @sortDirection = 'ASC' THEN 1 ELSE -1 END)), * 
FROM Fruits f 
1

Por qué no tienen otra tabla de valor comparable, se unen en la columna de la variedad y la especie en el valor de comparación.

E.g.

INSERT INTO FruitSort VALUES ('Gala', 2) 
INSERT INTO FruitSort VALUES ('Fuji', 1) 

SELECT ROW_NUMBER() OVER (ORDER BY FruitSort.sortvalue) 
FROM Fruits f 
JOIN FruitSort 
    ON FruitSort.variety == Fruits.variety 

¿No sería eso el truco también al ser un poco más de base de datos-y?

No tengo mucha práctica, por lo que la sintaxis probablemente esté rota. Sin embargo, estoy bastante insatisfecho con el concepto de sentencias 'CASE' en SQL.

3

Ya que estás en SQL 2008, se puede usar un CTE:

;WITH CTE AS 
(
    SELECT 
     CASE WHEN @sortColumnName = 'Variety' THEN 
      CASE f.Variety 
       WHEN 'Fuji' THEN 1 
       WHEN 'Gala' THEN 2 
       ELSE 3 
      END  
     END AS sort_column, 
     * 
    FROM 
     Fruits F 
) 
SELECT 
    ROW_NUMBER() OVER (
     ORDER BY 
      CASE WHEN @sortDirection = 'DESC' THEN sort_column ELSE 0 END DESC, 
      CASE WHEN @sortDirection = 'ASC' THEN sort_column ELSE 0 END ASC), 
    type, 
    variety, 
    price 
FROM 
    CTE 

No es tan elegante como el * -1 solución para este problema en particular, pero puede ser adaptado para otras situaciones en las que quiero evitar la duplicación de código.

Cuestiones relacionadas