Workaround: BLOBs in ValueItemList dekodieren
Verfasst: Fr 23. Sep 2011, 16:14
Für schnelles Suchen nach Datensätzen im Sinne einer einengenden Suche ist ein Listenfeld, in dessen sichtbarer Spalte 1 man alle denkbaren Suchbegriffe aneinanderreiht und in der unsichtbaren Spalte 2 ein geeignetes WHERE-Kriterium (z.B. zum Filtern eines Tabellen-Kontrollfeldes) ablegt, recht praktisch.
Daß man das Listenfeld dazu in Base zwangsweise an eine Tabelle binden muß, die dann eben keinen Bezug zur eigentlichen Datenbank hat und nur einen Datensatz aufweist (in dem immer der letzte Suchterm steht), damit kann man auch noch leben.
Damit das ganze ordentlich schnell funktioniert, nimmt man, wenn die Daten ohnehin schon in einer mysql-Datenbank stecken, statt einer lokalen Abfrage in base besser eine Sicht ("view") in mysql, die sich mit der mysql-workbench sehr komfortabel anlegen und pflegen läßt.
Ein (stark gekürztes) Beispiel zur Illustration:
In diesem Beispiel heißt die im Listenfeld angezeigte Spalte "display" und ermöglicht die Suche eines Lieferscheins nach Rechnungsnummer, Lieferscheinnummer oder -Datum (analog kann man Bestellnummern, Bezugsquellen und vieles mehr hinzufügen), indem die unsichtbare Spalte "wc" ein geeignetes WHERE-Kriterium vorhält.
Schwieriger wird es dann, wenn man feststellt, daß (aus mir bislang unerfindlichen Gründen auch auf einem überall auf UTF8 justierten System) mysql an Stelle von Text Binär-BLOBs zurückliefert; das zeigt sich z.B. in phpmyadmin, wo man die Texte durch die Option "Blob-Inhalte anzeigen" immerhin doch zu Gesicht bekommt. Betrachtet man die Sicht direkt über Ansicht/Datenbankobjekte/Tabellen, wo sie wie eine normale Tabelle erscheint, enthalten alle Felder nur "<OBJEKT>".
Benutzt man sie nun als Datenquelle ("Listeninhalt") für ein Listenfeld, so werden erfreulicherweise die Daten für Spalte 0 ("display") korrekt angezeigt. Doch das an sich bewährte Makro zum Filtern eines Tabellen-Kontrollfelds funktioniert nicht wie erwartet. Der Grund liegt darin, daß zwar StringItemList (d.h. Spalte 0) Klartext enthält, nicht aber ValueItemList (Spalte 1):
Hierbei handelt es sich offenbar um einen Bytestrom, in welchem Sonderzeichen als negative Werte (daher die eingestreuten Minuszeichen!) im Sinne einer Zeierkomplementdarstellung erscheinen, es reicht also nicht, einfach byteweise in die entsprechenden Zeichen umzuwandeln. Der Vollständigkeit halber hier noch das Makro, das ein Tabellen-Kontrollfeld ("gridSuchergebnis") filtert, danach eine Funktion, welche die nötige Dekodierung leistet:
Kursiv ist noch eine weitere denkbare und auch funkionierende, aber nicht minder unelegante Notlösung - wenn man die Datenbank nochmals direkt nach der entsprechenden Datensatznummer fragt ("SELECT wc FROM sampledb.vSuche LIMIT " & STR(idx) & ", 1 ;"), bekommt man erstaunlicherweise doch auch Klartext...
Vielleicht hilft es ja noch jemandem. - Natürlich wäre es viel schöner, wenn jemand wüßte, wie man das Problem (die unangeforderten BLOBs) vielleicht näher an der Wurzel beheben könnte.
Daß man das Listenfeld dazu in Base zwangsweise an eine Tabelle binden muß, die dann eben keinen Bezug zur eigentlichen Datenbank hat und nur einen Datensatz aufweist (in dem immer der letzte Suchterm steht), damit kann man auch noch leben.
Damit das ganze ordentlich schnell funktioniert, nimmt man, wenn die Daten ohnehin schon in einer mysql-Datenbank stecken, statt einer lokalen Abfrage in base besser eine Sicht ("view") in mysql, die sich mit der mysql-workbench sehr komfortabel anlegen und pflegen läßt.
Ein (stark gekürztes) Beispiel zur Illustration:
Code: Alles auswählen
CREATE ALGORITHM=UNDEFINED DEFINER=`sampledb`@`localhost` SQL SECURITY DEFINER VIEW `sampledb`.`vSuche` AS
(SELECT
CONCAT(`Lieferschein`, ' (Lieferscheinnummer)') AS "display",
CONCAT("Lieferschein='", `Lieferschein`,"'") AS "wc"
FROM `tblLieferschein` WHERE `Lieferschein` IS NOT NULL)
UNION
(...)
(SELECT
CONCAT(`Rechnung`, ' (Rechnungsnummer)') AS "display",
CONCAT("Rechnung='", `Rechnung`,"'") AS "wc"
FROM `tblLieferschein`
WHERE `Rechnung` IS NOT NULL)
UNION
(SELECT
CONCAT(`Datum`, ' (Datum)') AS "display",
CONCAT("Datum='", `Datum`, "'") AS "wc",
`Datum` As "Crit"
FROM `tblLieferschein`
WHERE `Datum` IS NOT NULL)
ORDER BY display ASC
Schwieriger wird es dann, wenn man feststellt, daß (aus mir bislang unerfindlichen Gründen auch auf einem überall auf UTF8 justierten System) mysql an Stelle von Text Binär-BLOBs zurückliefert; das zeigt sich z.B. in phpmyadmin, wo man die Texte durch die Option "Blob-Inhalte anzeigen" immerhin doch zu Gesicht bekommt. Betrachtet man die Sicht direkt über Ansicht/Datenbankobjekte/Tabellen, wo sie wie eine normale Tabelle erscheint, enthalten alle Felder nur "<OBJEKT>".
Benutzt man sie nun als Datenquelle ("Listeninhalt") für ein Listenfeld, so werden erfreulicherweise die Daten für Spalte 0 ("display") korrekt angezeigt. Doch das an sich bewährte Makro zum Filtern eines Tabellen-Kontrollfelds funktioniert nicht wie erwartet. Der Grund liegt darin, daß zwar StringItemList (d.h. Spalte 0) Klartext enthält, nicht aber ValueItemList (Spalte 1):
Code: Alles auswählen
StringItemList:
0 | String : ""
1 | String : " DU-PCG3-60MON-VOS-DISPLAY-26 (`Artikelnummer)"
2 | String : "Test$äöüÄÖÜß'"`´€µ@$End"
...
ValueItemList:
0 | String : ""
1 | String : "0x417274696b656c6e756d6d65723d272044552d504347332d36304d4f4e2d564f532d444953504c41592d323627"
3 | String : "0x42657374656c6c766f7267616e673d275465737424-3d-5c-3d-4a-3d-44-3d-7c-3d-6a-3d-64-3d-61272260-3e-4c-1e-7e-54-3e-4b4024456e6427"
...
Code: Alles auswählen
Sub lifSucheStatusChanged
Dim oDoc, oFormL, oFormP, oFormA, oFormS, oFormE, oLifSuche, oTxtDebug, oGridSuchergebnis As Object
Dim strWhereKlausel, strAC As String, idx As Long
oDoc=thisComponent
oFormS=oDoc.DrawPage.Forms.getByName("FormSuche")
oLifSuche=oFormS.getByName("lifSuche")
oTxtDebug=oFormS.getByName("txtDebug")
oFormE=oDoc.DrawPage.Forms.getByName("FormSuchergebnis")
oGridSuchergebnis=oFormE.getByName("gridSuchergebnis")
strWhereKlausel=[b]BlobDecode([/b]oLifSuche.ValueItemList(oLifSuche.SelectedItems(0))) '
[i] if false Then ' Workaround 2
idx=oLifSuche.SelectedItems(0)-1 ' Datensatznummer bestimmen; Listenfeld zählt einsbasiert!
' dieses Datensatzfeld auf anderem Wege holen
' SELECT "display", "wc" FROM "sampledb"."vSuche";
Dim oStatement, oResultSet As Object
oStatement = oFormE.ActiveConnection.CreateStatement
oResultSet = oStatement.executeQuery("SELECT wc FROM sampledb.vSuche LIMIT " & STR(idx) & ", 1 ;")
oResultSet.next
strWhereKlausel= oResultSet.getString(1)
End if[/i]
oTxtDebug.String=strWhereKlausel
oFormE.ApplyFilter = False
oFormE.Reload
oFormE.Filter = strWhereKlausel
oFormE.ApplyFilter = False
oFormE.ApplyFilter = True
oFormE.Reload
End Sub
Code: Alles auswählen
Function BlobDecode(strBlob As String)
Dim i As Long, strByte, strBuffer, strDecoded As String, intBufLen As Integer, intByte As Integer
'InputBox "", "", strBlob ' Auffangmöglichkeit
intBufLen = 2
strBuffer = ""
For i = 3 to Len(strBlob) + 1 ' "0x", also Zeichen1 bis 2, weglassen
strByte=Mid(strBlob, i, 1)
If Len(strBuffer)<intBufLen Then
strBuffer=strBuffer+strByte
If strByte="-" Then intBufLen=3 ' Puffer temporär für - vergrößern
Else
intBufLen=2 '
intByte = Clng(Replace("&h"&strBuffer,"&h-","-&h"))
If intByte<0 Then
intByte = 256 + intByte
End if
strDecoded = strDecoded & chr(intByte)'intByte & "/"
strBuffer = ""
i = i -1
End If
Next i
strDecoded = Replace(strDecoded, "ä", "ä")
strDecoded = Replace(strDecoded, "ö", "ö")
strDecoded = Replace(strDecoded, "ü", "ü")
strDecoded = Replace(strDecoded, "Ã", "Ä")
strDecoded = Replace(strDecoded, "Ã", "Ö")
strDecoded = Replace(strDecoded, "Ã", "Ü")
strDecoded = Replace(strDecoded, "Ã", "ß")
strDecoded = Replace(strDecoded, "¬", "€")
strDecoded = Replace(strDecoded, "µ", "µ")
' may be you need some more...
BlobDecode=strDecoded
End Function