sqlalchemy-postgresql, join 5 tbl, f-key von einer in zwei

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
rascha
User
Beiträge: 5
Registriert: Dienstag 13. April 2021, 12:20

Hallo! ich bin neu hier mit einem query-problem,

5 tabellen wie folgt a, b, c, d, e:

a: id, col1...

b: id, (foreign-key=a.id), col..

c: id, (foreign-key=a.id), col..

d: id, (foreign-key=b.id), col..

e: id, (foreign-key=c.id), col..

wie soll die abfrage auschauen, so dass auf jeden fall alle Einträge und zwar nicht wiederholt sondern korrect und identifizierbar drin sind?! danke
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich verstehe Deine Frage nicht. Welche Abfrage? Was sind alle Einträge? Und was bedeutet "korrekt"?
rascha
User
Beiträge: 5
Registriert: Dienstag 13. April 2021, 12:20

Hallo vielen dank für die Meldung! eine Abfrage, die alle tabellen joint unter a tabelle, d.h a hat ja fremd-key in b und c, b und c haben wiederum fremd-key in d und e.
ein resultat, die alle einträge von a-tabelle beinhaltet und darunter Einträge von b und c (zugeordnet zu a-id) und unter denen auch einträge von e und d (zugeordnet zu jeweils b-id , c-id)
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rascha: Und das Problem ist jetzt genau welches? Man joint halt alle Tabellen und gut ist.

Code: Alles auswählen

    ...
    print(
        table_a.join(table_b)
        .join(table_c)
        .join(table_d)
        .join(table_e)
        .select()
        .execute()
        .fetchall()
    )
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
rascha
User
Beiträge: 5
Registriert: Dienstag 13. April 2021, 12:20

__blackjack__ hat geschrieben: Dienstag 13. April 2021, 16:06 @rascha: Und das Problem ist jetzt genau welches? Man joint halt alle Tabellen und gut ist.

Code: Alles auswählen

    ...
    print(
        table_a.join(table_b)
        .join(table_c)
        .join(table_d)
        .join(table_e)
        .select()
        .execute()
        .fetchall()
    )
Hallo! vielen Dank für dein Input!
in sqlalchemy bin ich neu unterwegs. ich verwende db-session und zwar so:
database_url = "postgre_db_url"

engine = create_engine(
database_url
)

session_local = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

def get_db():
db = SessionLocal()
try:
yield db
except HTTPException:
db.close()



class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
col1 = Column(String, nullable=False)


def example(db: Session = Depends(get_db)):
db.query(A).join(B).join(C).join(D).all()

und wenn ich da alles in dieser form wie du sagst joine , dann bekomme ich nur die a-tabelle!
l.g
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rascha: Das ist nicht das gleiche. Du fragst `A` ab und joinst die anderen Tabellen, mein Code joint erst alle Tabellen und fragt die dann ab. Aber das funktioniert beim ORM ja sowieso alles komplett anders. Hättest Du ruhig erwähnen können das Du gar keine Tabellen abfragst sondern Objekte.

Was willst Du denn eigentlich machen hier? Wenn die Abhängigen Objekte generell gleich bei der ersten Abfrage mitgeladen werden sollen, oder nur in diesem speziellen Fall, dann kann man das an entsprechender Stelle angeben.

Edit: Wobei ich mich gerade Frage ob das was Du da machst, nicht auch schon das richtige macht. Was genau gefällt Dir an dem Ergebnis denn nicht?

Edit2: Warum willst Du das eigentlich machen? Premature optimization?
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
rascha
User
Beiträge: 5
Registriert: Dienstag 13. April 2021, 12:20

__blackjack__ hat geschrieben: Dienstag 13. April 2021, 21:10 @rascha: Das ist nicht das gleiche. Du fragst `A` ab und joinst die anderen Tabellen, mein Code joint erst alle Tabellen und fragt die dann ab. Aber das funktioniert beim ORM ja sowieso alles komplett anders. Hättest Du ruhig erwähnen können das Du gar keine Tabellen abfragst sondern Objekte.

Was willst Du denn eigentlich machen hier? Wenn die Abhängigen Objekte generell gleich bei der ersten Abfrage mitgeladen werden sollen, oder nur in diesem speziellen Fall, dann kann man das an entsprechender Stelle angeben.

Edit: Wobei ich mich gerade Frage ob das was Du da machst, nicht auch schon das richtige macht. Was genau gefällt Dir an dem Ergebnis denn nicht?

Edit2: Warum willst Du das eigentlich machen? Premature optimization?
Hi! kann sein, dass du den komplozierten Punkt hier ausser Acht gelassen hast? nämlich, dass f-key von a in b und c (i beiden) gibt.
das resultat wird abhängig davon welche a-key jeweils in a oder b eingefügt wurde!
das macht es schwirig objecte entsprechend ohne wiederholungen unter a-tabelle zu bringen.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rascha: Das habe ich schon gesehen. `join()` funktioniert nicht. Aber a) einfach ``all_a = session.query(A).all()`` funktioniert, eben mit abfragen/nachladen wie es bei den `relationships()` definiert ist, und falls da der Standard definiert ist, also "select" beim Zugriff auf die Attribute, oder man gibt als Option bei der Abfrage an, dass alle `relationships()` per JOIN in der gleichen Abfrage geladen werden sollen: ``all_a = session.query(A).options(joinedload("*")).all()``. Beispiel, folgende Datenbank:

Code: Alles auswählen

CREATE TABLE a (
        id INTEGER NOT NULL, 
        value TEXT, 
        PRIMARY KEY (id)
);
INSERT INTO a VALUES(1,'a 1');
INSERT INTO a VALUES(2,'a 2');
CREATE TABLE b (
        id INTEGER NOT NULL, 
        a_id INTEGER, 
        value TEXT, 
        PRIMARY KEY (id), 
        FOREIGN KEY(a_id) REFERENCES a (id)
);
INSERT INTO b VALUES(1,1,'b 1');
INSERT INTO b VALUES(2,2,'b 2');
CREATE TABLE c (
        id INTEGER NOT NULL, 
        a_id INTEGER, 
        value TEXT, 
        PRIMARY KEY (id), 
        FOREIGN KEY(a_id) REFERENCES a (id)
);
INSERT INTO c VALUES(1,1,'c 1');
INSERT INTO c VALUES(2,2,'c 2');
CREATE TABLE d (
        id INTEGER NOT NULL, 
        b_id INTEGER, 
        value TEXT, 
        PRIMARY KEY (id), 
        FOREIGN KEY(b_id) REFERENCES b (id)
);
INSERT INTO d VALUES(1,1,'d 1');
INSERT INTO d VALUES(2,2,'d 2');
CREATE TABLE e (
        id INTEGER NOT NULL, 
        c_id INTEGER, 
        value TEXT, 
        PRIMARY KEY (id), 
        FOREIGN KEY(c_id) REFERENCES c (id)
);
INSERT INTO e VALUES(1,1,'e 1');
INSERT INTO e VALUES(2,2,'e 2');
Variante 1:

Code: Alles auswählen

    all_a = session.query(A).all()
    a = all_a[0]
    print(a.value, a.b.value, a.c.e.value)
Setzt beim `all()` eine SQL-Abfrage ab um die `A`-Objekte zu laden, und jeweils eine Abfrage für jeden Attributzugriff:

Code: Alles auswählen

-- all()
SELECT a.id AS a_id, a.value AS a_value FROM a

-- a.b
SELECT b.id AS b_id, b.a_id AS b_a_id, b.value AS b_value 
FROM b 
WHERE ? = b.a_id

-- a.c
SELECT c.id AS c_id, c.a_id AS c_a_id, c.value AS c_value 
FROM c 
WHERE ? = c.a_id

-- c.e
SELECT e.id AS e_id, e.c_id AS e_c_id, e.value AS e_value 
FROM e 
WHERE ? = e.c_id


Variante 2:

Code: Alles auswählen

    all_a = session.query(A).options(joinedload("*")).all()
    a = all_a[0]
    print(a.value, a.b.value, a.c.e.value)
Setzt *eine* SQL-Abfrage gleich beim `all()` ab:

Code: Alles auswählen

SELECT a.id AS a_id, a.value AS a_value, b_1.id AS b_1_id, b_1.a_id AS b_1_a_id,
    b_1.value AS b_1_value, d_1.id AS d_1_id, d_1.b_id AS d_1_b_id,
    d_1.value AS d_1_value, c_1.id AS c_1_id, c_1.a_id AS c_1_a_id,
    c_1.value AS c_1_value, e_1.id AS e_1_id, e_1.c_id AS e_1_c_id,
    e_1.value AS e_1_value 
FROM a
  LEFT OUTER JOIN b AS b_1 ON a.id = b_1.a_id
  LEFT OUTER JOIN d AS d_1 ON b_1.id = d_1.b_id
  LEFT OUTER JOIN c AS c_1 ON a.id = c_1.a_id
  LEFT OUTER JOIN e AS e_1 ON c_1.id = e_1.c_id
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
rascha
User
Beiträge: 5
Registriert: Dienstag 13. April 2021, 12:20

@__blackjack__ Hi! das funktioniert, ich hatte schon die relationships verwendet aber von allen 3 objecten in
form von session.query(a, b, c).options(joinload(a.b_relatin),joinload(a.c_relatin),joinload(b.d_relation),joinload(c.e_relation)).all()
es hat aber nur richtig funktioniert solange b und c die selben f-key's von a hatten sonst war es konflikt!
aber deine Methode session.query(A).options(joinedload("*")).all() habe ich probiert und kein Konflikt.

super herzlichen Dank! L.G
Antworten