web-dev-qa-db-fra.com

"Trier par" en utilisant un paramètre pour le nom de la colonne

Nous souhaitons utiliser un paramètre dans la clause "Order By" d'une requête ou d'une procédure stockée créée avec Visual Studio DataSet Designer.

Exemple:

  FROM TableName
 WHERE (Forename LIKE '%' + @SearchValue + '%') OR
       (Surname LIKE '%' + @SearchValue + '%') OR
       (@SearchValue = 'ALL')
ORDER BY @OrderByColumn

Cette erreur s'affiche:

Variables are only allowed when ordering by an expression referencing 
a column name.
22
Emad-ud-deen

Vous devriez pouvoir faire quelque chose comme ceci:

SELECT *
FROM
    TableName
WHERE
    (Forename LIKE '%' + @SearchValue + '%') OR
    (Surname LIKE '%' + @SearchValue + '%') OR
    (@SearchValue = 'ALL')
ORDER BY 
    CASE @OrderByColumn
    WHEN 1 THEN Forename
    WHEN 2 THEN Surname
    END;
  • Attribuez 1 à @OrderByColumn pour trier sur Forename.
  • Attribuez 2 pour trier sur Surname.
  • Etc ... vous pouvez étendre ce schéma à un nombre arbitraire de colonnes.

Attention cependant aux performances. Ces types de constructions peuvent interférer avec la capacité de l'optimiseur de requêtes à trouver un plan d'exécution optimal. Par exemple, même si Forename est couvert par l'index, la requête peut toujours nécessiter le tri complet au lieu de simplement parcourir l'index dans l'ordre.

Si tel est le cas et que vous ne pouvez pas supporter les implications en termes de performances, il peut être nécessaire d'avoir une version distincte de la requête pour chaque ordre de tri possible, ce qui complique considérablement les choses côté client.

46
Branko Dimitrijevic

Je sais que j'arrive tard dans ce fil, mais je veux juste le poster au cas où quelqu'un d'autre aurait un problème similaire.

Le problème semble se produire lorsque vous essayez d'effectuer un ORDER BY Directement sur le paramètre, car SQL Server s'attend à ce que vous fournissiez un nombre (1 pour le premier champ, 2 pour le second, etc.) ou un nom de colonne présenté sous la forme d'un identifiant (MyField ou "MyField") ou d'une chaîne ('MyField').

Par exemple:

DECLARE @ORDERBY AS NVARCHAR(20)
;

SELECT @ORDERBY = :Param1 --(Supposing that the user enters 'MyField')
;

SELECT TOP 1 *
FROM MyTable
ORDER BY @ORDERBY DESC
;

Vous obtenez l'erreur suivante:

L'élément SELECT identifié par le numéro ORDER BY 1 contient une variable dans le cadre de l'expression identifiant une position de colonne. Les variables ne sont autorisées que lors de la commande par une expression faisant référence à un nom de colonne. (SQLSTATE = 42000) (1008) (Gravité = 16)

Si vous écrivez la requête manuellement de l'une des manières décrites (à l'aide d'un identifiant ou d'une chaîne), il n'y a pas d'erreur.

SELECT TOP 1 *
FROM MyTable
ORDER BY MyField DESC
;

SELECT TOP 1 *
FROM MyTable
ORDER BY "MyField" DESC
;

SELECT TOP 1 *
FROM MyTable
ORDER BY 'MyField' DESC
;

Donc, si vous effectuez une CAST() sur ce même paramètre, sa valeur est convertie en chaîne et la requête s'exécute avec succès:

DECLARE @ORDERBY AS NVARCHAR(20)
;

SELECT @ORDERBY = :Param1 --(Supposing that the user enters the text 'MyField')
;

SELECT TOP 1 *
FROM MyTable
ORDER BY CAST(@ORDERBY AS NVARCHAR(20)) DESC
;

Dans ce cas, (encore une fois, en supposant que l'utilisateur a écrit la chaîne "MyField" comme valeur de: Param1), la requête en cours d'exécution est:

SELECT TOP 1 *
FROM MyTable
ORDER BY 'MyField' DESC
;

Cette requête s'exécute avec succès, sans erreur et sans impact significatif apparent sur les performances, sans avoir besoin d'énumérer toutes les entrées utilisateur possibles dans une instruction CASE qui pourrait potentiellement s'étendre à des centaines de valeurs possibles.

J'ai utilisé cette solution plusieurs fois dans Microsoft SQL Server, de 2005 à 2016, sans aucun problème.

J'espère que cela peut encore être utile à quelqu'un.

0
3BK