La question initiale était "Comment dois-je paramétrer une requête ..."
Permettez-moi de préciser ici, que ce n'est pas une réponse à la question d'origine. Il y a déjà quelques démonstrations de ce que dans les autres bonnes réponses.
Cela dit, aller de l'avant et le drapeau de cette réponse, downvote, le marquer comme non pas une réponse... faire ce que vous pensez est juste.
Voir la réponse de Mark Brackett pour la meilleure réponse que j'ai (et 231 autres) upvoted. L'approche adoptée dans sa réponse permet 1) pour l'utilisation efficace de lier les variables, et 2) pour les prédicats qui sont sargable.
Réponse sélectionnée
Ce que je veux aborder ici est l'approche adoptée dans Joel Spolsky de la réponse, la réponse "sélectionné" que le droit de réponse.
Joel Spolsky approche est intelligent. Et il fonctionne raisonnablement, il va présentent un comportement prévisible et des performances prévisibles, compte tenu de la "normale" valeurs", et avec le normatif des cas limites, comme NULLE, et la chaîne vide. Et il peut être suffisant pour une application particulière.
Mais en termes de généraliser cette approche, mais nous considérons également la plus coin obscur cas, comme lorsque l' Name
colonne contient un caractère générique (tel que reconnu par le prédicat LIKE.) Le caractère générique je vois le plus souvent utilisé est l' %
(un signe de pourcentage.). Donc, nous allons en traiter ici, maintenant, et plus tard passer à d'autres cas.
Quelques problèmes avec le caractère %
Considérons un Nom de valeur de 'pe%ter'
. (Pour les exemples ici, j'utilise un littéral de chaîne de valeur en lieu et place du nom de la colonne.) Une ligne avec une valeur de Nom de `pe%ter " seraient retournés par une requête de la forme:
select ...
where '|peanut|butter|' like '%|' + 'pe%ter' + '|%'
Mais cette même ligne pourront pas être retournés si l'ordre des mots est inversé:
select ...
where '|butter|peanut|' like '%|' + 'pe%ter' + '|%'
Le comportement que nous observons est bizarre. Modification de l'ordre des termes de recherche dans la liste des modifications de l'ensemble de résultats.
Il va presque sans dire que nous ne voulons pas pe%ter
de match de beurre d'arachide, peu importe combien il l'aime.
Coin obscur cas
(Oui, je suis d'accord que c'est une obscure affaire. Probablement l'un qui n'est pas susceptible d'être testé. On ne s'attendrait pas d'un caractère générique dans la valeur d'une colonne. On peut supposer que l'application empêche une telle valeur d'être stocké. Mais dans mon expérience, j'ai rarement vu une contrainte de base de données spécifiquement des caractères non autorisés ou des motifs qui seraient considérés comme des caractères génériques sur le côté droit de l' LIKE
opérateur de comparaison.
Patcher un trou
Une approche à colmater ce trou est d'échapper à l' %
caractère générique. (Pour quiconque n'est pas familier avec la clause de sauvegarde sur l'opérateur, voici un lien vers la documentation de SQL Server.
select ...
where '|peanut|butter|'
like '%|' + 'pe\%ter' + '|%' escape '\'
Maintenant, nous pouvons comparer les littéral %. Bien sûr, quand on a un nom de colonne, nous allons avoir besoin de dynamique d'échapper le caractère générique. Nous pouvons utiliser l' REPLACE
, afin de rechercher des occurrences de l' %
personnage et insérer une barre oblique inverse devant chacun, comme ceci:
select ...
where '|pe%ter|'
like '%|' + REPLACE( 'pe%ter' ,'%','\%') + '|%' escape '\'
Si cela résout le problème avec le générique%. Presque.
Échapper au échapper
Nous reconnaissons que notre solution a présenté un autre problème. Le caractère d'échappement. Nous voyons que nous allons aussi avoir besoin d'échapper à toutes les occurrences d'un caractère d'échappement lui-même. Cette fois, nous utilisons la ! comme le caractère d'échappement:
select ...
where '|pe%t!r|'
like '%|' + REPLACE(REPLACE( 'pe%t!r' ,'!','!!'),'%','!%') + '|%' escape '!'
Le trait de soulignement trop
Maintenant que nous sommes sur une lancée, nous pouvons ajouter une autre REPLACE
gérer le trait de soulignement générique. Et juste pour le fun, cette fois, nous allons utiliser $ comme caractère d'échappement.
select ...
where '|p_%t!r|'
like '%|' + REPLACE(REPLACE(REPLACE( 'p_%t!r' ,'$','$$'),'%','$%'),'_','$_') + '|%' escape '$'
Je préfère cette approche s'échapper, car il travaille dans Oracle et MySQL ainsi que SQL Server. (J'ai l'habitude d'utiliser le \ barre oblique inverse comme caractère d'échappement, puisque c'est le personnage que nous utilisons dans les expressions régulières. Mais pourquoi être contraint par la convention!
Ces satanés crochets
SQL Server permet également des caractères génériques pour être traités comme des littéraux en les enfermant dans des crochets []
. Nous ne sommes donc pas fait de fixation encore, au moins pour SQL Server. Comme les paires de crochets ont une signification spéciale, nous aurons besoin d'échapper à ceux aussi bien. Si nous parvenons à sortir correctement des parenthèses, puis au moins on n'aura pas à s'embêter avec le tiret -
et le carat ^
dans les crochets. Et nous pouvons laisser tout %
et _
entre parenthèses échappé, puisque nous allons avoir désactivé la signification spéciale des crochets.
Trouver des paires de crochets ne devrait pas être difficile. C'est un peu plus difficile de gérer les occurrences de singleton % "et"_". (Notez qu'il ne suffit pas de juste d'échapper à toutes les occurrences de crochets, car un singleton support est considéré comme un littéral, et n'a pas besoin d'être échappé. La logique est un peu plus floue que je peux gérer sans courir le plus de cas de test.)
Inline expression devient malpropre
Que inline expression dans le SQL est de plus en plus longues et de plus laid. On peut probablement le faire fonctionner, mais ciel, à l'aide de la pauvre âme qui vient par derrière et a de le déchiffrer. En tant que fan je suis pour les expressions, je suis enclin à ne pas utiliser une ici, principalement parce que je ne veux pas avoir à laisser un commentaire expliquant la raison de la pagaille, et s'excuser pour cela.
Une fonction où ?
Bon, alors, si nous ne gérons pas que comme une ligne d'expression dans le SQL, le plus proche de la solution que nous avons est une fonction définie par l'utilisateur. Et nous savons que de ne pas accélérer les choses tout (à moins que nous pouvons définir un index sur elle, comme nous avons pu avec Oracle.) Si nous avons pour créer une fonction, nous pourrions mieux faire que dans le code qui appelle l'instruction SQL.
Et qu'une fonction peut avoir quelques différences dans le comportement, dépendant du SGBD et la version. (Un shout out à tous les développeurs Java tellement envie d'être en mesure d'utiliser tout moteur de base de données de façon interchangeable.)
La connaissance du domaine
Nous pouvons avoir des connaissances du domaine pour la colonne, (c'est l'ensemble des valeurs admissibles appliquée pour la colonne. Nous savons a priori que les valeurs stockées dans la colonne ne comprendront jamais un signe de pourcentage, un trait de soulignement, ou support de paires. Dans ce cas, nous avons simplement inclure un commentaire rapide que ces cas sont couverts.
Les valeurs stockées dans la colonne peut autoriser % ou _ personnages, mais une contrainte peut exiger de ces valeurs pour être échappé, peut-être l'aide d'un caractère définis, tels que les valeurs sont des valeurs de comparaison "safe". Encore une fois, un rapide commentaire sur le jeu autorisé de valeurs, et en particulier le caractère qui est utilisé comme un caractère d'échappement, et d'aller avec Joel Spolsky de l'approche.
Mais, en l'absence de la connaissance spécialisée et d'une garantie, il est important pour nous d'envisager la gestion de coin obscur de cas, et d'examiner si le comportement est raisonnable et "par le cahier des charges".
D'autres questions récapitulé
Je crois que d'autres ont déjà suffisamment souligné quelques-uns des autres communément considérés comme des domaines de préoccupation:
SQL injection (prendre ce qui semble être fourni par l'utilisateur de l'information, et notamment que, dans le texte SQL plutôt que de leur fournir par le biais de lier les variables. À l'aide de variables de liaison n'est pas obligatoire, c'est juste une approche pratique pour contrecarrer avec injection SQL. Il y a d'autres façons de traiter avec elle:
l'optimiseur de plan à l'aide d'analyse d'index plutôt que de l'indice vise, au besoin éventuel d'une expression ou de la fonction pour échapper les caractères génériques (indice possible sur l'expression ou de la fonction)
l'utilisation de valeurs littérales en place de lier les variables impacts de l'évolutivité
Conclusion
J'aime Joel Spolsky de l'approche. Il est intelligent. Et il fonctionne.
Mais dès que j'ai vu, j'ai tout de suite vu un problème potentiel avec elle, et ce n'est pas ma nature de le laisser glisser. Je ne veux pas être critique sur les efforts des autres. Je sais que beaucoup de développeurs prennent leur travail très personnellement, parce qu'ils investissent tellement dans et ils tiennent tellement à son sujet. Donc, s'il vous plaît comprendre, ce n'est pas une attaque personnelle. Ce que je suis à identifier ici est le type de problème que l'on rencontre dans la production plutôt que de tester.
Oui, je suis allé au-delà de la question d'origine. Mais où d'autre de laisser cette remarque à propos de ce que je considère être un problème important avec les "sélectionnés" répondre à une question?
Mon espoir est que quelqu'un va trouver ce post pour être de quelque utilité.
Excuses
Encore une fois, je ne m'excuse pour mon incapacité à respecter les règles et les conventions de Débordement de Pile, de poster ici ce n'est clairement pas une réponse à la discussion de la question.