Je construis une requête SQL en C #. Il différera en fonction de certaines conditions stockées en tant que variables dans le code.
string Query="SELECT * FROM Table1 WHERE 1=1 ";
if (condition1)
Query += "AND Col1=0 ";
if (condition2)
Query += "AND Col2=1 ";
if (condition3)
Query += "AND Col3=2 ";
Cela fonctionne, mais tester 1 = 1 ne semble pas élégant. Si je ne l'utilisais pas, je devrais me souvenir et vérifier à chaque fois si le mot-clé «où» était déjà ajouté ou non à la requête.
Y a-t-il une meilleure solution?
42 = 42
;-)Select 42
requêtes que nous recevions. (pas amusant d'essayer de retrouver la source)If I didn't use it, I would have to remember and check every time if "where" keyword was already added or not to the query
- C'est pourquoi vous utilisez1 = 1
. Le moteur de base de données l'optimise de toute façon, donc bien que cela puisse paraître moche, c'est de loin le moyen le plus simple de résoudre le problème.Réponses:
Enregistrez les conditions dans une liste:
la source
ToArray()
n'est pas nécessaire avec .NET 4 car il y a une surcharge qui en accepteIEnumerable<string>
.Une solution consiste simplement à ne pas écrire de requêtes manuellement en ajoutant des chaînes. Vous pouvez utiliser un ORM, comme Entity Framework , et avec LINQ to Entities, utiliser les fonctionnalités que le langage et le framework vous offrent:
la source
PrintResults(query)
requête générée sera ensuite utilisée dans dapper comme requête !!Un peu exagéré dans ce cas simple, mais j'ai utilisé un code similaire à celui-ci dans le passé.
Créer une fonction
Utilisez-le comme ça
De cette façon, si aucune condition n'est trouvée, vous ne vous souciez même pas de charger une instruction where dans la requête et enregistrez le serveur sql une micro-seconde de traitement de la clause where indésirable lorsqu'il analyse l'instruction sql.
la source
Il existe une autre solution, qui peut également ne pas être élégante, mais qui fonctionne et résout le problème:
Pour:
SELECT * FROM Table1
,SELECT * FROM Table1 WHERE cond1
AND condN
la source
WHERE
s'il n'y a pas de prédicats; le 1 = 1 existe spécifiquement pour éviter cela.String query = "SELECT * FROM Table1";
etstring jointer = " WHERE ";
?WHERE
lesAND
s doivent-ils être placés entre les conditions?string joiner
ligne parstring joiner = " WHERE ";
et laisser lajoiner = " AND ";
ligne seule.Faites quelque chose comme ça:
C'est l' injection SQL sûre et à mon humble avis , c'est assez propre. Le
Remove()
supprime simplement le dernierAND
;Cela fonctionne à la fois si aucune condition n'a été définie, si une seule a été définie ou si plusieurs ont été définies.
la source
conditions != null
c'est toujours le castrue
, car vous l'initialisez avec""
(sauf en C #"" == null
). Cela devrait probablement être un chèque, si ceconditions
n'est pas vide… ;-)Ajoutez simplement deux lignes à l'arrière.
Par exemple
deviendra à
Tandis que
deviendra à
======================================
Merci d'avoir signalé un défaut de cette solution:
"Cela peut interrompre la requête si, pour une raison quelconque, l'une des conditions contient le texte" 1 = 1 AND "ou" WHERE 1 = 1 ". Cela peut être le cas si la condition contient une sous-requête ou tente de vérifier si la colonne contient ce texte, par exemple. Ce n'est peut-être pas un problème dans votre cas, mais vous devriez le garder à l'esprit… "
Afin de se débarrasser de ce problème, nous devons distinguer le "principal" WHERE 1 = 1 et ceux de la sous-requête, ce qui est facile:
Rendez simplement le WHERE "principal" spécial: j'ajouterais un signe "$"
Ensuite, ajoutez toujours deux lignes:
la source
"1=1 AND "
ou" WHERE 1=1 "
. Cela peut être le cas si la condition contient une sous-requête ou tente de vérifier si une colonne contient ce texte, par exemple. Peut-être que ce n'est pas un problème dans votre cas, mais vous devriez le garder à l'esprit…Utilisez ceci:
la source
QuerySub
n'est à mon avis ni meilleure ni pire que l'utilisation duwhere 1=1
hack. Mais c'est une contribution réfléchie.... FROM SOMETABLE WHERE
; alors leTrimEnd
réduirait réellement ceci à... FROM SOMETABL
. Si c'était en fait unStringBuilder
(ce qu'il devrait être si vous avez à propos de cette manipulation de chaînes ou plus), vous pouvez simplementQuery.Length -= "WHERE ".Length;
.Pourquoi ne pas utiliser un générateur de requêtes existant? Quelque chose comme Sql Kata .
Il prend en charge les conditions complexes, les jointures et les sous-requêtes.
il fonctionne avec Sql Server, MySql et PostgreSql.
la source
La solution littérale la plus rapide à ce que vous demandez et à laquelle je puisse penser est la suivante:
Cela ne semble pas élégant, bien sûr, auquel je vous renvoie à la recommandation de CodeCaster d'utiliser un ORM. Mais si vous pensez à ce que cela fait ici, vous ne craignez vraiment pas de «gaspiller» 4 caractères de mémoire, et il est très rapide pour un ordinateur de déplacer un pointeur de 4 places.
Si vous avez le temps d'apprendre à utiliser un ORM, cela pourrait vraiment être rentable pour vous. Mais à ce propos, si vous essayez d'empêcher cette condition supplémentaire d'atteindre la base de données SQL, cela le fera pour vous.
la source
S'il s'agit de SQL Server , vous pouvez rendre ce code beaucoup plus propre.
Cela suppose également un nombre connu de paramètres, ce qui peut être une mauvaise hypothèse lorsque je pense aux possibilités.
En C #, vous utiliseriez:
Et puis côté SQL:
la source
Selon la condition, il peut être possible d'utiliser une logique booléenne dans la requête. Quelque chose comme ça :
la source
J'aime l'interface fluide de stringbuilder, j'ai donc créé des ExtensionMethods.
la source
IMHO, je pense que votre approche est fausse:
Interroger la base de données en concaténant une chaîne n'est JAMAIS une bonne idée (risque d' injection SQL et le code peut facilement être cassé si vous apportez des modifications ailleurs).
Vous pouvez utiliser un ORM (j'utilise NHibernate ) ou au moins utiliser
SqlCommand.Parameters
Si vous voulez absolument utiliser la concaténation de chaînes, j'utiliserais a
StringBuilder
(c'est le bon objet pour la concaténation de chaînes):En dernière analyse,
Where 1=1
c'est vraiment moche mais SQL Server l'optimisera quand même.la source
SELECT * FROM Table1 WHERE AND Col1=0
ne semble pas correct, c'est tout l'intérêt deWHERE 1=1
.Le Dapper SqlBuilder est une très bonne option. Il est même utilisé en production sur StackOverflow.
Lisez l'article de blog de Sam à ce sujet .
Pour autant que je sache, il ne fait partie d'aucun package Nuget, vous devrez donc copier-coller son code dans votre projet ou télécharger la source Dapper et créer le projet SqlBuilder. Dans tous les cas, vous devrez également référencer Dapper pour la
DynamicParameters
classe.la source
Je vois cela utilisé tout le temps dans Oracle lors de la création de SQL dynamique dans des procédures stockées . Je l'utilise dans les requêtes tout en explorant les problèmes de données, simplement pour passer plus rapidement entre différents filtres de données ... Il suffit de commenter une condition ou de la rajouter facilement.
Je trouve que c'est assez courant et assez facile à comprendre pour quelqu'un qui examine votre code.
la source
Réalisation avec des méthodes d'extension.
la source
En utilisant la
string
fonction, vous pouvez également le faire de cette façon:Personnellement, je me sens facile de supprimer le ou les éléments conditionnels à la fin, car sa position est facile à prévoir.
la source
J'ai pensé à une solution qui, eh bien, est peut-être un peu plus lisible:
Je ne suis tout simplement pas sûr que l'interpréteur SQL optimisera également la
Col1 = Col1
condition (imprimée lorsquecondition1
est false).la source
Voici une manière plus élégante:
la source
Comme cela a été dit, créer du SQL par concaténation n'est jamais une bonne idée . Pas seulement à cause de l'injection SQL. Surtout parce que c'est juste moche, difficile à entretenir et totalement inutile . Vous devez exécuter votre programme avec trace ou débogage pour voir quel SQL il génère. Si vous utilisez QueryFirst (clause de non-responsabilité: ce que j'ai écrit), la tentation malheureuse est supprimée et vous pouvez directement le faire en SQL.
Cette page a une couverture complète des options TSQL pour ajouter dynamiquement des prédicats de recherche. L'option suivante est pratique dans les situations où vous souhaitez laisser le choix des combinaisons de prédicats de recherche à votre utilisateur.
QueryFirst vous donne C # null à db NULL, vous appelez donc simplement la méthode Execute () avec des valeurs nulles le cas échéant, et tout fonctionne simplement. <opinion> Pourquoi les développeurs C # sont-ils si réticents à faire des choses en SQL, même si c'est plus simple? Mind boggles. </opinion>
la source
Pour les étapes de filtrage plus longues, StringBuilder est la meilleure approche, comme beaucoup le disent.
sur votre cas, j'irais avec:
la source
Concis, élégant et doux, comme le montre l'image ci-dessous.
la source