ACHTUNG. Das ist ein Archiv des alten forum.ruby-portal.de. Die aktuelle Mailingliste gibt es auf lists.ruby-lang.org/pipermail/ruby-de.

NOTICE. This is a ready-only copy of the old forum.ruby-portal.de. You can find the current mailing list at lists.ruby-lang.org/pipermail/ruby-de.

Die Programmiersprache Ruby

Blog|

Forum|

Wiki  


Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]

Ein neues Thema erstellen Auf das Thema antworten  [ 5 Beiträge ] 
Autor Nachricht
BeitragVerfasst: 25 Aug 2016, 20:38 
Offline
Interpreter
Benutzeravatar

Registriert: 18 Sep 2008, 22:32
Beiträge: 1821
Wohnort: NRW → UN
Hallo Community,

folgende Ausgangssituation: Ich habe zwei Models, "Post" und "Tag", jeweils schön in eigenen Tabellen ("posts" und "tags") sowie eine Kreuztabelle "posts_tags", d.h. es liegt eine many2many-Association vor (ein Post kann beliebig viele Tags haben, und zu einem Tag können beliebig viele Posts gehören).

Dann wollte ich alle Posts haben, auf die alle Tags einer Abfrage zutreffen. Beispiel: Post 1 hat die Tags "Grafik", "Wichtig", Post 2 hat nur das Tag "Grafik". Ich will jetzt eine Abfrage haben, die mir nur Post 1 zurückgibt, wenn nach "Grafik" und "Wichtig" kombiniert gefragt wird.

Ich war der Auffassung, dass das so schwer nicht sein kann, aber irgendwie bin ich nicht in der Lage, diese Query als eine einzelne SQL-Abfrage zu formulieren. Es geht mit mehreren nacheinander, aber es sollte doch möglich sein, das mit einer einzelnen Query hinzubekommen? Hat jemand einen Hinweis, welche Konstruktion man für diese Art Abfrage wählen sollte?

Im Einsatz ist auf Ruby-Seite Sequel als SQL-Mapper, aber die Frage ist vermutlich eher eine solche von SQL selbst. Insofern nehme ich auch entsprechende Hinweise entgegen, um die Umsetzung in Sequel kümmere ich mich dann schon selbst.

Valete,
Quintus

_________________
Habe den Mut, dich deines eigenen Verstandes zu bedienen! — Immanuel Kant

Ich bin freischaffender Softwareentwickler und freue mich über jedes neue Projekt. Kontaktinformation auf meiner Website.

Mein Blog | GitHub-Profil | Auf Twitter: @qquintilianus | PGP/GPG-Schlüssel: B1FE 958E D5E8 468E AA20 8F4B F1D8 799F BCC8 BC4F


Nach oben
 Profil  
 
BeitragVerfasst: 26 Aug 2016, 10:25 
Offline
Rubyist

Registriert: 09 Jun 2009, 18:00
Beiträge: 346
was auf jeden fall geht ist zwei mal gegen die tags tabelle zu joinen, je einmal für jeden tag. eventuell geht das auch mit nem subselect, aber um das rauszupuzzeln bräuchte ich sample-daten.

_________________
Ruhe jetzt, sonst hol ich meinen kleinen Bruder.


Nach oben
 Profil  
 
BeitragVerfasst: 27 Aug 2016, 16:48 
Offline
Interpreter
Benutzeravatar

Registriert: 18 Sep 2008, 22:32
Beiträge: 1821
Wohnort: NRW → UN
Danke für den Hinweis mit dem Subselect. Das folgende scheint soweit zu funktionieren:



1
2
3
4
5
6
7
8
SELECT t1.id,t1.tag_id FROM
(
SELECT posts.id,posts_tags.tag_id FROM posts
INNER JOIN posts_tags ON posts.id=posts_tags.post_id
WHERE posts_tags.tag_id=1
) AS t1
INNER JOIN posts_tags ON t1.id=posts_tags.post_id
WHERE posts_tags.tag_id=2;


(wobei 1 und 2 die IDs der Tags sind). Damit kann ich arbeiten und versuche das jetzt mal umzusetzen. (Und ja ich weiß, dass ich t1.tag_id hier nicht benötige, das war nur zum experimentieren da).

Was mich irritiert, ist, dass der folgende CTE-Ausdruck nicht funktioniert, sondern mit einem Syntax Error quittiert wird, obwohl er eigentlich gleichwertig und übersichtlicher sein sollte:



1
2
3
4
5
6
7
8
9
10
11
12
13
WITH tag1(pid,tid) AS
(
SELECT posts.id,posts_tags.tag_id FROM posts
INNER JOIN posts_tags ON posts.id=posts_tags.post_id
WHERE posts_tags.tag_id=1
),
WITH tag1_2(pid,tid) AS
(
SELECT pid,tid FROM tag1
INNER JOIN posts_tags ON pid=posts_tags.post_id
WHERE posts_tags.tag_id=2
)
SELECT pid,tid FROM tag1_2;


SQLite3 meint dazu „Error: near "tag1_2": syntax error“. Der zweite Ausdruck hätte den Charme, dass man noch mehr Tags einfach immer weiter runterfiltern könnte (einfach pro Tag ein neues WITH-Statement hinzufügen). Vielleicht übersehe ich da ja etwas offesnsichtliches, weil ich in SQL nicht sooo fit bin, daher lasse ich das hier mal für Hinweise stehen.

Da ich das SQL aber ohnehin weitestgehend generieren lassen werde, wird es wohl auch mit den Subselects gehen.

Sofern noch ein Interesse an Beispieldaten besteht, hier sind sie:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- Tabellen erstellen

CREATE TABLE posts ( id INT, title VARCHAR(255), PRIMARY KEY (id) );
CREATE TABLE tags ( id INT, name VARCHAR(255), PRIMARY KEY (id) );
CREATE TABLE posts_tags ( post_id INT, tag_id INT );

-- Posts

INSERT INTO posts VALUES (1, 'Test post with one tag');
INSERT INTO posts VALUES (2, 'Test post with no tags');
INSERT INTO posts VALUES (3, 'Test post with two tags');

-- Tags

INSERT INTO tags VALUES (1, 'Graphics');
INSERT INTO tags VALUES (2, 'Music');
INSERT INTO tags VALUES (3, 'Other');

-- Post 1 bekommt die Tags Graphics und Music
-- Post 2 bekommt nur das Tag Graphics

INSERT INTO posts_tags VALUES (1, 1);
INSERT INTO posts_tags VALUES (1, 2);
INSERT INTO posts_tags VALUES (2, 1);


Danke für deine Antwort!

Vale,
Quintus

_________________
Habe den Mut, dich deines eigenen Verstandes zu bedienen! — Immanuel Kant

Ich bin freischaffender Softwareentwickler und freue mich über jedes neue Projekt. Kontaktinformation auf meiner Website.

Mein Blog | GitHub-Profil | Auf Twitter: @qquintilianus | PGP/GPG-Schlüssel: B1FE 958E D5E8 468E AA20 8F4B F1D8 799F BCC8 BC4F


Nach oben
 Profil  
 
BeitragVerfasst: 27 Aug 2016, 17:03 
Offline
Interpreter
Benutzeravatar

Registriert: 18 Sep 2008, 22:32
Beiträge: 1821
Wohnort: NRW → UN
Ich habe das Problem mit WITH gelöst. War natürlich so ein dummer Fehler -- "WITH" muss für die späteren Statements nicht mehr wiederholt werden. Das sieht dann korrekt so aus:



1
2
3
4
5
6
7
8
9
10
11
12
13
WITH tag1(pid,tid) AS
(
SELECT posts.id,posts_tags.tag_id FROM posts
INNER JOIN posts_tags ON posts.id=posts_tags.post_id
WHERE posts_tags.tag_id=1
),
tag1_2(pid,tid) AS
(
SELECT pid,tid FROM tag1
INNER JOIN posts_tags ON pid=posts_tags.post_id
WHERE posts_tags.tag_id=2
)
SELECT pid,tid FROM tag1_2;


Danke trotzdem!

Vale,
Quintus

_________________
Habe den Mut, dich deines eigenen Verstandes zu bedienen! — Immanuel Kant

Ich bin freischaffender Softwareentwickler und freue mich über jedes neue Projekt. Kontaktinformation auf meiner Website.

Mein Blog | GitHub-Profil | Auf Twitter: @qquintilianus | PGP/GPG-Schlüssel: B1FE 958E D5E8 468E AA20 8F4B F1D8 799F BCC8 BC4F


Nach oben
 Profil  
 
BeitragVerfasst: 27 Aug 2016, 18:58 
Offline
Interpreter
Benutzeravatar

Registriert: 18 Sep 2008, 22:32
Beiträge: 1821
Wohnort: NRW → UN
Jetzt noch die Umsetzung in Sequel, damit die Ursprungsfrage komplett geklärt ist. Sequel ist schon echt cool, so Sachen wie WITH-Statements lassen sich wunderbar umsetzen. Das SQL aus meinem letzten Post geht in folgendem Ruby-Code unter Verwendung von Sequel auf, wenn für die Posts-Tabelle ein entsprechendes Model Post definiert wurde:



1
2
3
4
5
6
7
8
Post
.with(:tag1,
Post.join(:posts_tags, :post_id => :id)
.where(Sequel.qualify("posts_tags", "tag_id") => 1))
.with(:tag1_2,
DB[:tag1].join(:posts_tags, :post_id => :id)
.where(Sequel.qualify("posts_tags", "tag_id") => 2))
.from(:tag1_2)


Die entsprechenden Aufrufe von #with kann man jetzt leicht in eine Schleife packen, die über die einzelnen Tags iteriert.

Vale,
Quintus

_________________
Habe den Mut, dich deines eigenen Verstandes zu bedienen! — Immanuel Kant

Ich bin freischaffender Softwareentwickler und freue mich über jedes neue Projekt. Kontaktinformation auf meiner Website.

Mein Blog | GitHub-Profil | Auf Twitter: @qquintilianus | PGP/GPG-Schlüssel: B1FE 958E D5E8 468E AA20 8F4B F1D8 799F BCC8 BC4F


Nach oben
 Profil  
 
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 5 Beiträge ] 

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach: