QSqlRelationalTableModel und mehr als eine Relation über setRelation

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
WebDepp63
User
Beiträge: 13
Registriert: Mittwoch 16. August 2023, 10:40

Hallo Foren-Mitglieder,

ich habe folgendes Problem bei dem ich der Hilfe zu Qt for Python keine Lösung entnehmen konnte. Auch über Google habe ich bislang noch nichts gefunden.
Ich habe ein Model (mdl_Tabelle) per QSqlRelationalModel erzeugt für ein QTableView. Dieses QTableView gibt anhand des M;odels eine Liste von Aufgaben aus. In dieser Liste befindet sich in einer Spalte der Index des Erstellers der Aufgabe und in einer anderen der Index des Bearbeiters, also desjenigen, der die Aufgabe abarbeiten soll. Die Tabelle, die über diese beiden Indize in Relation gesetzt werden soll ist eine Personaltabelle (Name der Tabelle: Personal). In dieser befinden sich die Mitarbeiter eines Unternehmens unteranderem finden sich dort Vorname und Nachname.
Die Relationen habe ich erzeugt über setRelation wie folgt:

Code: Alles auswählen

self.mdl_Tabelle.setRelation(2, QtSql.QSqlRelation("Personal", "Index", "Vorname & ' ' & Nachname"))
self.mdl_Tabelle.setRelation(5, QtSql.QSqlRelation("Personal", "Index", "Vorname & ' ' & Nachname"))
Jetzt ist es so, dass die Tabelle leer bleibt wenn beide Beziehungen gesetzt sind. Kommentiere ich eins von beiden aus wird die Tabelle angezeigt und Vorname sowie Nachname werden anstelle des Indexes für die Person ausgegeben. Im anderen Fall wird der Index ausgegeben, was ja auch logisch ist.
Ich hatte schon darüber nachgedacht, dass vielleicht zwei Beziehungen zur selben Tabelle nicht möglich wären. Deshalb hab ich in der DB die Personal-Tabelle mal kopiert und unter einem anderen Namen eingefügt und die zweite Beziehung auf diese Kopie gelenkt. Auch in diesem Fall blieb die Tabelle leer. In der Hilfe wird aufgezeigt, dass mehrere Beziehungen durchaus möglich sind.
Was mache ich hier falsch? Wo ist mein Denkfehler?

Für Hilfe bin ich dankbar.
Viele Grüße
WebDepp63
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich sehe zwar zwei Relationen, aber jeweils die gleiche Spalte fue den Schluessel. Kann ja nicht sinnvoll sein. Muesste das nicht sowas wie ersteller_id und bearbeiter_id als zweites Argument sein?
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

So, nochmal geschaut: das ist wahrscheinlich Unfug, was ich da erzaehlt habe. Die Foreign keys werden ja ueber 2 und 5 als Spaltenindizes gebildet. Dann faellt mir erstmal nichts ein, da braeuchte man ein minimales Beispiel zur Verfikation (zB mit sqlite als Backend).
WebDepp63
User
Beiträge: 13
Registriert: Mittwoch 16. August 2023, 10:40

Grober Aufbau der Peronaltabelle: INDEX, Vorname, Nachname
Index ist PrimaryKey.
Bsp.datensätze: (1, Otto, Mustermann), (2, August, Flink)

Grober Aufbau der Aufgabentabelle: Index NochEinFeld, ERSTELLER, Aufgabe, Datum, BEARBEITER
Index ist PrimaryKey.
Ersteller enthält Index aus Personaltabelle und hat Spaltenindex 2 in der Aufgabentabelle
Bearbeiter enthält Index aus Peronaltabelle und hat Sppaltenindex 5 in der Aufgabentabelle

Ich binde also:
1. Relation: Spalte 2 (ERSTELLER) der Aufgabentabelle an die Personaltabelle ("Personal") über deren Spalte INDEX ("Index") um "Vorname & ' ' & Nachname" abzugreifen
2. Relation: Spalte 5 (BEARBEITER) der Aufgabentabelle an die Personaltabelle ("Personal") über deren Spalte INDEX ("Index") um "Vorname & ' ' & Nachname" abzugreifen

Die Peronaltabelle ist für beide Fälle dieselbe und es kann vorkommen ERSTELLER != BEARBEITER alss auch ERSTELLER == BEARBEITER.
Oder anders: die Namen der Personen jedes Aufgaben-Datensatzes werden aus der Personaltabelle abgerufen über den in der Spalte befindlichen Index

Die Hilfe sagt:

Code: Alles auswählen

model.setTable("employee")
model.setRelation(2, QSqlRelation("city", "id", "name"))

The setRelation() call specifies that column 2 in table employee is a foreign key that 
maps with field id of table city, and that the view should present the city's name field to the user.
Danach sollten diese setRelations so richtig sein. Oder ich habe da etwas nicht geschnallt.
Danke für die schnelle Antwort und viele Grüße
WebDepp63
WebDepp63
User
Beiträge: 13
Registriert: Mittwoch 16. August 2023, 10:40

Ups, Antworten haben sich überschnitten. Nochmals danke!
WebDepp63
User
Beiträge: 13
Registriert: Mittwoch 16. August 2023, 10:40

Hallo Forenmitgliedeer,

für alle die es interessiert. Es ist möglich in setRelation mehrere Felder anzugeben:

Code: Alles auswählen

setRelation(2, QtSql.QSqlRelation("Personal", "Index", "Vorname & ' ' & Nachname AS Ersteller")) 
also hier mehrere Felder kombiniert über: "Vorname & ' ' & Nachname" als eine Spalte unter der Spaltenüberschrift 'Ersteller' oder mit

Code: Alles auswählen

setRelation(2, QtSql.QSqlRelation("Personal", "Index", "Vorname, Nachname"))
also mehrere Felder über "Vorname, Nachname", wobei für jedes angegebene Feld eine eigene Spalte ausgegeben wird.

Wird aber mehr als eine Relation mit kombinierten Feldern versucht zu setzen, funktioniert es nicht:

Code: Alles auswählen

setRelation(2, QtSql.QSqlRelation("Personal", "Index", "Vorname & ' ' & Nachname AS Ersteller")) 
setRelation(5 QtSql.QSqlRelation("Personal", "Index", "Ort"))
Ergebnis hierbei: Tabelle bleibt leer!

Für die Standard-Variante mit nur einem Feld funktionieren mehrere Beziehungen. Es ginge also:

Code: Alles auswählen

setRelation(2, QtSql.QSqlRelation("Personal", "Index", "Nachname")) 
setRelation(5 QtSql.QSqlRelation("Personal", "Index", "Ort"))
Ergebnis hierbei: Tabelle wird ausgegeben!

LG, WebDepp63
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Klingt als ob das ein Bug ist. Kannst du irgendwie die erzeugten SQL-Statements sichtbar machen? Dann kann man das ggf. nachvollziehen.
WebDepp63
User
Beiträge: 13
Registriert: Mittwoch 16. August 2023, 10:40

Das muss ich mal sacken lassen, wie das gehen könnte. Da hatte ich auch schon drüber nachgedacht aber bis jetzt noch keine Lösung gefunden das auszugeben. Ich melde mich. Danke für den Schups wieder in diese Richtung. Die Idee war schon wieder untergegangen. Bis dahin... LG
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also es scheint als ob's da was gibt: https://doc.qt.io/qt-6/qsqlrelationalta ... tStatement

Noch besser waere natuerlich ein Weg, alle SQL Statements aus dem Qt System zu bekommen.
WebDepp63
User
Beiträge: 13
Registriert: Mittwoch 16. August 2023, 10:40

Danke für den Hinweis. Nach so etwas habe ich gesucht aber scheins übersehen. Aus folgender Anweisung:

Code: Alles auswählen

self.mdl_Tabelle.setRelation(2, QtSql.QSqlRelation("Personal", "Index", "Vorname & ' ' & Nachname AS Ersteller"))
wird das folgende SQL-Statement:

Code: Alles auswählen

SELECT ToDos.`Index`,ToDos.`Projekt`,relTblAl_2.Vorname & ' ' & Nachname AS Ersteller,ToDos.`Aufgabe`,ToDos.`Erledigen_bis`,ToDos.`Bearbeiter_Personal`,ToDos.`Erstellt`,ToDos.`Bearbeiter_Zugestellt`,ToDos.`Delegieren`,ToDos.`Erledigt` FROM ToDos,Personal relTblAl_2 WHERE (ToDos.`Ersteller_Personal`=relTblAl_2.Index)
Ich finde die folgenden Stelllen sehen nicht gut aus:

Code: Alles auswählen

1) ...relTblAl_2.Vorname & ' ' & Nachname AS Ersteller...
und

Code: Alles auswählen

2) ...FROM ToDos,Personal relTblAl_2 WHERE...
Meiner Meinung nach müsste da stehen für 1)

Code: Alles auswählen

...relTblAl_2.Vorname & ' ' & relTblAl_2.Nachname AS Ersteller...
und für 2)

Code: Alles auswählen

...FROM ToDos,Personal AS relTblAl_2 WHERE...
Wie dem auch sei. Das das setRelation-SQL-Statement für sich alleine überhaupt funktioniert erscheint mir unlogisch.

Noch ein ergänzender Hinweis: Die zugrundeliegende DB ist eine Access-DB in der nur Tabellen sind und die über ODBC angesprochen wird (QtSql.QSqlDatabase.addDatabase("QODBC")).
Der Hintergrund ist, dass eine Access-Anwendung existiert, die sich im Netzwerk (Front-/Backend-Struktur) schwer tut und immer wieder mal repariert werden muss. Damit der Umstieg fließend geschehen kann findet eine Neuentwicklung in Python sttatt auf Basis des Backends. Die Mitarbeiter arbeiten weiter mit der Access-Anwendung während die Umstellung auf Python parallel erfolgt. Natürlich findet die Entwicklung nicht auf der Laufzeit-Version des aktuellen Backends statt. Das wird aber gelegentlich kopiert um den aktuellen Datenbestand für die Entwicklung zu haben und das Laufzeitverhalten berücksichtigen zu können. Später soll dann auf MySQL umgesattelt werden, etc. Das nur kurz am Rande.

Da die weiteren SQL-Statements bislang alle auf der Access-DB funktinonieren, denke ich, dass es kein Problem des Access-Backends ist, dass die über setRelation erzeugten Abfragen nicht gehen. Das schließe ich zunächst mal aus. Allerdings ercheint mir die obige Syntax fraglich.

Warum möchte ich das überhaupt mit QSqlRelationalTableModel umsetzen? Weil die meisten Tabellen nahezu nativ sind (siehe bspw. die ToDo-Tabelle des obigen SQL-Statements. Änderungen könnten bedingt direkt in der Tabelle durchgeführt werden. Mit QSqlQueryModel wäre das ja nicht möglich. Ich wollte mir den Umweg über separate Editor-Dialoge sparen.

Für Ideen und Anregungen bin ich sehr dankbar. Der Hinweis auf die Methode selectStatement war schon Gold wert.
Danke nochmal und bis dahin, LG
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das mit dem AS ist denke ich eine SQL-Dialekt-Frage. Ich vermute mal das ACCESS das durchgehen laesst. Grammatikalisch ist ja nun

tabelle_a, tabelle_b as X

und

tabelle_a, tabelle_b X

gleich, weil man einfach Komma-separariert Tabellen-Statements bekommt, und fuer das aliasing auch auf das AS verzichten kann. Denn was sonst soll der Name danach sein? Wenn das nicht ginge, wuerde es auch nicht mit einer Spalte gehen.

Das Problem ist dann wohl, dass der Qt SQL Generator da was verbockt. Da muesste man jetzt die C++-Quellen studieren, und schauen, ob und was die koennen.

Alternativ ein eigenes Modell schreiben, mittels QAbstractItemModel, und ggf. statt Qt SQL komplett auf SQL Alchemy setzen. Ist aber natuerlich etwas Arbeit.
WebDepp63
User
Beiträge: 13
Registriert: Mittwoch 16. August 2023, 10:40

Hallo __deets__,

danke für deinen Einsatz. Das mit
...dass der Qt SQL Generator da was verbockt...
glaube ich mittlerweils auch. Um das abzuschließen:
1. Ich werde doch Dialoge zur Bearbeitung einführen
2. SQL Alchemy werde ich mir in einer ruhigen Minute mal ansehen
3. Wenn ich das von setRelation erzeugte SQL-Statement
(also oben dass gelistete:

Code: Alles auswählen

SELECT ToDos.`Index`,ToDos.`Projekt`,relTblAl_2.Vorname & ' ' & Nachname AS Ersteller,ToDos.`Aufgabe`,...
)
in Access direkt ausführen möchte, funktioniert dass nicht. Aber dem gehe ich auch in einer ruhigen Minute nochmal nach.
Also nochmals danke für die guten Ansätze/Ideen. Ich bleib am Ball ;-)

LG, WebDepp63
Benutzeravatar
grubenfox
User
Beiträge: 432
Registriert: Freitag 2. Dezember 2022, 15:49

Also mich irritieren die ganze Zeit die
`
(also bei `Index`, `Projekt` und `Aufgabe`)
WebDepp63 hat geschrieben: Dienstag 30. Januar 2024, 13:50

Code: Alles auswählen

SELECT ToDos.`Index`,ToDos.`Projekt`,relTblAl_2.Vorname & ' ' & Nachname AS Ersteller,ToDos.`Aufgabe`,...
)
Die habe ich bei Access noch nie gesehen. Die
'
von ' ' sind mir deutlich vertrauter.
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

@grubenfox: das ist ja aber auch ODBC SQL: https://learn.microsoft.com/en-us/sql/o ... rver-ver16
Benutzeravatar
grubenfox
User
Beiträge: 432
Registriert: Freitag 2. Dezember 2022, 15:49

Ach, ODBC! Ich habe immer nur direkt mit Access zu tun. Da ist mir ODBC nie unter die Finger gekommen.. Danke für die Erleuchtung. ;)
Antworten