web-dev-qa-db-fra.com

Échappement 'dans Access SQL

J'essaie de faire une recherche de domaine dans vba avec quelque chose comme:

DLookup("island", "villages", "village = '" & txtVillage & "'")

Cela fonctionne bien jusqu'à ce que txtVillage ressemble à Dillon's Bay, lorsque l'apostrophe est considéré comme une citation unique et que j'obtiens une erreur d'exécution.

J'ai écrit une fonction triviale qui échappe aux guillemets simples - elle remplace "'" par "". Cela semble être quelque chose qui arrive assez souvent, mais je ne trouve aucune référence à une fonction intégrée qui fait la même chose. Ai-je raté quelque chose?

19
inglesp

La fonction "Remplacer" devrait faire l'affaire. Basé sur votre code ci-dessus:

DLookup("island", "villages", "village = '" & Replace(txtVillage, "'", "''") & "'")
18
Matt

Bien que les fonctions de domaine abrégées telles que DLookup soient tentantes, elles ont leurs inconvénients. L'équivalent Jet SQL est quelque chose comme 

SELECT FIRST(island)
FROM villages
WHERE village = ?;

Si vous avez plus d'un candidat correspondant, il choisira le "premier", la définition de "premier" est dépendante de l'implémentation (moteur SQL) et non définie pour le moteur IIRC des moteurs Jet/ACE. Savez-vous lequel serait le premier? Si vous ne vous écartez pas de DLookup :) 

[Il est intéressant de noter que la réponse de Jet/ACE sera soit la valeur minimale basée sur l'index clusterd au moment du dernier compactage du fichier de base de données, soit la première valeur (heure valide) insérée si la base de données n'a jamais été compactée. La clé PRIAMRY KEY détermine à son tour l’index clusterisé, sinon une contrainte UNIQUE ou un index défini sur des colonnes NOT NULL, sinon la première ligne insérée (heure de validité). Que se passe-t-il si plusieurs contraintes ou index UNIQUE sont définis sur des colonnes NOT NULL, lequel serait utilisé pour la mise en cluster? Je n'en ai aucune idée! J'espère que vous avez l'idée qu'il n'est pas facile de déterminer le «premier», même si vous savez comment faire!]

J'ai également consulté Microsoft pour éviter d'utiliser les fonctions d'agrégat de domaine du point de vue de l'optimisation:

Informations sur les performances des requêtes dans une base de données Access http://support.Microsoft.com/kb/209126

"Évitez d'utiliser des fonctions d'agrégat de domaine, telles que la fonction DLookup ... le moteur de base de données Jet ne peut pas optimiser les requêtes utilisant des fonctions d'agrégat de domaine"

Si vous choisissez de réécrire à l'aide d'une requête, vous pouvez alors tirer parti de la syntaxe PARAMETERS. Vous pouvez également préférer la syntaxe Jet 4.0/ACE PROCEDURE, par exemple. quelque chose comme

CREATE PROCEDURE GetUniqueIslandName
(
   :village_name VARCHAR(60)
)
AS 
SELECT V1.island_name
  FROM Villages AS V1
 WHERE V1.village_name = :village_name
       AND EXISTS 
       (
        SELECT V2.village_name
          FROM Villages AS V2
         WHERE V2.village_name = V1.village_name
         GROUP 
            BY V2.village_name
        HAVING COUNT(*) = 1
       );

De cette façon, vous pouvez utiliser les fonctionnalités du moteur - ou au moins celles de ses fournisseurs de données - pour échapper à tous les caractères (pas simplement les guillemets simples et doubles) selon les besoins.

3
onedaywhen

C'est pire que tu ne le penses. Pensez à ce qui se passerait si quelqu'un entrait une valeur telle que celle-ci et que vous n'échappiez rien:

'); DROP TABLE [YourTable]

Pas beau.

La raison pour laquelle il n’existe pas de fonction intégrée permettant simplement d’échapper à une apostrophe tient au fait que la bonne façon de gérer cela consiste à utiliser des paramètres de requête. Pour une requête de style Ole/Access, vous devez définir ceci comme chaîne de requête:

DLookup("island", "village", "village = ? ")

Et puis définissez le paramètre séparément. Je ne sais pas comment vous allez définir la valeur du paramètre de vba, cependant.

3
Joel Coehoorn

Les requêtes paramétrées telles que suggérées par Joel Coehoorn sont la meilleure solution, au lieu d'effectuer la concaténation dans une chaîne de requête. Premièrement - évite certains risques pour la sécurité, deuxièmement - je suis raisonnablement certain que cela prend entre les mains du moteur et vous n'avez pas à vous en préoccuper. 

1
Gnudiff

Mais alors, ça devrait être comme ça (avec une autre citation double chacun):

sSQL = "SELECT * FROM tblTranslation WHERE fldEnglish=""" & myString & """;"

Ou ce que je préfère:

Créez une fonction pour échapper aux guillemets simples, car "échapper" avec "[]" n'autoriserait pas ces caractères dans votre chaîne ...

Public Function fncSQLStr(varStr As Variant) As String

If IsNull(varStr) Then
        fncSQLStr = ""
    Else
        fncSQLStr = Replace(Trim(varStr), "'", "''")
    End If

End Function

J'utilise cette fonction pour toutes mes requêtes SQL, comme SELECT, INSERT et UPDATE (ainsi que dans la clause WHERE ...)

strSQL = "INSERT INTO tbl" & 
    " (fld1, fld2)" & _
    " VALUES ('" & fncSQLStr(str1) & "', '" & fncSQLStr(Me.tfFld2.Value) & "');"

ou

strSQL = "UPDATE tbl" & _
    " SET fld1='" & fncSQLStr(str1) & "', fld2='" & fncSQLStr(Me.tfFld2.Value) & "'" & _
    " WHERE fld3='" & fncSQLStr(str3) & "';"
1
user2497464

Je crois que l’accès peut utiliser Chr $ (34) et contient heureusement des guillemets simples/apostrophes.
par exemple 

DLookup("island", "villages", "village = " & chr$(34) & nonEscapedString & chr$(34))

Bien que vous deviez alors échapper à la chr $ (34) (")

Vous pouvez utiliser la fonction Remplacer. 

Dim escapedString as String

escapedString = Replace(nonescapedString, "'", "''")
1
Rob Gray

mettez des parenthèses autour des critères pouvant contenir une apostrophe.

Quelque chose comme:

DLookup("island", "villages", "village = '[" & txtVillage & "]'")

Ils pourraient avoir besoin d’être en dehors des guillemets simples ou juste autour de txtVillage comme:

DLookup("island", "villages", "village = '" & [txtVillage] & "'")

Mais si vous trouvez la bonne combinaison, cela prendra soin de l'apostrophe.

Keith B

0
keith b

Pour ceux qui ont des problèmes avec les guillemets simples et la fonction Remplacer, cette ligne peut vous faire gagner du temps ^ o ^

Replace(result, "'", "''", , , vbBinaryCompare)
0
niceboomer

Au fait, voici ma fonction EscapeQuotes

Public Function EscapeQuotes(s As String) As String

    If s = "" Then
        EscapeQuotes = ""
    ElseIf Left(s, 1) = "'" Then
        EscapeQuotes = "''" & EscapeQuotes(Mid(s, 2))
    Else
        EscapeQuotes = Left(s, 1) & EscapeQuotes(Mid(s, 2))
    End If

End Function
0
inglesp