24

次のような方法で、vba でドメイン ルックアップを実行しようとしています。

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

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

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

4

10 に答える 10

25

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

DLookup("island", "villages", "village = '" & Replace(txtVillage, "'", "''") & "'")
于 2008-10-14T03:21:28.327 に答える
3

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

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

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

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

また、最適化の観点からドメイン集約関数の使用を避けるようにという Microsoft のアドバイスも見ました。

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

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

于 2008-10-14T08:04:09.003 に答える
3

思ったより悪いです。誰かが次のような値を入力し、何もエスケープしていないとしたらどうなるか考えてみてください:

'); DROP TABLE [YourTable]

かわいくない。

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

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

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

于 2008-10-14T03:14:18.760 に答える
1

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

于 2009-01-04T09:12:01.327 に答える
1

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

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

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

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

Dim escapedString as String

escapedString = Replace(nonescapedString, "'", "''")
于 2008-10-14T03:22:15.360 に答える
0

一重引用符と置換機能に問題がある人は、この行で問題が解決するかもしれません ^o^

Replace(result, "'", "''", , , vbBinaryCompare)
于 2010-02-25T02:28:01.757 に答える
0

ところで、これが私の 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
于 2008-10-14T03:16:13.453 に答える
-2

私の解決策ははるかに簡単です。最初は、次の SQL 式を使用して ADO レコードセットを作成しました。

Dim sSQL as String
sSQL="SELECT * FROM tblTranslation WHERE fldEnglish='" & myString & "';"

myStringInt'l Electrics のようにアポストロフィが含まれていると、私のプログラムは停止します。二重引用符を使用すると問題が解決しました。

sSQL="SELECT * FROM tblTranslation WHERE fldEnglish="" & myString & "";"
于 2013-06-14T18:26:05.900 に答える