Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Specyficzne wyświetlanie bez powtórzeń
Forum PHP.pl > Forum > Bazy danych > MySQL
krynol
Witam.

Mam pewien problem z wyświetlaniem danych z bazy.
Mam utworzoną tabelę w której przechowywane są dane użytkownika.
Tabela składa się z następujących pól:

id - identyfikator wiadomości
id_user - identyfikator osoby która dostała wiadomość
id_sender - identyfikator osoby wysyłającej wiadomość
content - treść wiadomości
stauts - 0 lub 1 w zależności czy wiadomość została przeczytana

Chciałbym wyśwetlić wszystkie w tabeli osoby w którymi były prowadzone rozmowy. Czyli wyświetlić mam osoby do których pisałem albo które do mnie pisały, ale bez powtórzeń.
Pierwsze co zrobiłem to:
  1. mysql_query ("SELECT FROM KR_messages WHERE id_user='".$user['id']."' or id_sender='".$user['id']."')

A efekt tego był taki:
-michał
-adam
-adam
-michał
-michał

Czyli nie poprawnie. Późnie spróbowałem Group By
  1. mysql_query ("SELECT * FROM KR_messages WHERE id_user='".$user['id']."' or id_sender='".$user['id']."' GROUP BY id_user")

Jednak to również daje niepoprawne wyniki bo czasami ja jestem nadwacą (czyli id_sender) a czasami odbiorcą (id_user) więc grupowanie musiało by być przez: id_user, id_sender.

Ktoś ma jakieś pomysły?
javafxdev
dzisiejszy odcinek sponsoruje liczba 1 oraz słowo: 'distinct'
krynol
Zatem jak to ma wyglądać?
Zapomniałem dodać, że w tabeli messages są tylko identyfikatory użytkowników, z kolei w tabeli members są ich dane takie jak np imie.

Poniżej przedstawiam graficznie jaki jest problem. Po lewej są moje tabele z bazy danych, po prawej cały rezultat jaki chciałbym osiągnąć.
Bardzo proszę o pomoc


nospor
Cytat
dzisiejszy odcinek sponsoruje liczba 1 oraz słowo: 'distinct'
oraz fraza 'nie tedy droga' wink.gif

@krynol wracajac do tematu:
Twoje pierwsze zapytanie jest jak najbardziej ok (pomijajac fakt ze pomiedzy SELECT a FROM ewidentnie czegos brakuje wink.gif )
Teraz w php musisz pogrupowac swoje rekordy po id nie nalezacym do osoby aktualnie zalogowanej i jestes w domu. Jak to sie mniej wiecej robi pokazalem tu
http://nospor.pl/grupowanie-wynikow.html
majac tak przygotowana tablice wyswietlasz ja sobie jak ci pasuje
javafxdev
Patrząc na Twoją bazę kilka uwag:
- tabela z użytkownikami nie potrzebuje pola ID_user wystary ID które będzie użyte w tabelce messages.
- tabelka z messages pola ID_user ID_sender proponuję zamienić na ID_sender, ID_receiver.

Co do samego działania to potrzebujesz wyświetlić użytkowników z którymi dany user prowadził rozmowę, możesz to zrobić jednym zapytaniem:
  1. SELECT u1.id, u1.name FROM messages LEFT JOIN users u1 ON messages.sender_id = u1.id WHERE receiver_id = 1
  2. UNION
  3. SELECT u2.id, u2.name FROM messages LEFT JOIN users u2 ON messages.receiver_id = u2.id WHERE sender_id = 1;

i dostaniesz osoby z którymi gadał user o ID = 1.

Nie słuchaj rad zeby coś tam robić w PHP jakieś pętle, filtrowania cuda na kiju, później kończy się to tak że jak będziesz miał wiele milionów rekodrów, bazę danych na innym serwerze to wszystko trzeba będzie przepchnąć przez sieć do serwera PHP i sieć się zamuli, aplikacja się zamuli i będzie kupa.

Oczywiście wiemy że ta aplikacja to jakaś tam mała zabawa, ale uczyć trzeba się od samego początku dobrze wink.gif
nospor
Cytat
Nie słuchaj rad zeby coś tam robić w PHP jakieś pętle, filtrowania cuda na kiju, później kończy się to tak że jak będziesz miał wiele milionów rekodrów, bazę danych na innym serwerze to wszystko trzeba będzie przepchnąć przez sieć do serwera PHP i sieć się zamuli, aplikacja się zamuli i będzie kupa.

@javafxdev przeczytaj jeszcze raz problem autora, przejrzyj obrazki, a moze cos ci zaswita tongue.gif Tak czy siak musisz wszystkie niezbedne pobrac do php wiec nie stoi na przeszkodzie by i w php je ladnie pogrupowac bo to bedzie juz zaden dodatkowy narzut. Dodatkowo tez byloby milo jakbys przeczytal rozwiazania ktore proponuja inni bo odnosze wrazenie ze tego nie zrobiles i pleciesz trzy po trzy.... Przeciez twoje zapytanie tak samo pobierze te milion rekordow jak ich tyle bedzie...
javafxdev
Problem autora jest taki:
"Czyli wyświetlić mam osoby do których pisałem albo które do mnie pisały, ale bez powtórzeń"

@nospor Załóżmy że user o ID = 1 przeprowadził milion rozmów z uzytkownikiem 'Ania' w Twoim rozwiązaniu zostanie 'Ania' zwrócona milion razy i pogrupowana w PHP i finalnie dostaniemy jeden rekord. W moim rozwiązaniu 'Ania' zostanie zwrócona jeden raz. Nie będzie pętli w php robiącej milion razy sprawdzenie, nie będzie przepychania niepotrzebnych danych przez sieć.
Piszesz również że: " Przeciez twoje zapytanie tak samo pobierze te milion rekordow jak ich tyle bedzie..." otóż nie, pobierze tylko jeden raz. Spróbuj sobie odpalić to zapytanie i sprawdź sam. Jeżeli nie widzisz różnicy to po co się kłucić.
nospor
@javafxdev autor chce rowniez wyswietlic wiadomosci z danym userem.
A po drugie twoje zapytanie nie ma zadnego limitu ani nic, wiec jak user mial milion wiadomosci z userem nospor to dostanie milion rekordow a nie jeden.

I teraz pozwol ze zacytuje ciebie
"Jeżeli nie widzisz różnicy to po co się kłucić."


edit: ok, UNION usunie duplikaty, nie zwrocilem uwagi na to. Nie jestem jednak przekonany co do optymalnosci tego rozwiazania bo i tak zapytanie wpierw musi przeleciec przez te wszystkie milion wiadomosci a dopiero potem usunie na łaczeniu UNION duplikaty
Nie zmienia to faktu ze autor chce wyswietlic tez wiadomosci przy userze wiec tak czy siak trzeba je pobrac. Mozna to oczywiscie zrobic dynamicznie chocby ajaxem.
javafxdev
@nospor wyobraź sobie sytułację gdzie masz telefon na którym chcesz zrobić taką aplikację - wyświetlasz listę kontaktów i po kliknięciu na dany kontakt wyświetlasz historię rozmowy. Wyobraź sobie teraz że telefon wyciąga wszystkie dane z historią rozmowy do pamięci - wyciąga z karty pamięci SD (wolne czasy dostępów) milion rekordów trwa to koszmarnie długo, przenosi to do pamięci i zaczyna obrabiać, pamięci w telefonie zaczyna brakować (odpalony facebook i inne chaty), zużycie baterii na przejście po całej liście diametralnie rośnie, procesor się poci i to wszystko tylko po to zeby pokazać listę 80 kontaktów gdzie na koniec musisz jeszcze zrobić jednego if-a zeby usunąć samego siebie z listy. Do historii rozmów z 74 osobami nie wejdziesz nigdy w przeciągu miesiąca/dwóch albo i dłużej, ale musisz je mieć na liście. Zasoby potrzebne do wyświetlenia tej listy w Twoim rozwiązaniu są lekko mówiąc zbyt duże.
A teraz wyobraź sobie że zamiast telefonu masz PHP z 1000 userów. szybki dysk SSD zaczyna być jak karta w telefonie, szybki procesor intel i7 staje się jak Pentium II, 32 GB ramu robią się jak 128 MB, firma hostingowa liczy cykle procesora tylko po to zeby wykonać milion niepotrzebnych obrotów pętli, procek cały czas chodzi na 100% zeby zrobić prostą rzecz jaką jest pokazanie 80 osób na liście kontaktów, userzy mówią że im apka muli i nie będa z niej korzystać i tak kończy 80% projektów w IT wink.gif
nospor
wyobraz sobie, ze autor poprosil o rozwiazanie jak na obrazku...

Ja sobie wole wyobrazac piekniejsze obrazki. Przedstawilem rozwiazanie o ktore prosil autor. Oczywiscie ze mozna to zrobic optymalniej, pobrac tylko wpierw nazwy userow bez duplikacji a potem klikajc na usera doczytywac wiadomosci (chocby ajaxem). Ja to wiem.

ps: jest tez cos takiego jak stronicowanie itp, bo nawet jak wyswietlisz wiadomosci tylko dla jednego usera a ich bedzie milion to tez szlag trafi appke. Tak samo jak szlag trafi appke jak user rozmawial z milionem uzytkownikow i nawet wowczas twoje hiper zapytanie tez spowoduje rozwalenie appki - wyobraz to sobie wink.gif
trueblue
  1. SELECT DISTINCT(u.name)
  2. FROM uzytkownik AS u,wiadomosc AS w
  3. WHERE w.id_user=u.id_user OR w.id_sender=u.id_user
nospor
@trueblue zapomniales o warunku ze szukamy wiadomosci z userem o id 15 wink.gif
trueblue
  1. SELECT DISTINCT(u.name)
  2. FROM uzytkownik AS u,wiadomosc AS w
  3. WHERE (w.id_user=u.id_user OR w.id_sender=u.id_user) AND (w.id_user=15 OR w.id_sender=15)
javafxdev
@trueblue jak napisał @nospor 'nie tedy droga' trzeba robić w PHP, do tego Twoje zapytanie zwróci też samego usera o ID = 15, a tego nie chcemy mieć w wynikach

@nospor mówisz o stronicowaniu więc wytłumaczę Ci jak to będzie działać w moim przykładzie: do tego union dodasz LIMIT i OFFSET i nadal masz listę 10,20,50 userów ktorzy są potrzebni do wyświetlenia na liście, dostaniesz z bazy tyle ile potrzebujesz i apki 'szlag nie trafi', natomiast w Twoim rozwiązaniu przy milionie kontaktów i tak wszystko przepchniesz do PHP i tam dopiero zrobisz limit i offset? nie mając unikalnych rezultatów z bazy i tak będziesz musiał wszystko przepchnąć do serwera zeby chociażby zrobić stronicowanie (skąd będziesz wiedział ile elementów będzie zawierać lista jak nie przejdziesz całej w PHP) i tutaj apka się rzeczywiście wywali, dlatego nie rozumiem dlaczego tak bronisz tego swojego rozwiązania opartego na PHP.
nospor
Ciezko mi sie z toba rozmawia wink.gif

Cytat
dlatego nie rozumiem dlaczego tak bronisz tego swojego rozwiązania opartego na PHP.

Sprobuje jeszcze raz ci to wyjasnic:
autor prosil o liste userow bez duplikatow oraz liste wiadomosci przy kazdym userze. Moj kod to robi. Tak, moj kod sie wywali przy duzej liczbie danych.
Teraz twoje rozwiazanie, ktore jest rozwiazaniem problemu wg ciebie a nie jest, bo nie robi to o co prosil autor. Robi tylko w polowie. I twoje rozwiazanie przy duzej liczbie danych tez sie wylozy. Teraz nagle dodajesz do niego limit offsety itp. No ok, ale rownie dobrze mozna to pododawac do mojego.

poza tym napisalem wczesniej jak to powinno wygladac
Cytat
Oczywiscie ze mozna to zrobic optymalniej, pobrac tylko wpierw nazwy userow bez duplikacji a potem klikajc na usera doczytywac wiadomosci (chocby ajaxem). Ja to wiem.
Wiec nie, nie upieram sie przy moim pierwszym rozwiazaniu. Mowie jedynie ze ono robi to o co prosil autor, a Twoje nie. Twoje trzeba jeszcze uzupelnic o druga polowe i tak czy siak zabezpieczyc przed duza iloscia danych a z Twojej pierwszej wypowidzi wynikalo ze Twoje zapytanie jest och i ach a nie bylo.
javafxdev
Ciężko się rozmawia bo przedstawiam logiczne argumenty wink.gif

To ja Ci też spróbuje wyjaśnić dlaczego napisałem o offsetach i limitach - bo Ty zacząłeś: cytat: "ps: jest tez cos takiego jak stronicowanie itp" więc jak zacząłeś o tym mówić to chciałem Ci wyjaśnić dlaczego moje zapytanie będzie działać przy stronicowaniu a Twoje nie, natomiast Ty piszesz dalej: "Teraz nagle dodajesz do niego limit offsety itp. No ok, ale rownie dobrze mozna to pododawac do mojego."

Otóż wyjaśniam że do Twojego nie można dodać limitu i offsetu - dlaczego, ano dlatego:

Jeżeli wyciągnę pierwszych 10 rekordów z tabelki messages zapytaniem
  1. SELECT * FROM WHERE user_id = ... OR sender_id = .. LIMIT 10

to jeżeli pierwsze 10 rozmów było prowadzone z np. 'Arkiem' to nie dostanę listy userów grupując to w PHP, bo dostanę tylko 'Arka', więc nie dość że Twoje rozwiązanie się nie skaluje, to jeszcze NIE MOŻNA do niego dodać limitu i offsetu.
Natomiast w moim zapytaniu:
  1. SELECT u1.id, u1.name FROM messages LEFT JOIN users u1 ON messages.sender_id = u1.id WHERE receiver_id = 1
  2. UNION
  3. SELECT u2.id, u2.name FROM messages LEFT JOIN users u2 ON messages.receiver_id = u2.id WHERE sender_id = 1
  4. LIMIT 10;

dostaniesz nadal właściwą listę userów i dopiero potem wyciągasz ajaxem dla konkretnego klikniętego usera wiadomości z LIMITEM.

Więc Twoje rozwiązanie ma dwa problemy: wywali się przy dużej liczbie danych, a następnie będzie potrzebny refaktoring PHP i samych zapytań aby to naprawić jak aplikacja zacznie się rozrastać- droższy maintanace.

Ale obaj przecież wiemy, że to tylko jakaś praca domowa, ew. 'nowy facebook', więc nie ma się o co kłucić smile.gif

Ja z chęcią zobaczę lepsze rozwiązanie od tego co ja podałem takie żeby było skalowalne i szybkie bo nie twierdzę że moje rozwiązanie jest najlepsze.

nospor
Cytat
Ciężko się rozmawia bo przedstawiam logiczne argumenty
Nie dosc ze inteligentny to jeszcze skromny wink.gif *

Bede mial kiedys chwilke to zrobie testy na duzych danych dla Twojego zapytania i zapytania trueblue bo mnie ciekawi co tutaj bedzie lepsze



*nie, to nie byl sarkazm ani nic zlego nie mialem na mysli smile.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.