A.ParentId ist eine _id in P, wenn das Feld ParentTab eine 0 enthält und
A.ParentId ist eine _id in A, wenn das Feld ParentTab eine 1 enthält.
Kann man mit SQL eine Abfrage bauen, die alle Einträge in A findet, die
auf einen bestimmten Satz in P verweisen und alle Sätze in A, die auf
einen Satz in A verweisen, der auf einen Satz in P verweist?
Die Sätze der Ergebnismenge sollen so sortiert sein, dass die A-Sätze,
die auf einen A-Satz verweisen, direkt nach dem A-Satz kommen, auf den
sie verweisen.
Die Schachtelungstiefe in A ist 1 - es gibt also keine Sätze, die auf
einen Satz in A verweisen, der auf einen Satz in A verweist.
Uhu U. schrieb:> Kann man mit SQL eine Abfrage bauen, die alle Einträge in A findet, die> auf einen bestimmten Satz in P verweisen und alle Sätze in A, die auf> einen Satz in A verweisen, der auf einen Satz in P verweist?
Ja kann man.
Sheeva P. schrieb:> Hast Du Gründe dafür, warum Du dazu zwei Tabellen verwendest?
Ja. Die P-Tabelle soll Kollektionen von A-Einträgen benennen. In
weiteren Tabellen werden diese Kollektionen dann über die P-Einträge
referiert. Das ist nur ein sehr rudimentärer Baum.
T.roll schrieb:> Ja kann man.
So weit bin ich mittlerweile auch. Nur wie die Select-Anweisung konkret
aussehen muss, habe ich noch nicht herausgefunden. Hab mich erst mal mit
Sqliteman rumgeärgert, bis ich herausgefunden hatte, wie die Eingabe
funktioniert...
Hallo,
Fang damit an, das Du die einzelnen Fragestellungen in jeweils einer
Select Anweisung formulierst.
Versuch noch nicht das Gesamtproblem in einem Rutsch zu lösen.
Im zweiten Schritt kombinierst Du Deine vorherigen Lösungen durch Joins
zu einer Gesamtlösung.
Wenn Du die einzelnen Schritte postest kann ich schauen wo ich Dir
helfen kann.
Gruß
Frank
Frank L. schrieb:> Wenn Du die einzelnen Schritte postest kann ich schauen wo ich Dir> helfen kann.
Das ist nett.
Das ist meine Spielwiese:
1
INSERT INTO "P" VALUES(1, ...);
2
INSERT INTO "P" VALUES(2, ...);
3
\
4
\
5
\ ParentId (Spalte 2)
6
INSERT INTO "A" VALUES(1, 1, 0, ...);
7
INSERT INTO "A" VALUES(2, 1, 0, ...);
8
INSERT INTO "A" VALUES(3, 2, 0, ...);
9
INSERT INTO "A" VALUES(4, 2, 0, ...);
10
\
11
\ ParentTab (Spalte 3)
12
\ /
13
INSERT INTO "A" VALUES(5, 4, 1, ...);
14
INSERT INTO "A" VALUES(6, 4, 1, ...);
Die Sätze 5 und 6 hängen an Satz 4; 1 bis 4 hängen an den Sätzen 1 und 2
in Tabelle P
Die Abfrage auf ParentId=1 soll A.1 und A.2 liefern,
die Abfrage auf ParentId=2 soll A.3, A.4, A.5, A.6 (in der Reihenfolge)
liefern.
Die Einzelabfragen sind ja noch schön einfach:
1
SELECT * FROM A WHERE ParentId=2 AND ParentTab=0;
2
SELECT a2.* FROM A AS a1 JOIN A AS a2 ON a1._id=a2.ParentId WHERE a1.ParentId=2 AND a1.ParentTab=0;
Die 1. Abfrage bringt A.3 und A.4
die 2. Abfrage bringt A.5 und A.6
1
SELECT * FROM A WHERE ParentId=2 AND ParentTab=0
2
UNION
3
SELECT a2.* FROM A AS a1 JOIN A AS a2 ON a1._id=a2.ParentId WHERE a1.ParentId=2 AND a1.ParentTab=0;
Spaßeshalber: könnte man die Schachtelung in A auch grenzenlos machen
und die A-Sätze, die beliebig tief geschachtelt sind auch mit einem
einzigen SQL,Befehl so herausangeln?
Uhu U. schrieb:> beliebig tief geschachtelt sind auch mit einem> einzigen SQL,Befehl so herausangeln?
SQL ist (absichtlich) nicht turing-mächtig. Da geht "beliebig tief" IMO
nicht ohne weiteres.
Bedenke dass Du im obigen Beispiel für jede weitere Ebene ein
zusätzliches JOIN einfügen müsstest.
Hallo,
Mit einer Rahmenbedingung kann eine SQL-Datenbank einen Baum mit
beliebiger Tiefe und einem Select rekursiv durchlaufen.
Die Denksportaufgabe ist er öffnet :-)
Tip: Es ist keine OO-DB... Es geht nicht mit jeder relationalen DB
Gruß
Frank
Uhu U. schrieb:> Frank L. schrieb:>> Wenn Du die einzelnen Schritte postest kann ich schauen wo ich Dir>> helfen kann.>> Das ist nett.>> Das ist meine Spielwiese:>
1
> INSERT INTO "P" VALUES(1, ...);
2
> INSERT INTO "P" VALUES(2, ...);
3
> \
4
> \
5
> \ ParentId (Spalte 2)
6
> INSERT INTO "A" VALUES(1, 1, 0, ...);
7
> INSERT INTO "A" VALUES(2, 1, 0, ...);
8
> INSERT INTO "A" VALUES(3, 2, 0, ...);
9
> INSERT INTO "A" VALUES(4, 2, 0, ...);
10
> \
11
> \ ParentTab (Spalte 3)
12
> \ /
13
> INSERT INTO "A" VALUES(5, 4, 1, ...);
14
> INSERT INTO "A" VALUES(6, 4, 1, ...);
15
>
> Die Sätze 5 und 6 hängen an Satz 4; 1 bis 4 hängen an den Sätzen 1 und 2> in Tabelle P>> Die Abfrage auf ParentId=1 soll A.1 und A.2 liefern,> die Abfrage auf ParentId=2 soll A.3, A.4, A.5, A.6 (in der Reihenfolge)> liefern.>> Die Einzelabfragen sind ja noch schön einfach:>
1
> SELECT * FROM A WHERE ParentId=2 AND ParentTab=0;
2
> SELECT a2.* FROM A AS a1 JOIN A AS a2 ON a1._id=a2.ParentId WHERE
3
> a1.ParentId=2 AND a1.ParentTab=0;
4
>
>> Die 1. Abfrage bringt A.3 und A.4> die 2. Abfrage bringt A.5 und A.6>>
1
> SELECT * FROM A WHERE ParentId=2 AND ParentTab=0
2
> UNION
3
> SELECT a2.* FROM A AS a1 JOIN A AS a2 ON a1._id=a2.ParentId WHERE
4
> a1.ParentId=2 AND a1.ParentTab=0;
5
>
> vereinigt die beiden Resultat-Sets.
Hallo,
Dein Beispiel weicht schon von Deinem Anfangspost ab.
Du schreibst "A.ParentId ist eine _id in P, wenn das Feld ParentTab eine
0 enthält" bitte erkläre nochmal genau was Du willst.
Willst Du hinterher eine sortierte Menge von Sätzen haben, die alle
Werte umfasst oder interessieren Dich tatsächlich nur die Menge für ein
konkretes Tab?
Gruß
Frank
Frank L. schrieb:> Du schreibst "A.ParentId ist eine _id in P, wenn das Feld ParentTab eine> 0 enthält" bitte erkläre nochmal genau was Du willst.
ParentId kann zwei verschiedene Arten von Verweisen enthalten:
- wenn ParentTab == 0 zeigt ParentId in die Tabelle P
- wenn ParentTab == 1 zeigt ParentId in die Tabelle A
Zu jedem Satz in P gehören n Sätze in A. (ParentTab=0)
Zu jedem Satz in A können m weitere Sätze in A gehören. (ParentTab=1)
Die Abfrage soll die Sätze so liefern:
1
A.3
2
A.4
3
A.5
4
A.6
(Die Einrückung soll nur deutlich machen, dass 5 und 6 zu 4 gehören.)
Falls noch ein Satz A.7 mit ParentId=2 und ParentTab=0 folgen würde,
müsste der nach A.6 kommen, usw.
Hallo,
so, schauen wir mal.
Ausgehend von:
A.ParentId ist eine _id in P, wenn das Feld ParentTab eine 0 enthält
Schritt 1: Alle Elemente in a deren ParentTab eine 0 enthält, wir
selektieren direkt ParentId für die nächste Kombination.
Ergebnis: 1, 2, 3, 4 in A
------------------------------------------------------------------------
Zweiter Teil: A.ParentId ist eine _id in A, wenn das Feld ParentTab eine
1 enthält.
Schritt 1: Alle a für ParentTab = 1
Ergebnis: 1, 2, 3, 4, 5, 6
------------------------------------------------------------------------
Letzlich hast Du damit alle gültigen Kombinationen Deiner Werte.
Würdest Du jetzt einen neuen Datensatz mit den Daten:
1
INSERTINTOa(_id,ParentId,ParentTab)VALUES(7,13,0)
einfügen, würde dieser nicht in der Gesamtabfrage auftauchen, da er
nicht korrekt ist.
Wenn Du jetzt alle Werte haben willst, die direkt oder in direkt an
einer ParentId hängen, würdest Du die Abfrage so gestalten:
Ergebnis: 3, 4, 5, 6
Das Ganze ist in keiner Form performanzoptimiert abgebildet. Es soll nur
veranschaulichen wie es geht. Performanztechnisch ist diese Formulierung
die Hölle und nicht für große Datenmengen geeignet.
Gruß
Frank
Der Knackpunkt an dieser Abfrage ist die Kombination von UNION und dem
zweiten Teil Deiner Frage "A.ParentId ist eine _id in A, wenn das Feld
ParentTab eine 1 enthält." Hier durch werden 5 und 6 immer dazu
gemischt.
Das muss ich mir nochmal näher anschauen.
Gruß
Frank
Frank L. schrieb:> Ergebnis: 1, 2, 3, 4, 5, 6
Das ist nicht, was ich haben will.
Eine Abfrage für P._id=2 soll folgendes ergeben:
1
1. alle Sätze in A mit ParentId=2 und ParentTab=0 und
2
2. alle Sätze in A mit ParentId=<eine _id aus dem ersten teil der abfrage> und ParentId=1
Die Sätze aus 2. sollen jeweils nach dem A-Satz kommen, auf den sie
verweisen. (Vermutlich muss ich da noch eine Sequenznummer einbauen und
das Ergebnis danach sortieren.)
Du hast Recht, die Beschreibung im Eingangsposting ist nicht korrekt.
Es müsste korrekt heißen:
1. alle Einträge in A, die auf einen bestimmten Satz in P verweisen und
2. alle Sätze in A, die auf einen Satz in A verweisen, der auf einen
Resultatsatz aus 1. verweist.
Beitrag "Re: Ist so eine SQL-Abrage mit einem SQL-Befehl möglich?" beschreibt es
korrekt.
Ich komme immer wieder zu dem Resultat, dass meine Anfrage mit der UNION
das leistet. Ich habs in Sqliteman getestet, es läuft zumindest auf der
Mini-DB, die ich ihm zu fressen gegeben habe.
sqlite ab 3.8.3 unterstützt eine "WITH" clause für rekursive queries.
http://sqlite.org/lang_with.html
Zum Datenmodell: ich würde eine spalte als parentid nach A bezeichnen
und eine zweite spalte als parentid nach B, das macht die queries
einfacher und lässt sich mit passender DB einfacher per referentieller
integrität konsistent machen.
SQL schrieb:> select * from a left outer join p on a.parentid=p.id and a.parenttab=1> order by a.id,a.parenttab,a.parentid
D.h., wenn ich alle A-Sätze bekommen will, die an P.2 hängen, müsste ich
schreiben:
select * from a left outer join p on a.parentid=2 and a.parenttab=1
order by a.id,a.parenttab,a.parentid
Das habe ich in Sqliteman ausprobiert. Das Ergebnis ist leider leer.
rµ schrieb:> Zum Datenmodell: ich würde eine spalte als parentid nach A bezeichnen> und eine zweite spalte als parentid nach B, das macht die queries> einfacher und lässt sich mit passender DB einfacher per referentieller> integrität konsistent machen.
Stimmt, das würde das Modell einfacher machen und auch nicht mehr
Speicher fressen.
SQL schrieb:> select * from a left outer join p on a.parentid=p.id and a.parenttab=1> order by a.id,a.parenttab,a.parentid
Ein einfaches Join reicht nicht, weil es 2 parent tables gibt, und beide
müssen gejoint werden.