Grupy dyskusyjne Google nie obsługują już nowych postów ani subskrypcji z Usenetu. Treści historyczne nadal będą dostępne.

Multiselect a warunek kwerendy.

16 wyświetleń
Przejdź do pierwszej nieodczytanej wiadomości

Piotr Lipski

nieprzeczytany,
24 paź 2003, 10:42:0924.10.2003
do
Problem jest prościutki i już go rozwiązałem, ale mam wrażenie, że
nieoptymalnie.
Czy da się eleganciej jakoś?

Jest tak:
Kwerenda wybiera rekordy.
(zadziwiające, no nie?)

Jedym z warunków jest, żeby ID rekordu znajdowało się na liście typu
multiselect (a konkretnie z właściwością Multiselect ustawioną na
"Extended")
Czyli mam listę wielokrotnego wyboru i chcę odfiltrować te rekordy, których
ID znajdują się wśród "wartości" listy.
("Wartości" piszę w cudzysłowie, bo wartością takiej listy jest w
rzeczywistości zawsze Null)

Moje rozwiązanie jest takie, że napisałem sobie funkcję, która dostaje na
wejście ID rekordu, przegląda sobie kolekcję ItemsSelected listy i jak
znajdzie id rekordu wśród pozycji wybranych, zwraca -1, a jak nie znajdzie,
zwraca 0. Działa, ale wymaga napisania funkcji i użycia jej w kwerendzie.
Można jakoś eleganciej?

--
PL


Tomasz Kalbarczyk

nieprzeczytany,
24 paź 2003, 11:00:1224.10.2003
do
> Moje rozwiązanie jest takie, że napisałem sobie funkcję, która dostaje na
> wejście ID rekordu, przegląda sobie kolekcję ItemsSelected listy i jak
> znajdzie id rekordu wśród pozycji wybranych, zwraca -1, a jak nie
znajdzie,
> zwraca 0. Działa, ale wymaga napisania funkcji i użycia jej w kwerendzie.
> Można jakoś eleganciej?


Hej.

Ja rozwiazalem to nieco inaczej - jak buduje selecta to przegladam kolekcję
ItemsSelected, ale buduje sobie z nich ciag x,y,z - ktory nastepnie
wykorzystuje w warunku in ( i tutaj moja lista) zapytania.

pzdr.
Tomek


Krzysztof Naworyta

nieprzeczytany,
24 paź 2003, 17:11:1024.10.2003
do
Juzer Piotr Lipski <xp...@nie.spamuj.interia.bo.pl.w.ryj> napisał

Też zawsze mnie niepokoiła niemożność efektywnego sparametryzowania
warunku "In (...)"
Owszem, przy pomocy funkcji Eval można napisać warunek:

(...)
Where
Eval([ID] & " In " & fLst()) = True

gdzie fLst:

Function fLst()
Dim strItems As String
Dim varItem As Variant
Dim lst As Access.ListBox

Set lst = Forms!frmList!Lista0

With lst
For Each varItem In lst.ItemsSelected
strItems = strItems & "," & lst.ItemData(varItem)
Next
If Len(strItems) > 0 Then
strItems = Mid(strItems, 2)
Else
strItems = "0"
End If
End With
fLst = "(" & strItems & ")"
End Function

ale nie czarujmy się ! Jet musi każdorazowo pobrać wartość pola, następnie
przekazać ją do funkcji Eval (dość chybotliwej) i porównać w wyrażeniu "In
(....)"
Indeksy i tak szlag trafił! Czyli efekt taki sam albo gorszy jak przy
wykorzystaniu Twojej funkcji.

Ale jest jeszcze inne "In", bardziej naturalne dla Jeta i z indeksami !

1. kwerenda:

SELECT * FROM mojaTabela As T
WHERE
Exists (Select ID From tmp Where tmp.ID=T.ID) =
List2Table("tmp", "frmList", "Lista0")

2. funkcja List2Table:

Function List2Table(tmpTbN As String, frmN As String, lstN As String) As
Boolean
Dim strItems As String
Dim varItem As Variant
Dim ws As Workspace
Dim db As Database
Dim lst As Access.ListBox
Dim wsp As Currency
Dim i As Long

On Error GoTo err_exit

Set lst = Forms(frmN)(lstN)

Set ws = DBEngine(0)
ws.BeginTrans

Set db = CurrentDb
db.Execute "Delete From " & tmpTbN

With lst
wsp = .ItemsSelected.Count / .ListCount

If wsp < 0.5 Then
For Each varItem In lst.ItemsSelected
db.Execute "Insert Into " & tmpTbN & " (ID) Values(" &
lst.ItemData(varItem) & ")"
Next
Else
For i = 0 To .ListCount - 1
If .Selected(i) = False Then
db.Execute "Insert Into " & tmpTbN & " (ID) Values(" &
.ItemData(i) & ")"
End if
Next
End If
End With

ws.CommitTrans

List2Table = (wsp < 0.5)
Exit Function
err_exit:
If Not ws Is Nothing Then
ws.Rollback
End If
MsgBox Err.Description
End Function


3. uwagi:

tabela "tmp" (pierwszy parametr funkcji) musi już wcześniej istnieć w
bazie! Nie da się jej utworzyć "on fly" (jest to pewnego rodzaju minus)
Jako parametr została dołożona w zasadzie jedynie dla przejrzystości
SQL'a, ale też dzięki temu możemy użyć kilku takich pomocniczych tabel,
nawet w jednej kwerendzie.

Z moich testów wynika, że opłaca się w tej tabeli ustawić indeks na polu
ID (unikalny? - to zależy od listy)
Dla nawet maksymalnego wyboru na liście (połowa zaznaczeń) opóźnienie
poprzez n-insertów jest rekompensowane szybkością wyliczenia warunku
"Exists"

Z tych samych powodów co powyżej z tabelą, nie da się indeksu uprzednio
dropnąć a na
końcu funkcji ponownie założyć, bo tabela tmp jest już blokowana drugim
warunkiem:
Exists (Select ID From tmp Where tmp.ID=T.ID)

Trochę to zagmatwane w porównaniu z tworzeniem wyrażenia SQL w kodzie, ale
wydaje się że nie całkiem pozbawione sensu ...
Tym bardziej jeśli w liście zaznaczyć dużo ;-)

4. W zależności ile tych itemów jest zaznaczonych funkcja zwraca true
(szukaj pasujących do tabeli) lub false (szukaj niepasujących).
Dlatego maksymalne opóźnienie w wyliczeniu kwerendy nastąpi przy
zaznaczeniu połowy listy!

5. Na formularzy warto w przypadku długich list dołożyć pole wyliczane:
=Lista0.ListCount
aby pełnego wypełnienia nie musiała dokonywać funkcja List2Table()

PS.
Jeśli ktoś nie rozumie dlaczego moja funkcja miała by być lepsza od
funkcji Piotra, to śpieszę z wyjaśnieniem:
Moja funkcja pobiera _stałe_ parametry (niezależne od pól wykorzystywanych
w kwerendzie), więc wykonana zostanie raz !
Resztę (warunek "Exists") Jet sobie zoptymalizuje.
Testowane na a'97 i a'2k.

PS.2
Wszelkie uwagi i spostrzeżenia mile widziane (także krytyczne)

--
KN

archiwum grupy:
http://groups.google.pl/advanced_group_search?&as_ugroup=pl*msaccess


kw:
- itemsSelected, lista, kwerenda, filtrowanie, multiwybór, multiselect

Nowe wiadomości: 0