❤ Unterstütze jetzt das LIBREOFFICE-Forum ❤

Workaround: BLOBs in ValueItemList dekodieren

Base ermöglicht es Ihnen, Ihre Daten in einer Datenbank direkt mit LibreOffice zu bearbeiten.
Antworten
devdol
Beiträge: 45
Registriert: Fr 11. Mär 2011, 17:59

Workaround: BLOBs in ValueItemList dekodieren

Beitrag von devdol » 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:

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

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"
...
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:

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
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...

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
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.

Antworten