Tri dynamique dans les procédures stockées SQL


126

C'est un problème sur lequel j'ai passé des heures à étudier dans le passé. Cela me semble être quelque chose qui aurait dû être abordé par les solutions SGBDR modernes , mais pour l'instant je n'ai rien trouvé qui réponde vraiment à ce que je considère être un besoin incroyablement courant dans toute application Web ou Windows avec un back-end de base de données.

Je parle de tri dynamique. Dans mon monde fantastique, cela devrait être aussi simple que quelque chose comme:

ORDER BY @sortCol1, @sortCol2

C'est l'exemple canonique donné par les développeurs novices de SQL et de procédures stockées sur tous les forums sur Internet. «Pourquoi n'est-ce pas possible? ils demandent. Invariablement, quelqu'un finit par leur parler de la nature compilée des procédures stockées, des plans d'exécution en général et de toutes sortes d'autres raisons pour lesquelles il n'est pas possible de mettre un paramètre directement dans une ORDER BYclause.


Je sais ce que certains d'entre vous pensent déjà: «Alors laissez le client faire le tri». Naturellement, cela décharge le travail de votre base de données. Dans notre cas cependant, nos serveurs de base de données ne transpirent même pas 99% du temps et ils ne sont même pas encore multicœurs ni aucune des myriades d'améliorations de l'architecture système qui se produisent tous les 6 mois. Pour cette seule raison, avoir nos bases de données gérer le tri ne serait pas un problème. De plus, les bases de données sont trèsbon pour trier. Ils sont optimisés pour cela et ont eu des années pour bien faire les choses, le langage pour le faire est incroyablement flexible, intuitif et simple et surtout tout écrivain SQL débutant sait comment le faire et plus important encore, il sait comment le modifier, faire des changements, faire de la maintenance, etc. Lorsque vos bases de données sont loin d'être taxées et que vous souhaitez simplement simplifier (et raccourcir!) le temps de développement, cela semble être un choix évident.

Ensuite, il y a le problème du Web. J'ai joué avec JavaScript qui fera le tri côté client des tableaux HTML, mais ils ne sont inévitablement pas assez flexibles pour mes besoins et, encore une fois, comme mes bases de données ne sont pas trop taxées et peuvent faire le tri très très facilement, je ont du mal à justifier le temps qu'il faudrait pour réécrire ou lancer mon propre trieur JavaScript. Il en va généralement de même pour le tri côté serveur, bien qu'il soit probablement déjà largement préféré à JavaScript. Je ne suis pas de ceux qui aiment particulièrement les frais généraux des DataSets, alors poursuivez-moi.

Mais cela ramène le fait que ce n'est pas possible - ou plutôt, pas facilement. J'ai fait, avec les systèmes antérieurs, une manière incroyablement pirate d'obtenir un tri dynamique. Ce n'était pas joli, ni intuitif, simple ou flexible et un écrivain SQL débutant serait perdu en quelques secondes. Cela semble déjà être non pas tant une «solution» qu'une «complication».


Les exemples suivants ne sont pas destinés à exposer des meilleures pratiques ou un bon style de codage ou quoi que ce soit, ni ne reflètent mes capacités en tant que programmeur T-SQL. Ils sont ce qu'ils sont et j'admets pleinement qu'ils sont déroutants, de mauvaise forme et tout simplement piratés.

Nous passons une valeur entière comme paramètre à une procédure stockée (appelons simplement le paramètre "sort") et à partir de là, nous déterminons un tas d'autres variables. Par exemple ... disons que le tri est 1 (ou la valeur par défaut):

DECLARE @sortCol1 AS varchar(20)
DECLARE @sortCol2 AS varchar(20)
DECLARE @dir1 AS varchar(20)
DECLARE @dir2 AS varchar(20)
DECLARE @col1 AS varchar(20)
DECLARE @col2 AS varchar(20)

SET @col1 = 'storagedatetime';
SET @col2 = 'vehicleid';

IF @sort = 1                -- Default sort.
BEGIN
    SET @sortCol1 = @col1;
    SET @dir1 = 'asc';
    SET @sortCol2 = @col2;
    SET @dir2 = 'asc';
END
ELSE IF @sort = 2           -- Reversed order default sort.
BEGIN
    SET @sortCol1 = @col1;
    SET @dir1 = 'desc';
    SET @sortCol2 = @col2;
    SET @dir2 = 'desc';
END

Vous pouvez déjà voir comment si je déclarais plus de variables @colX pour définir d'autres colonnes, je pourrais vraiment faire preuve de créativité avec les colonnes à trier en fonction de la valeur de "sort" ... pour l'utiliser, cela finit généralement par ressembler à ce qui suit clause incroyablement désordonnée:

ORDER BY
    CASE @dir1
        WHEN 'desc' THEN
            CASE @sortCol1
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END DESC,
    CASE @dir1
        WHEN 'asc' THEN
            CASE @sortCol1
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END,
    CASE @dir2
        WHEN 'desc' THEN
            CASE @sortCol2
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END DESC,
    CASE @dir2
        WHEN 'asc' THEN
            CASE @sortCol2
                WHEN @col1 THEN [storagedatetime]
                WHEN @col2 THEN [vehicleid]
            END
    END

C'est évidemment un exemple très dépouillé. Le vrai truc, puisque nous avons généralement quatre ou cinq colonnes sur lesquelles prendre en charge le tri, chacune avec une éventuelle colonne secondaire ou même une troisième colonne à trier en plus de cela (par exemple, date décroissante puis triée secondairement par nom croissant) et chaque support bi- tri directionnel qui double effectivement le nombre de cas. Ouais ... ça devient poilu très vite.

L'idée est que l'on pourrait "facilement" changer les cas de tri de telle sorte que le Vehicleid soit trié avant le storagedatetime ... mais la pseudo-flexibilité, au moins dans cet exemple simple, s'arrête vraiment là. Essentiellement, chaque cas qui échoue à un test (car notre méthode de tri ne s'applique pas cette fois-ci) renvoie une valeur NULL. Et ainsi vous vous retrouvez avec une clause qui fonctionne comme suit:

ORDER BY NULL DESC, NULL, [storagedatetime] DESC, blah blah

Vous avez eu l'idée. Cela fonctionne car SQL Server ignore effectivement les valeurs nulles dans l'ordre des clauses. C'est incroyablement difficile à maintenir, comme toute personne ayant une connaissance de base de SQL peut probablement le voir. Si j'ai perdu l'un de vous, ne vous sentez pas mal. Il nous a fallu beaucoup de temps pour le faire fonctionner et nous sommes toujours confus en essayant de le modifier ou d'en créer de nouveaux comme celui-ci. Heureusement, il n'a pas besoin de changer souvent, sinon cela deviendrait rapidement "ne vaut pas la peine".

Pourtant, cela a fonctionné.


Ma question est alors: y a-t-il une meilleure façon?

Je suis d'accord avec des solutions autres que celles de la procédure stockée, car je réalise que ce n'est peut-être pas la voie à suivre. De préférence, j'aimerais savoir si quelqu'un peut le faire mieux dans la procédure stockée, mais sinon, comment gérez-vous tous permettre à l'utilisateur de trier dynamiquement des tables de données (bidirectionnelles également) avec ASP.NET?

Et merci d'avoir lu (ou du moins écrémé) une si longue question!

PS: Soyez heureux de ne pas avoir montré mon exemple de procédure stockée prenant en charge le tri dynamique, le filtrage dynamique / recherche de texte des colonnes, la pagination via ROWNUMBER () OVER, ET essayez ... attraper avec la restauration des transactions sur les erreurs ... "de la taille d'un géant" ne commence même pas à les décrire.


Mettre à jour:

  • Je voudrais éviter le SQL dynamique . Analyser une chaîne ensemble et exécuter un EXEC dessus va à l'encontre de beaucoup de l'objectif d'avoir une procédure stockée en premier lieu. Parfois, je me demande si les inconvénients de faire une telle chose n'en valent pas la peine, du moins dans ces cas spéciaux de tri dynamique. Pourtant, je me sens toujours sale chaque fois que je fais des chaînes SQL dynamiques comme ça - comme si je vis toujours dans le monde ASP classique.
  • Une grande partie des raisons pour lesquelles nous voulons des procédures stockées en premier lieu est pour la sécurité . Je n'ai pas la possibilité de faire un appel sur les problèmes de sécurité, je suggère seulement des solutions. Avec SQL Server 2005, nous pouvons définir des autorisations (sur une base par utilisateur si nécessaire) au niveau du schéma sur des procédures stockées individuelles, puis refuser directement toute requête sur les tables. Critiquer les avantages et les inconvénients de cette approche est peut-être pour une autre question, mais encore une fois, ce n'est pas ma décision. Je suis juste le singe du code principal. :)

Référez-vous également à stackoverflow.com/questions/3659981/… - ORDER BY dynamique SQL Server avec des types de données mixtes
LCJ

Le SQL dynamique est le moyen supérieur FAR ... IF [et c'est un gros IF] .. votre couche d'accès aux données est stricte et votre SQL dynamique est généré par un système qui est rigoureusement programmé avec des règles SGBDR exprimées sous une forme parfaite. Une architecture de base de données
conçue par

Réponses:


97

Ouais, c'est une douleur, et la façon dont tu le fais ressemble à ce que je fais:

order by
case when @SortExpr = 'CustomerName' and @SortDir = 'ASC' 
    then CustomerName end asc, 
case when @SortExpr = 'CustomerName' and @SortDir = 'DESC' 
    then CustomerName end desc,
...

Cela, pour moi, est toujours bien meilleur que la création de SQL dynamique à partir de code, qui se transforme en un cauchemar d'évolutivité et de maintenance pour les DBA.

Ce que je fais à partir du code, c'est refactoriser la pagination et le tri afin que je n'ai au moins pas beaucoup de répétition avec les valeurs de remplissage pour @SortExpret @SortDir.

En ce qui concerne le SQL, gardez la conception et le formatage identiques entre les différentes procédures stockées, de sorte qu'il soit au moins soigné et reconnaissable lorsque vous apportez des modifications.


1
Exactement. Mon objectif était d'éviter de faire une commande EXEC sur une grosse chaîne varchar 5000. Tout ce que nous faisons doit être fait via des procédures stockées ne serait-ce que pour la sécurité supplémentaire puisque nous pouvons définir des autorisations sur celles-ci au niveau du schéma. L'évolutivité et les gains de performances ne sont qu'un plus dans notre cas.
Sean Hanley le

1
Ajoutez la maintenabilité à {sécurité, évolutivité, performances}. Une fois que vous avez 3 ou 4 applications avec SQL dynamique en cours d'exécution sur votre base de données, vous êtes foutu, vous ne pouvez rien changer, d'autant plus que les applications vieillissent et que les développeurs avancent. Exec et SQL dynamique sont mauvais.
Eric Z Beard le

C'est juste - nous le faisons déjà, bien avant mon arrivée, pour toutes les applications Web ASP classiques encore en cours d'exécution et de nombreuses applications Access VB toujours en circulation. Je me contracte et je dois retenir mes envies de corriger des erreurs flagrantes chaque fois que je dois effectuer une maintenance sur l'une d'entre elles.
Sean Hanley

1
C'est ce que je fais aussi, sauf que j'encode la direction dans SortExpr: ORDER BY CASE WHEN sort = 'FirstName' THEN FirstName END ASC, CASE WHEN sort = '-FirstName' THEN FirstName END DESC
Michael Bray

C'est LE cauchemar pour les DBA et les ingénieurs logiciels. Donc, au lieu de pouvoir avoir des systèmes dynamiques mais stricts qui génèrent des instructions SQL expressives basées sur votre schéma d'information, vous avez ce glop dégoûtant de charabia codé en dur. C'est une mauvaise programmation à son meilleur.
hajikelist

23

Cette approche empêche les colonnes triables d'être dupliquées deux fois dans l'ordre par, et est un peu plus lisible IMO:

SELECT
  s.*
FROM
  (SELECT
    CASE @SortCol1
      WHEN 'Foo' THEN t.Foo
      WHEN 'Bar' THEN t.Bar
      ELSE null
    END as SortCol1,
    CASE @SortCol2
      WHEN 'Foo' THEN t.Foo
      WHEN 'Bar' THEN t.Bar
      ELSE null
    END as SortCol2,
    t.*
  FROM
    MyTable t) as s
ORDER BY
  CASE WHEN @dir1 = 'ASC'  THEN SortCol1 END ASC,
  CASE WHEN @dir1 = 'DESC' THEN SortCol1 END DESC,
  CASE WHEN @dir2 = 'ASC'  THEN SortCol2 END ASC,
  CASE WHEN @dir2 = 'DESC' THEN SortCol2 END DESC

Cela semblait être une bonne réponse mais ne semble pas fonctionner lorsque les colonnes triables ont des types de données différents
SlimSim


6

Mes applications le font beaucoup mais elles construisent toutes dynamiquement le SQL. Cependant, lorsque je traite des procédures stockées, je fais ceci:

  1. Faites de la procédure stockée une fonction qui renvoie une table de vos valeurs - pas de tri.
  2. Ensuite, dans votre code d'application, faites un select * from dbo.fn_myData() where ... order by ...afin que vous puissiez spécifier de manière dynamique l'ordre de tri.

Alors au moins la partie dynamique est dans votre application, mais la base de données fait toujours le gros du travail.


1
C'est probablement le meilleur compromis que j'ai jamais vu entre l'utilisation conjointe de SQL dynamique et de procédures stockées. Je l'aime. Je pourrais expérimenter parfois une approche similaire, mais un tel changement serait prohibitif dans l'un de nos projets en cours.
Sean Hanley le

1
Vous pouvez obtenir la même chose en utilisant une variable de table locale au lieu d'une fonction tabulaire renvoyant des données. Je trouve les tables locales plus flexibles que les fonctions, car vous pouvez générer des informations de débogage.
Sanjay Zalke

5

Une technique de procédure stockée (hack?) Que j'ai utilisée pour éviter le SQL dynamique pour certains travaux est d'avoir une colonne de tri unique. C'est à dire,

SELECT
   name_last,
   name_first,
   CASE @sortCol WHEN 'name_last' THEN [name_last] ELSE 0 END as mySort
FROM
   table
ORDER BY 
    mySort

Celui-ci est facile à battre en soumission - vous pouvez concater des champs dans votre colonne mySort, inverser l'ordre avec des fonctions mathématiques ou de date, etc.

De préférence cependant, j'utilise mes gridviews asp.net ou d'autres objets avec un tri intégré pour faire le tri pour moi APRÈS avoir récupéré les données de Sql-Server. Ou même si ce n'est pas intégré - par exemple, les tables de données, etc. dans asp.net.


4

Vous pouvez pirater cela de différentes manières.

Conditions préalables:

  1. Une seule instruction SELECT dans le sp
  2. Oubliez tout tri (ou ayez une valeur par défaut)

Puis insérez dans une table temporaire:

create table #temp ( your columns )

insert #temp
exec foobar

select * from #temp order by whatever

Méthode n ° 2: configurez un serveur lié à lui-même, puis sélectionnez-le en utilisant openquery: http://www.sommarskog.se/share_data.html#OPENQUERY


4

Il peut y avoir une troisième option, puisque votre serveur a beaucoup de cycles de réserve - utilisez une procédure d'aide pour faire le tri via une table temporaire. Quelque chose comme

create procedure uspCallAndSort
(
    @sql varchar(2048),        --exec dbo.uspSomeProcedure arg1,'arg2',etc.
    @sortClause varchar(512)    --comma-delimited field list
)
AS
insert into #tmp EXEC(@sql)
declare @msql varchar(3000)
set @msql = 'select * from #tmp order by ' + @sortClause
EXEC(@msql)
drop table #tmp
GO

Attention: je n'ai pas testé cela, mais cela "devrait" fonctionner dans SQL Server 2005 (qui créera une table temporaire à partir d'un jeu de résultats sans spécifier les colonnes à l'avance.)


2

À un moment donné, cela ne vaut-il pas la peine de s'éloigner des procédures stockées et d'utiliser simplement des requêtes paramétrées pour éviter ce type de piratage?


1
Dans certains cas, ce sont peut-être des marteaux sur un clou, mais souvent nous voulons définir des permissions (EXECUTE en particulier) directement sur les procédures stockées et interdire toute requête SQL directement sur les tables, même SELECT. Je n'aime pas beaucoup le piratage non plus, mais la sécurité n'est pas mon devoir.
Sean Hanley le

1
C'est pourquoi tant de personnes se tournent vers la cartographie relationnelle d'objets. Des allers-retours inutiles pour le tri, d'énormes blocs CASE pour les mêmes, des mises à jour insensées de tonnes de colonnes alors qu'il n'en fallait vraiment qu'une seule à mettre à jour, etc. Le seul argument gagnant pour les procédures stockées qui reste est la sécurité.
Pittsburgh DBA

Je passe d'un ORM (EF) à une procédure stockée car l'ORM ne prend pas en charge la recherche de texte intégral.
Ronnie Over du

@RonnieOverby La recherche en texte intégral est souvent mieux servie par une solution dédiée, par exemple Lucene.
Hank Gay

@HankGay J'ai l'étrange impression que le framework d'entité ne supporte pas non plus Lucene.
Ronnie Over du

2

Je suis d'accord, utilisez le côté client. Mais il semble que ce ne soit pas la réponse que vous souhaitez entendre.

Donc, c'est parfait tel quel. Je ne sais pas pourquoi vous voudriez le changer, ou même demander "Y a-t-il un meilleur moyen." Vraiment, cela devrait s'appeler "The Way". En outre, il semble fonctionner et répondre parfaitement aux besoins du projet et sera probablement suffisamment extensible pour les années à venir. Étant donné que vos bases de données ne sont pas taxées et que le tri est vraiment très simple, cela devrait le rester pour les années à venir.

Je ne transpirerais pas.


Je n'ai aucun problème avec le côté client, car j'emprunte cette voie avec les applications Windows. Mais qu'en est-il des applications Web? Je ne trouve pas beaucoup de solution JavaScript suffisamment flexible. Et oui, cela fonctionne comme je l'ai dit comme nous l'avons fait, mais c'est un cauchemar de SQL. Bien sûr, j'aimerais savoir s'il existe de meilleures façons.
Sean Hanley le

Il est intégré aux contrôles .NET plus récents (2.0 et plus récents). Ou vous pouvez créer le vôtre et l'appliquer à une vue de données. msdn.microsoft.com/en-us/library/hwf94875(VS.80).aspx
DS

2
Mon problème est donc d'évolutivité et de performances. Le tri côté client ou côté serveur Web nécessite de charger toutes les données au lieu des 10 ou 15 que vous allez afficher sur une page à la fois. C'est extrêmement coûteux, à long terme, alors que le tri de base de données n'a pas cela.
Sean Hanley

2

Lorsque vous paginez des résultats triés, le SQL dynamique est une bonne option. Si vous êtes paranoïaque à propos de l'injection SQL, vous pouvez utiliser les numéros de colonne au lieu du nom de colonne. J'ai fait cela avant d'utiliser des valeurs négatives pour la descente. Quelque chose comme ça...

declare @o int;
set @o = -1;

declare @sql nvarchar(2000);
set @sql = N'select * from table order by ' + 
    cast(abs(@o) as varchar) + case when @o < 0 then ' desc' else ' asc' end + ';'

exec sp_executesql @sql

Ensuite, vous devez simplement vous assurer que le nombre est compris entre 1 et # de colonnes. Vous pouvez même étendre cela à une liste de numéros de colonne et l'analyser dans une table d'entiers en utilisant une fonction comme celle-ci . Ensuite, vous construisez l'ordre par clause comme ceci ...

declare @cols varchar(100);
set @cols = '1 -2 3 6';

declare @order_by varchar(200)

select @order_by = isnull(@order_by + ', ', '') + 
        cast(abs(number) as varchar) + 
        case when number < 0 then ' desc' else '' end
from dbo.iter_intlist_to_tbl(@cols) order by listpos

print @order_by

Un inconvénient est que vous devez vous souvenir de l'ordre de chaque colonne côté client. Surtout lorsque vous n'affichez pas toutes les colonnes ou que vous les affichez dans un ordre différent. Lorsque le client souhaite trier, vous mappez les noms de colonnes à l'ordre des colonnes et générez la liste des entiers.


Nous utilisons sp_executesql pour créer des requêtes de création de rapports dynamiques. Très efficace. Le SQL ne peut pas être construit à partir de l'application, mais les paramètres sont simplement insérés là où c'est nécessaire et exécutés normalement.
Josh Smeaton

2

Un argument contre le tri côté client est la pagination et les données de grand volume. Une fois que votre nombre de lignes dépasse ce que vous pouvez facilement afficher, vous triez souvent dans le cadre d'un saut / prise, que vous souhaitez probablement exécuter en SQL.

Pour Entity Framework, vous pouvez utiliser une procédure stockée pour gérer votre recherche de texte. Si vous rencontrez le même problème de tri, la solution que j'ai vue consiste à utiliser une procédure stockée pour la recherche, en renvoyant uniquement un jeu de clés d'identification pour la correspondance. Ensuite, ré-interrogez (avec le tri) sur la base de données en utilisant les identifiants dans une liste (contient). EF gère cela assez bien, même lorsque le jeu d'identifiants est assez volumineux. Oui, il s'agit de deux allers-retours, mais cela vous permet de toujours conserver votre tri dans la base de données, ce qui peut être important dans certaines situations, et vous empêche d'écrire une cargaison de logique dans la procédure stockée.


1

Que diriez-vous de gérer le tri sur les éléments affichant les résultats - grilles, rapports, etc. plutôt que sur SQL?

ÉDITER:

Pour clarifier les choses puisque cette réponse a été votée à la baisse plus tôt, je vais élaborer un peu ...

Vous avez déclaré que vous connaissiez le tri côté client mais que vous vouliez vous en éloigner. C'est votre appel, bien sûr.

Ce que je tiens à souligner, cependant, c'est qu'en le faisant du côté client, vous pouvez extraire des données UNE FOIS, puis les utiliser comme vous le souhaitez - au lieu de faire plusieurs allers-retours vers le serveur à chaque fois. le tri est changé.

Votre serveur SQL n'est pas taxé pour le moment et c'est génial. Ça ne devrait pas l'être. Mais ce n'est pas parce qu'il n'est pas encore surchargé qu'il le restera pour toujours.

Si vous utilisez l'un des éléments ASP.NET les plus récents pour l'affichage sur le Web, une grande partie de ces éléments est déjà intégré.

Vaut-il la peine d'ajouter autant de code à chaque procédure stockée juste pour gérer le tri? Encore une fois, votre appel.

Ce n'est pas moi qui serai finalement en charge de le soutenir. Mais réfléchissez à ce qui sera impliqué lorsque des colonnes seront ajoutées / supprimées dans les différents ensembles de données utilisés par les procédures stockées (nécessitant des modifications des instructions CASE) ou lorsque soudainement au lieu de trier par deux colonnes, l'utilisateur décide qu'il en a besoin de trois - vous obligeant à mettre à jour maintenant chacune de vos procédures stockées qui utilise cette méthode.

Pour moi, cela vaut la peine d'obtenir une solution côté client fonctionnelle et de l'appliquer à la poignée d'affichages de données destinés aux utilisateurs et d'en finir avec elle. Si une nouvelle colonne est ajoutée, elle est déjà gérée. Si l'utilisateur souhaite trier par plusieurs colonnes, il peut trier par deux ou vingt d'entre elles.


Ce serait la bonne façon, mais n'est pas considérée comme "une meilleure façon"
DS

Parce que j'écris toujours mon propre tri en C # ou en JavaScript et il semble que cela devrait être beaucoup plus facile et plus rapide en SQL. Ainsi ma question. Est-ce que je manquais simplement quelque chose d'évident ou sommes-nous coincés à écrire notre propre tri personnalisé (en C # ou JavaScript) pour chaque application sur laquelle nous travaillons?
Sean Hanley le

3
Attendez, qu'en est-il des ensembles de résultats avec des dizaines de milliers de lignes? Vous ne pouvez pas renvoyer toutes ces données au client. Vous devez effectuer la pagination et le tri sur la base de données.
Eric Z Beard le

Yadyn, compris. Mais une fois que vous avez un trieur générique pour vos grilles, vous ne l'utilisez que pour toutes vos affaires.
Kevin Fairchild le

Eric, c'est vrai ... Dans de tels cas, vous avez besoin d'une manipulation supplémentaire et peut-être que cela aurait du sens dans SQL. C'est loin d'être un problème entre le vrai et le faux. Dans certains cas, cela aura du sens pour SQL et dans certains cas, sur le client.
Kevin Fairchild le

1

Désolé, je suis en retard à la fête, mais voici une autre option pour ceux qui veulent vraiment éviter le SQL dynamique, mais veulent la flexibilité qu'il offre:

Au lieu de générer dynamiquement le SQL à la volée, écrivez du code pour générer un processus unique pour chaque variation possible. Ensuite, vous pouvez écrire une méthode dans le code pour examiner les options de recherche et lui faire choisir le processus approprié à appeler.

Si vous n'avez que quelques variantes, vous pouvez simplement créer les procs à la main. Mais si vous avez beaucoup de variations, au lieu d'avoir à les maintenir toutes, vous maintiendrez simplement votre générateur de proc à la place pour qu'il les recrée.

En tant qu'avantage supplémentaire, vous obtiendrez de meilleurs plans SQL pour de meilleures performances en le faisant également.


-1

Cette solution pourrait ne fonctionner qu'en .NET, je ne sais pas.

Je récupère les données dans le C # avec l'ordre de tri initial dans la clause SQL order by, je mets ces données dans un DataView, je les cache dans une variable de session et je les utilise pour créer une page.

Lorsque l'utilisateur clique sur un en-tête de colonne pour trier (ou page, ou filtre), je ne retourne pas dans la base de données. Au lieu de cela, je retourne à mon DataView mis en cache et définit sa propriété "Sort" sur une expression que je construis dynamiquement, tout comme je le ferais en SQL dynamique. (Je fais le filtrage de la même manière, en utilisant la propriété "RowFilter").

Vous pouvez le voir / sentir qu'il fonctionne dans une démo de mon application, BugTracker.NET, à http://ifdefined.com/btnet/bugs.aspx


DOUX! Bug tracker.NET est génial!
digiguru

-7

Vous devez éviter le tri SQL Server, sauf si nécessaire. Pourquoi ne pas trier sur le serveur d'applications ou côté client? De plus .NET Generics fait un tri exceptionnel


6
En raison de l'évolutivité. C'est bien pour quelques milliers de lignes, mais je ne veux pas en tirer dix mille et les trier. Ou plus. Et qu'en est-il de la pagination? Je ne veux souvent tirer que ce que j'ai besoin d'afficher. Le tri des lignes 21 à 30 sur 24056 après coup serait incorrect.
Sean Hanley
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.