MYSQL selecteer je eigen posts en die van je vrienden
ik zit met een probleem in mijn MySQL code waar ik niet uitkom.
ik heb 2 columns in mijn MySQL data base
column 1 posts:
id, user_id, type, text, time
en column 2 friends:
id, user_id, user_id_2, time
nu wil ik graag dat er op de home pagina een overzicht komt geselecteerd op tijd met posts van je vrienden en jezelf
ik heb het volgende:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
SELECT *
FROM `friends`, `posts`
WHERE friends.user_id="' . $user_id . '" AND friends.status="friends"
OR friends.user_id_2="' . $user_id . '" AND friends.status="friends"
OR posts.user_id="'.$user_id.'"
ORDER BY `time`
FROM `friends`, `posts`
WHERE friends.user_id="' . $user_id . '" AND friends.status="friends"
OR friends.user_id_2="' . $user_id . '" AND friends.status="friends"
OR posts.user_id="'.$user_id.'"
ORDER BY `time`
waarbij $user_id de id van de ingelogde gebruiker bevat
maar dit zorgt ervoor dat als je geen vrienden hebt dat je je eigen posts niet ziet.
misschien zitten er verdere bugs in maar omdat ik er niet mee verder kom kan ik deze nog niet vinden
weet iemand hoe dit kan?
alvast bedankt
Gewijzigd op 26/01/2018 13:50:56 door Christian k
Wat is het verschil tussen 'user_id' en 'user_id_2'? De naamgeving is niet echt duidelijk.
stel je voegt iemand toe als vriend dan ben jij user_id en die van je toegevoegde vriend word user_id_2. Zodat allebeide id's in de column
UserID en FriendID lijken mij duidelijker.
Dan kan er verwarring ontstaan over een combinatie van AND en OR in een query. Om er zeker van te zijn dat zaken goed gegroepeerd worden kan het helpen om de delen die bij elkaar horen te voorzien van ( haken ).
En dan wellicht nog het volgende: wat als iemand niet langer vriend is of wil zijn met $user_id, houdt dit dan ook in dat deze berichten moet verdwijnen, of gaat het erom dat ze op het moment van plaatsen van zo'n bericht vrienden waren?
Maar ook: hebben de berichten uberhaupt iets met elkaar te maken, of staan deze verder los van elkaar? Je zou het misschien ook zo kunnen maken dat je bepaalde personen volgt, en als jij aangeeft een vriend te willen zijn van iemand anders, dat je iemand dan automatisch volgt (maar dat dan later, mogelijk los van de vriendschap, weer uit kunt schakelen)?
En als de berichten niets met elkaar van doen hebben zou je deze uit elkaar kunnen trekken zodat je wellicht een wat minder vreemde spagaat hebt: berichten van jezelf, en berichten van anderen. Of je verzamelt in een query eerst alle gebruikers waarvan je berichten wilt zien (volgen?) en haalt deze vervolgens op. Als het te lastig is om dingen in één query op te lossen kun je altijd een extra query introduceren, of bijvoorbeeld wat rekenwerk naar PHP verplaatsen. Niet alles hoeft per se in één query opgelost te worden.
En tevens: zijn deze berichten alleen zichtbaar voor vrienden onder elkaar? In welk geval een systeem waarbij zowel A vriend is van B en vice versa (dus geen "eenzijdige" vriendschap) mogelijk een betere aanpak is? Of mogelijk nog anders: iemand kan zelf aangeven met wie hij/zij de berichten deelt?
Alle post staan los van elkaar en er word alleen bij gehouden welke user_id (dus wie) de post plaatst.
Wat ik graag zou willen is dat er op de home pagina een overzicht komt van de posts van jezelf en je vrienden geselecteerd op tijd. Wat ik krijg met mijn eigen mysql code is bijvoorbeeld dit:
vriend a
post maart
post feb
post jan
vriend b
post maart
post feb
post jan
Wat er dus gebeurt is dat er per vriend de posts op volgorde komt te staan en ik zou graag dit willen:
vriend a post maart
vriend b post maart
vriend a post feb
vriend b post feb
vriend a post jan
vriend b post jan
1) een query die de user_id's verzameld van jou* en je vrienden
2) een query die de posts verzameld van de lijst met user_id's die je reeds verzameld hebt bij punt 1.
Voor probleem 1 zou je dan iets krijgen als
Code (php)
1
2
3
4
5
2
3
4
5
SELECT u.id FROM users u
JOIN friends f
ON u.id=f.user_1 OR u.id=f.user_2
WHERE f.status='friends' AND (f.user_1=$user_id OR f.user_2=$user_id)
GROUP by u.id
JOIN friends f
ON u.id=f.user_1 OR u.id=f.user_2
WHERE f.status='friends' AND (f.user_1=$user_id OR f.user_2=$user_id)
GROUP by u.id
En stel dat dit de user_id's 2, 5 en 9 oplevert dan zou je die lijst weer gebruiken voor probleem 2: **
Code (php)
1
2
3
4
5
2
3
4
5
SELECT u.id, u.name, p.text, p.created FROM posts p
JOIN users u
ON p.user_id=u.id
WHERE p.user_id IN(2,5,9)
ORDER BY p.created DESC
JOIN users u
ON p.user_id=u.id
WHERE p.user_id IN(2,5,9)
ORDER BY p.created DESC
Beiden queries kunnen echter ook in één keer:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
SELECT u.id, u.name, p.text, p.created FROM posts p
JOIN users u
ON p.user_id=u.id
WHERE p.user_id IN(
SELECT u.id FROM users u
JOIN friends f
ON u.id=f.user_1 OR u.id=f.user_2
WHERE f.status='friends' AND (f.user_1=$user_id OR f.user_2=$user_id)
GROUP by u.id
)
ORDER BY p.created DESC
JOIN users u
ON p.user_id=u.id
WHERE p.user_id IN(
SELECT u.id FROM users u
JOIN friends f
ON u.id=f.user_1 OR u.id=f.user_2
WHERE f.status='friends' AND (f.user_1=$user_id OR f.user_2=$user_id)
GROUP by u.id
)
ORDER BY p.created DESC
* jou == de ingelogde gebruiker
** ik heb de kolom 'time' vervangen voor 'created' omdat het woord 'time' een gereserveerd woord is in (My)SQL.
Toevoeging op 27/01/2018 12:57:49:
Als toevoeging op je laatste post kun je de ORDER BY natuurlijk veranderen naar bijvoorbeeld
Toevoeging op 27/01/2018 15:49:40:
Frank Nietbelangrijk op 27/01/2018 12:08:25:
Ik zou het probleem in tweeën delen.
1) een query die de user_id's verzameld van jou* en je vrienden
2) een query die de posts verzameld van de lijst met user_id's die je reeds verzameld hebt bij punt 1.
Voor probleem 1 zou je dan iets krijgen als
En stel dat dit de user_id's 2, 5 en 9 oplevert dan zou je die lijst weer gebruiken voor probleem 2: **
Beiden queries kunnen echter ook in één keer:
* jou == de ingelogde gebruiker
** ik heb de kolom 'time' vervangen voor 'created' omdat het woord 'time' een gereserveerd woord is in (My)SQL.
Toevoeging op 27/01/2018 12:57:49:
Als toevoeging op je laatste post kun je de ORDER BY natuurlijk veranderen naar bijvoorbeeld
1) een query die de user_id's verzameld van jou* en je vrienden
2) een query die de posts verzameld van de lijst met user_id's die je reeds verzameld hebt bij punt 1.
Voor probleem 1 zou je dan iets krijgen als
Code (php)
1
2
3
4
5
2
3
4
5
SELECT u.id FROM users u
JOIN friends f
ON u.id=f.user_1 OR u.id=f.user_2
WHERE f.status='friends' AND (f.user_1=$user_id OR f.user_2=$user_id)
GROUP by u.id
JOIN friends f
ON u.id=f.user_1 OR u.id=f.user_2
WHERE f.status='friends' AND (f.user_1=$user_id OR f.user_2=$user_id)
GROUP by u.id
En stel dat dit de user_id's 2, 5 en 9 oplevert dan zou je die lijst weer gebruiken voor probleem 2: **
Code (php)
1
2
3
4
5
2
3
4
5
SELECT u.id, u.name, p.text, p.created FROM posts p
JOIN users u
ON p.user_id=u.id
WHERE p.user_id IN(2,5,9)
ORDER BY p.created DESC
JOIN users u
ON p.user_id=u.id
WHERE p.user_id IN(2,5,9)
ORDER BY p.created DESC
Beiden queries kunnen echter ook in één keer:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
SELECT u.id, u.name, p.text, p.created FROM posts p
JOIN users u
ON p.user_id=u.id
WHERE p.user_id IN(
SELECT u.id FROM users u
JOIN friends f
ON u.id=f.user_1 OR u.id=f.user_2
WHERE f.status='friends' AND (f.user_1=$user_id OR f.user_2=$user_id)
GROUP by u.id
)
ORDER BY p.created DESC
JOIN users u
ON p.user_id=u.id
WHERE p.user_id IN(
SELECT u.id FROM users u
JOIN friends f
ON u.id=f.user_1 OR u.id=f.user_2
WHERE f.status='friends' AND (f.user_1=$user_id OR f.user_2=$user_id)
GROUP by u.id
)
ORDER BY p.created DESC
* jou == de ingelogde gebruiker
** ik heb de kolom 'time' vervangen voor 'created' omdat het woord 'time' een gereserveerd woord is in (My)SQL.
Toevoeging op 27/01/2018 12:57:49:
Als toevoeging op je laatste post kun je de ORDER BY natuurlijk veranderen naar bijvoorbeeld
ik heb er wat mee gepruts en het werkt ook alleen ik krijg nu hetvolgende:
persoon a
post 1: 27 jan
post 2: 26 jan
post 3: 25 jan
persoon b:
post 1: 26 jan
post 2: 25 jan
Hij zet ze nu op volgorde van tijd alleen dan gegroepeerd per persoon.
Ik zou graag willen dat hij de personen door elkaar gooit en dus alleen op tijd sorteert.
Mischien komt dit omdat ik p.created zo opsla:
Zou het kunnen dat mysql niet op deze manier wil sorteren en dat ik p.created met time() moet vullen?
Die datums zijn, of liever gezegd, dat datumformaat is ongeschikt om mee te sorteren. Beter is om een DATETIME (YYYY-MM-DD HH:MM:SD) te gebruiken, eventueel met een apart bijgehouden tijdszone, of een vertaling naar dezelfde tijdszone. Of een unix timestamp, wat jij wilt. Beide zijn geschikt(er), in ieder geval om mee te rekenen.
Een goede gewoonte is ook om dit soort datums enkel een leesbaar(der) format te geven net voordat je zo'n datum weergeeft op het scherm. De rest van de tijd moeten machines hier mee kunnen werken / rekenen.
Stel je hebt geen vrienden, dan staat er dat er geen posts zijn om weer te geven. Je ziet dus je eigen posts niet. Terwijl je je eigen posts wel ziet als je 1 of meer vrienden hebt. Hoe kan ik er voor zorgen dat ik mijn eigen posts ook kan zien ongeacht of ik vrienden heb?
Gewijzigd op 27/01/2018 19:39:23 door Thomas van den Heuvel
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
SELECT u.id, u.name, p.text, p.time, u.profilepic, u.lastname, p.created FROM posts p
JOIN users u
ON p.user_id=u.id
WHERE p.user_id IN(
SELECT u.id FROM users u
JOIN friends f
ON u.id=f.user_id OR u.id=f.user_id_2
WHERE f.status="friends" AND (f.user_id="$user_id" OR f.user_id_2="$user_id")
GROUP by u.id
)
ORDER BY p.created DESC';
JOIN users u
ON p.user_id=u.id
WHERE p.user_id IN(
SELECT u.id FROM users u
JOIN friends f
ON u.id=f.user_id OR u.id=f.user_id_2
WHERE f.status="friends" AND (f.user_id="$user_id" OR f.user_id_2="$user_id")
GROUP by u.id
)
ORDER BY p.created DESC';
Dit is wat ik op dit moment heb maar het is hier toch niet mogelijk om tussen de in() iets toe te voegen? Aangezien je hier vrienden selecteert.
Mja, maar als je geen vrienden hebt dan levert de SELECT van regel 5 t/m 9 niets op, waardoor je IN() effectief leeg is.
Als dat werkt dan is dat een goede oplossing :). Of je gaat voor de verdeel-en-heers strategie, waarbij je je probleem opdeelt in verschillende deelproblemen.
Perfect! Het werkt nu zoals ik het graag wou. Bedankt voor jullie tijd, moeite en hulp! :)