Anti-FAQ: Jak wywoływać kwerendy parametryczne?
 

Gdy wywołujemy naszą kwerendę parametryczną metodą DoCmd.OpenQuery lub za pomocą bezpośredniego wywołania jej łańcucha SQL DoCmd.RunSQL nie ma problemu - takie zapytanie dobrze rozumie nasze odwołania typu Forms!Form1!Pole1. Ale kto próbował otwierać kwerendy parametryczne w kodzie, ten dobrze zna poniższy komunikat:

Błąd wykonania '3061': Za mało parametrów. Oczekiwano 2.

Błąd pojawia się podczas takich operacji jak:

No dobrze, ale jak sobie z tym radzić?

Metoda 1 (bezpośrednie wyliczenie parametru):

Postać SQL naszego zapytania budujemy dynamicznie w kodzie procedury:

CurrentDb.Execute "SELECT * FROM Query1 WHERE ID=" & Forms!Form1!FiltrID

UWAGA: W powyższym przykładzie założyłem, że pole ID jest typu numerycznego. Dla innych typów danych są odmienne standardy odwoływania się do parametru  filtru, np. dla daty należy napisać tak:

CurrentDb.Execute "SELECT * FROM Query1 WHERE Data1=CDate('" & Forms!Form1!FiltrData1 & "')"

Zakładam, że zasady budowania filtrów dla różnych typów danych są znane i zagadnienie to nie jest przedmiotem niniejszego opracowania, aczkolwiek również ma swoje problemy (patrz punkt nr 5 w niniejszym dziale zatytułowany: Jak znaleźć Morse'a, czyli problem cudzysłowów w polach tekstowych?).

Metoda 2! (listowanie parametrów):

Sposób podał Krzysztof Naworyta (k.naworyta@datacomp.com.pl).  Okazuje się, że wystarczy przerzucić na access'a wyliczenie tych parametrów, przy pomocy funkcji Eval(), a problem znika! Oto przykład praktycznej realizacji tego pomysłu:

Dim q As QueryDef, p As Parameter, rs As Recordset
    Set q = CurrentDb.QueryDefs("QueryParam")
    'lub dla kwerendy tymczasowej
    'Set q = CurrentDb.CreateQueryDef("","SELECT * FROM Query1 WHERE ID=Forms!Form1!FiltrID")
    For Each p In q.Parameters
        p.Value = Eval(p.Name)
    Next
    Set rs = q.OpenRecordset()
    'tu robimy dowolne operacje na rs
    Set rs = Nothing
    Set q = Nothing

To bardzo wygodna i elegancka metoda.

Dopisek KN

Skąd się bierze główny problem? Powłoka Access'a wykorzystuje DAO jako swoją główną bibliotekę dostępu do Jet'a, ale DAO nie wykorzystuje Access'a (!)
DAO jest uniwersalną biblioteką, którą można wykorzystać w dowolnym środowisku programistycznym, nawet tam gdzie access'a w ogóle nie ma.
Dlatego właśnie coś takiego jak access'owe Forms!Formularz1!Pole0 jest dla DAO kompletnie niezrozumiałe.
Na szczęście pisząc nasz kod w accessie, możemy użyć access'ową fukcję Eval(), dla której zbitka tekstowa "Forms!Formularz1!Pole1" nie stanowi tajemnic, a która dla DAO jest tylko nazwą nieznanego parametru.

Oczywiście, jeśli nasza kwerenda zawiera inne parametry, nie będące odwołaniem do pól formularzy (czy raportów, jeśli jakimś cudem miałoby to sens ;-) ), to wartości tych paramerów musimy nadać bezpośrednio:

   If Not p.name like "forms*" then
     p.Value  = 3.14
   End if

/Dopisek KN - koniec.

Metoda 3! (z użyciem funkcji Eval):

Ostatnia metoda jest najprostsza w zastosowaniu. Wystarczy wszystkie parametry w kwerendzie zapisać w postaci:
Eval("[Forms]![Tabela1]![Tekst2]"), a problem znika sam.
A jeśli już piszę kto podał, to... metody jeszcze nigdzie nie spotkałem, wiec ją przypisuję sobie.

K. P.