2010-07-09 5 views
7

Je dispose de la base de données et de la requête suivantes. La requête prend deux paramètres: la colonne de tri et la direction. Cependant, je dois ajouter un tri personnalisé à la requête (basé sur le Fuji devrait venir en premier et Gala en second lieu, etc.). Cette partie fonctionne également mais elle crée du code dupliqué dans ma requête. Pour cette raison, je suis certain que les gens ne me laisseront pas vérifier cela. Ma question est la suivante: y a-t-il un moyen de ne pas reproduire la déclaration CASE?Ordre de tri personnalisé - Comment ne pas dupliquer l'instruction 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 

Merci!

Répondre

5

Vous pouvez multiplier la clé de tri par +1 ou -1 selon que l'ASC ou DESC est demandé:

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

Pourquoi ne pas avoir une autre table pour une valeur comparable, joignez-vous à la colonne de variété, et trier sur la valeur de comparaison.

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 

Cela ne ferait-il pas aussi l'affaire tout en étant un peu plus de base de données?

Je ne suis pas très pratiqué, donc la syntaxe est probablement assez cassée. Je suis cependant assez insatisfait du concept des instructions 'CASE' dans SQL.

3

Puisque vous êtes sur SQL Server 2008, vous pouvez utiliser 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 

Ce n'est pas aussi lisse que la * -1 solution pour ce problème particulier, mais il peut être adapté à d'autres situations où vous vouloir éviter la duplication de code.