SQL SQL-Abfrage (mit Join)?

skoda26

Newbie
Registriert
Nov. 2020
Beiträge
2
Hallo!

Ich lerne gerade Web-Entwicklung und habe zu einer SQL-Abfrage mal eine Frage.

Gegeben sind die folgenden beiden Tabellen:

posts
  • id
  • user_id
  • posttext

likes
  • id
  • user_id
  • post_id

So,
wenn User 5 den Beitrag mit der ID 6 von User 7 liked,
steht im Endeffekt in der likes-Tabelle folgendes:

id = 1
user_id = 5
post_id = 6

Jetzt möchte ich aber mittels dem Laravel-QueryBuilder, ich denke am besten
mit einer Join-Abfrage folgender erreichen:

Ich möchte alle Posts aus der posts-Tabelle haben. Im Ergebnis aber zusätzlich
nur, falls bei dem entsprechenden Post ein Like vorhanden ist, die Daten aus
der likes-Tabelle.

Wie mache ich das am beste? Mache ich einen einfachen Join, habe ich das
Problem, dass die Daten aus der likes-Tabelle auch versucht werden abzu
rufen - auch, wenn es für den entsprechenden Post gar kein Like gibt:

PHP:
$posts = DB::table('posts')
    ->leftJoin('likes_post_id', 'posts.id', '=', 'likes.user_id')
    ->where('posts.user_id', Auth::user()->id)
    ->get();

Vielleicht könnt ihr mir einen Tipp geben, wie ich das umsetzen kann?

LG, Dennis
 
Das ist kein klassisches SQL. Schau dir mal die Join-Typen an. Stichwort InnerJoin ;)

Oh, ich merke gerade, das InnerJoin für deinen Anwendungsfall nicht passt. Du willst ja trotzdem alle Posts auch ohne likes auswerten.

LeftJoin ist an der Stelle schon korrekt. Zumindest im klassischen SQL bekommst du dann NULL Werte für die Spalten aus der Like-Tabelle sofern keine Referenz vorhanden ist. Was genau stört dich denn jetzt an deinem Ergebnis?
 
Zuletzt bearbeitet:
was soll ein right join aendern? Dann koennte er auch einfach die Tabellen vertauschen.

Er braucht einen left(-outer) join, den hat er ja. Ich verstehe noch nicht so ganz was das Problem ist.
 
skoda26 schrieb:
Ich möchte alle Posts aus der posts-Tabelle haben. Im Ergebnis aber zusätzlich
nur, falls bei dem entsprechenden Post ein Like vorhanden ist, die Daten aus
der likes-Tabelle.

Du brauchst einen INNER JOIN, weil nur der das Ergebnis einschränkt das alle Join Bedingungen erfüllt sind.
Bei einem OUTER JOIN würden die Ergebnisse mit NULL aufgefüllt werden.

Du musst herausfinden, was bei dem Laravel-QueryBuilder ein Inner Join ist. Meine Vermutung, statt
.leftJoin(..) solltest Du .join(..) benutzen
 
Kuestennebel79 schrieb:
Du brauchst einen INNER JOIN, weil nur der das Ergebnis einschränkt das alle Join Bedingungen erfüllt sind.
Bei einem OUTER JOIN würden die Ergebnisse mit NULL aufgefüllt werden.
Ähhh, nein.
Er will ja gerade immer die Daten aus POSTS und, wenn Likes vorhanden sind, zusätzlich die Daten aus LIKES. Genau das ist die klassische Funktion des Outer Joins.
Allerdings glaube ich dass der TE weitere Probleme bekommt, wenn es zu einem Post mehrere Likes gibt, dann würde er ja beim Outer Join die Daten aus POST für jeden LIKES-Eintrag dupliziert bekommen.
Ich würde hier eher mit einem Subselect arbeiten, der mir die Anzahl der Likes liefert und diese bei bedarf in einer separaten Abfrage nachladen.
Code:
select *
      ,(select count (*) from likes where post_id = p.id) as AnzahlLikes
  from posts p 
 where p.id = ...
 
  • Gefällt mir
Reaktionen: Kuestennebel79
Ich finde OPs Beschreibung was er genau haben will total uneindeutig.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: mental.dIseASe, BeBur und Kuestennebel79
AgiOli schrieb:
Er will ja gerade immer die Daten aus POSTS und, wenn Likes vorhanden sind, zusätzlich die Daten aus LIKES.
Stimmt, das hatte ich falsch verstanden, als wenn er Posts einschränken will auf Basis der Likes eines Users.
Dann ist es ein Outer Join der richtig benutzt wird oder zwei Abfragen wie oben beschrieben
 
Ich danke euch. Ich denke, ich bin jetzt ein Schritt weiter - aber noch nicht am Ziel.

PHP:
$posts = DB::table('posts')
    ->leftJoin('likes', 'posts.user_id', '=', 'likes.user_id')
    ->whereIn('posts.user_id', $array_id)
    ->get();

So wird zumindest fast das angezeigt, was ich erhalten möchte. Aber ich kann
nicht auf die posts.user_id zugreifen. Die ist im Ergebnis 0 null - aber sie ist in
der Datenbank und wird doch ganz pben in der Quers (also durch
table(posts) abgerufen - oder?
 
IN Clause ist bei manchen Datenbanken limitiert.
 
Ich kenne den Query Builder Syntax jetzt nicht. Aber der LEFT JOIN sollte alle likes mitreinnehmen mit allen Spalten die da drin sind. Ich sehe kein explizites SELECT statement hier, evtl. ändert das etwas hier je nachdem wie der Query Builder da genau funktioniert.

Wenn ein Post mehrere Likes hat, dann macht der LEFT JOIN da auch mehrere Zeilen draus, bin mir nicht sicher ob das das gewünschte Resultat ist. Ich rate hier jetzt etwas, aber eine typische Query würde hier z.B. SUM verwenden um nur die Anzahl der Likes als Spalte reinzunehmen, dann kann man auch wieder nach Post gruppieren.

Keine Ahnung wie viele hier diesen speziellen Query Syntax kennen, evtl. bekommst du mehr Hilfe wenn du auch die generierten SQL statements dazuschreibst.
 
skoda26 schrieb:
Ich möchte alle Posts aus der posts-Tabelle haben. Im Ergebnis aber zusätzlich nur, falls bei dem entsprechenden Post ein Like vorhanden ist, die Daten aus
der likes-Tabelle.
Was möchtest du genau? Denn auch dein Beispielcode ist etwas, sagen wir mal, verwirrend!

Wenn du alle »Posts« des Benutzers X haben möchtest, ist es ja einfach. WHERE-Klausel mit user_id = ?.

Ab jetzt wird es allerdings dann trickreich und es kommt genau darauf an, was du willst: Möchtest du die Anzahl der Likes, kannst du mit einem Sub-Select arbeiten oder mit einem JOIN.

Code:
// Variante 1 - MySQL/MariaDB … Wichtig, funktioniert nur, wenn man partielle GROUP BY Klauseln erlaubt
SELECT    post.*, COUNT(like.user_id) as likes
FROM      post_table post
LEFT JOIN like_table like
          ON (like.post_id = post.post_id)
WHERE     user_id = ? /* autor_id */
GROUP BY  (post_id)


// Variante 2 - Funktioniert immer
SELECT post.*, (
       SELECT COUNT(like.user_id)
       FROM   like_table like
       WHERE  like.post_id = post.post_postID
       ) as likes
FROM   post_table post
WHERE  user_id = ? /* autor_id */

Beides bringt die Anzahl der Likes.

Solltest du die »Likes« mit den Nutzerdaten wollen, wird es komplizierter und lässt sich in der Form nicht mit einem Query erledigen, ohne dass du nicht ein massiv überladenes »Super-Object« bekommst, dass Daten aus den Tabellen post und like vermischt.

In dem Fall würde ich dir empfehlen 2 Queries zu nutzen. Im ersten fragst du die Posts ab, holst dir die entsprechenden IDs von den Posts und fragst dann die Likes ab in dem du über ein Where die IDs der Posts nutzt.

Das benötigt zwar dann mehr PHP-Code, aber man hat zwei recht simple Queries, die auch sehr schnell ausgeführt werden.

NeoExacun schrieb:
Sollte ein Right Join nicht eher deiner Idee entsprechen?
Kommt immer darauf an, was man will, in dem Fall ist das LEFT JOIN aber schon richtig: Er möchte die Posts und wenn Daten vorhanden sind auch die Likes.

RIGHT JOIN braucht man in der Regel in speziellen Fällen und würde hier zum Beispiel bewirken, dass nur Post angezeigt werden, für die auch ein Like vorhanden ist.
 
Zurück
Oben