web-dev-qa-db-ja.com

Access SQLでのエスケープ

私は次のようなものでVBAでドメインルックアップを実行しようとしています:

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

これは、アポストロフィが単一引用符であると見なされるtxtVillageがDillon's Bayのようなものになるまで正常に機能し、実行時エラーが発生します。

一重引用符をエスケープする簡単な関数を作成しました-「」を「」に置き換えます。これはかなり頻繁に現れるもののようですが、同じことをする組み込み関数への参照を見つけることができません。私は何かを見逃しましたか?

21
inglesp

「置換」機能でうまくいくはずです。上記のコードに基づいて:

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

DLookupなどの省略形のドメイン関数は魅力的ですが、欠点があります。同等のJet SQLは次のようなものです

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

一致する候補が複数ある場合、「最初」の候補が選択されます。「最初」の定義は実装(SQLエンジン)に依存し、Jet/ACEエンジンIIRCには未定義です。どちらが最初になるか知っていますか?しない場合は、DLookupを避けてください。

[興味深いことに、Jet/ACEの回答は、データベースファイルが最後に圧縮されたときのクラスター化インデックスに基づく最小値、またはデータベースが一度も圧縮されていない場合は最初の(有効な時間)挿入値になります。クラスター化インデックスは、存在しない場合はPRIAMRY KEYによって決定され、そうでない場合はNOT NULL列に定義されたUNIQUE制約またはインデックス、そうでない場合は最初の(有効な時間)挿入された行。クラスタリングに使用されるNOT NULL列に複数のUNIQUE制約またはインデックスが定義されている場合はどうなりますか?わからない!方法を知っていても、「最初」を判断するのは容易ではないという考えが得られると信じています。]

最適化の観点からドメイン集約関数を使用しないようにするためのマイクロソフトからのアドバイスも見ました。

Accessデータベースでのクエリパフォーマンスに関する情報 http://support.Microsoft.com/kb/209126

「DLookup関数などのドメイン集計関数の使用は避けてください... Jetデータベースエンジンは、ドメイン集計関数を使用するクエリを最適化できません。」

クエリを使用して書き換える場合は、PARAMETERS構文を利用できます。または、Jet 4.0/ACE PROCEDURE構文を使用することもできます。何かのようなもの

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
       );

このようにして、エンジン自体の機能、または少なくともデータプロバイダーの機能を使用して、必要に応じてすべての文字(二重引用符や単一引用符だけでなく)をエスケープできます。

3
onedaywhen

それはあなたが考えるよりも悪いです。誰かがこのような値を入力し、何もエスケープしていない場合はどうなるか考えてみてください。

'); DROP TABLE [YourTable]

きれいじゃない。

単にアポストロフィをエスケープする組み込み関数がない理由は、これを処理する正しい方法がクエリパラメータを使用することであるからです。 Ole/Accessスタイルのクエリの場合、これをクエリ文字列として設定します。

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

そして、パラメータを個別に設定します。ただし、vbaからパラメーター値を設定する方法はわかりません。

3
Joel Coehoorn

Joel Coehoornが提案するようなパラメーター化されたクエリは、クエリ文字列で連結を行う代わりに、進むべき道です。 1つ目は特定のセキュリティリスクを回避すること、2つ目はそれがエンジン自身の手にエスケープすることを合理的に確信しており、そのことについて心配する必要はありません。

1
Gnudiff

しかし、それは次のようになります(それぞれ1つずつ二重引用符で囲みます)。

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

または私が好むもの:

単一引用符をエスケープする関数を作成します。「[]」を使用した「エスケープ」では、これらの文字を文字列に含めることができないためです...

Public Function fncSQLStr(varStr As Variant) As String

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

End Function

SELECT、INSERT、UPDATEなどのすべてのSQLクエリで(そしてWHERE句でも...)この関数を使用します。

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

または

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

アクセスにはChr $(34)を使用でき、喜んで単一引用符/アポストロフィを中に含めることができると思います。
例えば

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

ただし、chr $(34)をエスケープする必要があります( ")

置換機能を使用できます。

Dim escapedString as String

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

アポストロフィが含まれる可能性のある基準を大括弧で囲みます。

何かのようなもの:

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

次のように、単一引用符の外、またはtxtVillageの前後に配置する必要があります。

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

しかし、正しい組み合わせを見つければ、アポストロフィが処理されます。

キースB

0
keith b

単一引用符と置換機能に問題がある場合は、この行で1日を節約できます^ o ^

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

ちなみに、これが私の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