Listenfeld Einträge dynamisch aus m:n Abfrage

Servus zusammen,
da ich trotz intensiver Suche im Netz und zahlreichen Versuchen keine Lösung für mein Problem finde, frag ich hier, in der Hoffnung, daß mir jemand weiterhelfen kann.

Mein Problem ist eigentlich rasch umschrieben und scheint auf den ersten Blick banal: Ausgangssituation ist eine m:n-Beziehung. (Zwei Tabellen mit einer Verbindungstabelle)
Ich möchte in einem Formular für Tabelle 1 ein Listenfeld haben, welches alle mit dem aktuell im Hauptformular angezeigten Datensatz verknüpften Datensätze aus Tabelle 2 als Listenelemente anzeigt.
Alle Versuche, das über SQL-Abfragen zu lösen schlugen fehl, da LOB offenbar nicht den aktuellen Datensatz an die SQL-Abfrage für die Listeneinträge übergibt.
Platzierung in Unterformular (mit der Verbindungstabelle als Datenquelle) scheidet aus, da die Eingabe in einem Feld von Tabelle 1 erfolgen soll. (Außerdem wäre das Kernproblem hier genau das Gleiche)
Auch mit Hilfstabelle als Filter oder Self-Join scheint das nicht zu gehen. Genausowenig komme ich mit einer definierten Abfrage und Parameter als Umweg nicht zum gewünschten Ergebnis.
In der Liste erscheinen stets alle Datensätze von Tabelle 2, die irgendeine Zuordnung (zu irgendeinem DS) zu Tabelle 1, nicht aber nur zum aktuell angezeigten haben.

Gibt es da irgendeine Einstellung, die ich übersehen habe? Oder irgendeinen Trick oder Workaround?
Es ist auch gut möglich, daß ich einfach nur auf dem Schlauch stehe. Vielleicht kann mir jemand runter helfen?

Vielen Herzlichen Dank im Voraus.

P.S.: Ich bitte um Nachsicht, falls das eine dumme Anfängerfrage sein sollte. Bislang habe ich solche Projekte ausschließlich mit Filemaker umgesetzt. Da wäre das einfach mit einem Variablenfeld lösbar. In LO und SQL bin ich aber leider wirklich Anfänger.

Standard bei einer n:m-Verbindung:
Du hast 3 Tabellen, “Tab1”, “rel_Tab1_Tab2” und “Tab2”.
Du hast ein Formular “Tab1”, in das mit einem Tabellenkontrollfeld ein Unterformular “rel_Tab1_Tab2” angehängt ist.
Das Tabellenkontrollfeld zeigt ein Listenfeld, das alle Datensätze zu “Tab2” enthält. So kannst Du neue Datensätze zu “rel_Tab1_Tab2” hinzufügen oder löschen.

Willst Du ein Listenfeld vom Inhalt her anpassen, so geht das nur über Makros. Du musst zuerst den Code für das Feld anpassen und dann das Feld mit einem refresh neu einlesen. Das funktioniert aber nur fehlerhaft bei Listenfeldern in Tabellenkontrollfeldern, wenn Du versucht, jedem Datensatz einen neuen Listenfeldinhalt zuzuweisen.

Schau einmal im aktuellen Handbuch S.486 “Listenfeld” und S. 505 “Listenfelder durch Eingabe der Anfangsbuchstaben einschränken”.

Gruß

Robert

Danke Robert.

Soweit so klar.

Das ist schlecht. Ich wollte eigentlich sofern irgend möglich Makros vermeiden. Einerseits fehlt mir momentan die Zeit, mich in deren Programmierung einzuarbeiten. Andererseits bin ich kein Berufsprogrammierer, der sich ständig damit befasst. D.h. wenn ich in einem Jahr den heute zusammengestöpselten Code nachvollziehen möchte, fang ich wieder von vorne an, da ich in der Zwischenzeit alles wieder vergessen habe. :wink:

Das wäre in diesem Fall egal. Das Listenfeld liegt nicht in einem Tabellenkontrollfeld.

Mein Ziel ist, daß der Anwender aus einer bestehenden Liste von Einträgen (DS aus Tab2, die über rel_Tab1_Tab2 einem bestimmten DS in Tab1 zugeordnet sind) auswählt, um anschließend mit den Werten aus diesem ausgewählten DS Berechnungen gemacht werden können. Konkret handelt es sich bei den Einträgen (in Tab2) um Artikeldaten verschiedener Hersteller. In dem Formular soll anhand dieser Daten (und weiterer Parameter) der Wareneinsatz für ein Produkt (Tab1) in Abhängigkeit von der Auswahl in besagtem Listenfeld (und weiterer nach gleichem Schema angelegter Verknüpfungen) berechnet werden.

Was wäre die einfachste Möglichkeit, den Listeninhalt in Abhängigkeit vom gerade angezeigten DS aus Tab_1 zu ermitteln?
Idee: Vielleicht ein kleines Makro, welches ein SQL-UPDATE absetzt und ein Variablenfeld (gleicher Wert in allen DS in Tab_1) mit der ID des gerade aufgerufenen DS befüllt? (Ausgelöst beim DS-Wechsel in Tab_1)
Wäre das sehr komplex zu programmieren? Dann könnte man den Listeninhalt einfach mit Verknüpfung des Variablenfelds mit der rel-Tabelle abfragen.
(Da in Tab_1 nie mehr als 100, vielleicht 150 DS vorhanden sein werden, sollte der UPDATE-Befehl keine großartigen Performanceprobleme machen.)

Ohne die geringste Ahnung von der Makroprogrammierung zu haben, müsste der Befehl dann in etwa so lauten:

Setze Variable = Tab_1.ID 
Führe SQL-Befehl aus: UPDATE "Tab1" SET "Variablenfeld" = Variable

Oder ist das kurz gedacht?

Für das Makro:
Schau einfach einmal auf S. 487 des aktuellen Handbuches, Handbuch Base LO 7.5
Da steht so ein Makro für ein Listenfeld. Den SQL-Code musst Du anpassen, die Verbindung zum Formular vermutlich auch. Dann wirst Du noch irgendwo aus dem Formular auslesen müssen, welchen Primärschlüssel denn der aktuelle Datensatz hat.

Das, was Du sonst so beschreibst, bleibt mir ohne eine Beispieldatenbank unklar.

@michael_m Auch ich verstehe den Sinn der Sache nicht. Wenn ich dich richtig verstanden habe, möchtest du anhand des Eintrages in Tabelle1, die dazugehörigen Datensätze aus Tabelle2 angezeigt bekommen, um einen davon wiederum in Tabelle 1 einzutragen?
Beschreibe doch mal, was du eigentlich erreichen willst, vielleicht ist es ganz einfach ohne Listenfeld machbar.

Vergiss Makros. Du brauchst sie in aller Regel nicht, wenn Du ein paar mehr Klicks in Kauf nimmst.
relations2listboxes.odb beinhaltet eine m-n-Beziehung zwischen Personen und Dingen, verknüpft über die Tabelle “P_T”. Die Formulare verwenden immer das gleiche Schema:
Das Formular “Persons” hat die Personen im Hauptformular und “P_T” als Unterformular verknüpft über die Personen-ID. Das Unterformular besteht aus einem Listenfeld mit Dingen, das in einem Tabellen-Kontrollfeld eingebettet ist, was eine Tabellenspalte aus Listenfeldern ergibt über die jeder Person viele Dinge zugeordnet werden können.
Spiegelbildlich sind im Formular “Things” die Dinge im Hauptformular und widerum “P_T” als Unterformular, verknüpft über die Ding-ID, mit einem Listenfeld mit Personen im Tabellenkontrollfeld, so dass jedem Ding viele Personen zugeordnet werden können.

Vielen Dank für den Input.
Die Beispieldatei von @Villeroy beschreibt im Wesentlichen meinen Status quo, bzw. den Punkt an dem ich nicht weiterkomme.
Ich habe zur Verdeutlichung meines Problems in der Tabelle Persons ein zusätzliches Feld eingefügt, und in dem Formular ein weiteres Tabellenkontrollfeld.
Mit diesem Feld soll hier das “Lieblings-Thing” der jeweiligen Person definiert werden. :laughing:

Im Endeffekt geht es mir darum, daß ich genau die Liste, die in der Tabelle links unten angezeigt wird, als Einträge im Listenfeld haben möchte.
Das muß doch mit Bordmitteln ohne Makro gehen, oder?

relations2listboxes.odb (62.4 KB)

P.S.: Btw: Gibt es eine Möglichkeit einzustellen, damit Listenfelder innerhalb von Tabellen genauso dargestellt werden, wie wenn sie direkt auf dem Formular platziert werden? (Siehe erster Eintrag in der gelben Tabelle auf dem ersten Screenshot)

Das ist eine 1:n-Beziehung zwischen Person und Ding.
Extras>SQL…

alter table "Persons" add column FAV integer;
alter table "Persons" add foreign key (FAV) references "Things" (ID)

und dann Ansicht>Tabellen aktualisieren
Das Ergebnis sieht dann so aus:
Bildschirmfoto von 2023-05-03 11-53-40
In den Formularen fügst Du ein Listenfeld zu den Personen hinzu mit dem Inhalt.

SELECT "Name", "ID" FROM "Things" AS "Things" ORDER BY "Name" ASC

Jetzt kann man für jede Person einen Favoriten angeben.

P.S. Das obige ist natürlich ein Fehltritt, wenn man einen Favoriten aus den bereits im Besitz befindlichen Dingen wählen soll. So könnte jetzt folgendes auch gemeint sein: “Ich habe einen Hammer und einen Meißel, aber mein größter Wunsch wäre die Axt, die ich noch nicht habe.”
Base kann ohne Makros kaum Listenfeldeinträge filtern (es gibt da einen sehr kruden Weg).
Man könnte jetzt an P_T eine Zahl (Integer) anhängen, wo man unter den vorhandenen Einträgen ein Ranking vornimmt. Die höchste oder niedrigste Zahl wäre dann der Favorit.

OK, hier ist dieser krude Weg. Eine Tabelle “Filter” speichert eine Zahl “INT1” in Zeile 1. Das Hauptformular bezieht sich auf diese Zeile mit der Zahl “INT1” WHERE “FID”=1.
Nun wird das rote Unterformular auf eine Person gefiltert. Der [OK]-Knopf updatet dieses Formular samt Listenfeld, das nur diejenigen Dinge anzeigt, die momentan im Besitz der Person sind. Das Listenfeld wird von einer Abfrage gefüllt, welche die iin der Filter-Zeile gespeicherte Personen-ID verwendet.
Dies hat widerum ein kleines Problem wenn der favorisierte Gegenstand nicht mehr im Besitz der Person ist (Zeile wurde aus gelber Tabelle gelöscht). Dann zeigt das Listenfeld für den Favoriten einen verwaisten leeren Eintrag weil der Inhalt in P_T keinen Einfluss hat auf den Favoriten-Eintrag in der Personenliste.
relations2listboxes_Fav.odb (73.3 KB)

1 Like

Ja, genau das war die Anforderung, an der ich gescheitert bin, bzw. nicht mehr weiterwusste.

Als “krude” würde ich das nicht bezeichnen. Eher als clever.
Vielen Dank dafür. :1st_place_medal:

Für meine weitere Arbeit an dem Projekt reicht mir das jetzt erstmal. Für den späteren Live-Einsatz wäre es für die Usability fein, wenn man den Button weglassen könnte und stattdessen bei Feldwert-Änderung ein Makro auslöst, welches das Formular aktualisiert. Vielleicht hat jemand den passenden Code zur Hand? Wenn nicht, muß ich mich doch irgendwannmal in einer (oder wahrscheinlich eher vielen) Mußestunde(n) in die Makro-Programmierung reinfuchsen. :see_no_evil:

Das wäre dann dieses Makro: https://forum.openoffice.org/en/forum/download/file.php, das ich oft verwende.
Es kann beliebige Formulare, Listenfelder und Combo-Boxen im selben Formular-Dokument updaten. Nicht bei Feldwert-Änderung, sondern wenn ein irgendwie geänderter oder hinzugefügter Datensatz gespeichert wird oder wenn einer gelöscht wird. Man kann also eine Speichern-Schaltfläche als Standardschaltfläche festlegen (reagiert auf Eingabetaste) und alles reagiert auf den geänderten Datensatz, aber auch wenn der Datensatz gelöscht wurde oder wenn einer hinzugefügt wurde.

  1. Dem auslösenden Formular ein verstecktes Kontrollfeld mit dem Namen “AutoRefresh” hinzufügen.
  2. Die Elemente ermitteln, die neu geladen werden sollen und als Wert eintragen.
  3. Dem Ereignis “Nach Datensatzaktion” das Makro zuordnen.

Beispiel für einen Eintrag: ../Unterformular1/Tabelle1/ListenFeld1 geht in der Hierarchie eine Ebene nach oben und erneuert im Formular “Unterformular1”, innerhalb des Tabellenfelds “Tabelle1” das “Listenfeld1”. Das Unterformular wird nicht neu geladen und bleibt auf dem aktuellen Datensatz stehen. Nur das Listenfeld in der Spalte wird neu geladen.
Mehrere Elemente können mit Semikolon getrennt eingetragen werden.

Apache OpenOffice Community Forum - Cascading list boxes with and without macros - (View topic) stellt lösungen für kaskadierende Listenfelder dar. Eine Lösung verwendet das obige Makro mit Hilfe von Filterformularen und unsichtbaren Schaltflächen.

Vielen herzlichen Dank für die ausführliche Hilfestellung.
Da hab ich jetzt erstmal genug zu tun, das umzusetzen.

Schau Dir erstmal dias Beispiel mit den Listenfeldern genau an. Ich glaube, das ist einigermaßen deutlich.
Und dann noch https://forum.openoffice.org/en/forum/download/file.php?id=40136 (zwei gleiche Filter-Formulare mit und ohne AutoRefresh)