Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL][PHP] Pobranie nieprzeczytanych wiadomości użytkownika
Forum PHP.pl > Forum > Przedszkole
gogomania
Witam,
próbuję stworzyć zapytanie, które pobierze wiadomości obecnie zalogowanego użytkownika.

Struktura tabel:
  1. CREATE TABLE `konwersacje` (
  2. `konwersacja_id` int(8) NOT NULL,
  3. `konwersacja_temat` varchar(150) NOT NULL
  4. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  5. ALTER TABLE `konwersacje`
  6. ADD PRIMARY KEY (`konwersacja_id`);
  7. ALTER TABLE `konwersacje`
  8. MODIFY `konwersacja_id` int(8) NOT NULL AUTO_INCREMENT;
  9.  
  10. CREATE TABLE `konwersacje_czlonkowie` (
  11. `id` int(11) NOT NULL,
  12. `konwersacja_id` int(8) NOT NULL,
  13. `uzytkownik_id` int(11) NOT NULL,
  14. `konwersacja_ostatnio_ogladana` int(10) NOT NULL,
  15. `konwersacja_usunieta` int(1) NOT NULL
  16. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  17. ALTER TABLE `konwersacje_czlonkowie`
  18. ADD PRIMARY KEY (`id`),
  19. ADD UNIQUE KEY `unikalny` (`konwersacja_id`,`uzytkownik_id`),
  20. ADD KEY `FK_uzytkownicy_konwersacje_czlonkowie1` (`uzytkownik_id`);
  21. ALTER TABLE `konwersacje_czlonkowie`
  22. MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
  23. ALTER TABLE `konwersacje_czlonkowie`
  24. ADD CONSTRAINT `FK_uzytkownicy_konwersacje_czlonkowie1` FOREIGN KEY (`uzytkownik_id`) REFERENCES `uzytkownicy` (`uzytkownik_id`) ON UPDATE CASCADE;
  25.  
  26. CREATE TABLE `konwersacje_wiadomosci` (
  27. `wiadomosc_id` int(10) NOT NULL,
  28. `konwersacja_id` int(8) NOT NULL,
  29. `uzytkownik_id` int(11) NOT NULL,
  30. `data_wyslania` int(10) NOT NULL,
  31. `wiadomosc_ogladana` int(1) NOT NULL DEFAULT '0',
  32. `wiadomosc_tresc` text NOT NULL
  33. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  34. ALTER TABLE `konwersacje_wiadomosci`
  35. ADD PRIMARY KEY (`wiadomosc_id`),
  36. ADD KEY `konwersacja_id` (`konwersacja_id`),
  37. ADD KEY `uzytkownik_id` (`uzytkownik_id`);
  38. ALTER TABLE `konwersacje_wiadomosci`
  39. MODIFY `wiadomosc_id` int(10) NOT NULL AUTO_INCREMENT;
  40. ALTER TABLE `konwersacje_wiadomosci`
  41. ADD CONSTRAINT `FK_uzytkownicy_konwersacje_wiadomosci` FOREIGN KEY (`uzytkownik_id`) REFERENCES `uzytkownicy` (`uzytkownik_id`) ON UPDATE CASCADE;
  42.  
  43. CREATE TABLE `uzytkownicy` (
  44. `uzytkownik_id` int(11) NOT NULL,
  45. `login` varchar(32) NOT NULL,
  46. `haslo` varchar(255) NOT NULL,
  47. `imie` varchar(55) NOT NULL,
  48. `nazwisko` varchar(80) NOT NULL,
  49. `tel_komorkowy` varchar(25) NOT NULL DEFAULT '',
  50. `tel_stacjonarny` varchar(25) NOT NULL DEFAULT '',
  51. `email` varchar(200) NOT NULL,
  52. `firma_id` int(1) NOT NULL DEFAULT '0',
  53. `pozwol_email` int(1) NOT NULL DEFAULT '0',
  54. `uprawnienia` int(1) NOT NULL DEFAULT '0',
  55. `ostatnie_logowanie` datetime DEFAULT NULL,
  56. `zdjecie` varchar(150) DEFAULT NULL,
  57. `typ` enum('Normalny','Pracownik','Administrator','Super-Administrator') NOT NULL DEFAULT 'Normalny',
  58. `aktywny` int(1) NOT NULL DEFAULT '0'
  59. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  60. ALTER TABLE `uzytkownicy`
  61. ADD PRIMARY KEY (`uzytkownik_id`),
  62. ADD UNIQUE KEY `login` (`login`),
  63. ADD KEY `firma_id` (`firma_id`);
  64. ALTER TABLE `uzytkownicy`
  65. MODIFY `uzytkownik_id` int(11) NOT NULL AUTO_INCREMENT;
  66. ALTER TABLE `uzytkownicy`
  67. ADD CONSTRAINT `FK_firmy_uzytkownicy` FOREIGN KEY (`firma_id`) REFERENCES `firmy` (`firma_id`) ON UPDATE CASCADE;


I przyznam, że się pogubiłem. Czy ktoś może mi pomóc/nakierować?
funkcja nad którą pracuję:
  1. function zlicz_wiadomosci_nieprzeczytane($uzytkownik_id) {
  2. global $connect;
  3.  
  4. $uzytkownik_id = (int)$uzytkownik_id;
  5.  
  6. $sql = "SELECT
  7. COUNT(konwersacje_wiadomosci.wiadomosc_ogladana) AS nieczytana
  8. FROM konwersacje_wiadomosci, konwersacje_czlonkowie
  9. WHERE konwersacje_wiadomosci.uzytkownik_id = {$_SESSION['uzytkownik_id']}
  10. AND konwersacje_wiadomosci.wiadomosc_ogladana = 0
  11. AND konwersacje_czlonkowie.konwersacja_ostatnio_ogladana = 0
  12. ";
  13.  
  14. $wynik = mysqli_query($connect, $sql);
  15.  
  16. if($wynik === FALSE) {
  17. die(mysqli_error($connect));
  18. } else {
  19. if($row = mysqli_fetch_row($wynik)) {
  20. return $row[0];
  21. }
  22. }
  23.  
  24. }
Niree
  1. $uzytkownik_id = (int)$uzytkownik_id;
  2.  
  3. $sql = "SELECT
  4. COUNT(konwersacje_wiadomosci.wiadomosc_ogladana) AS nieczytana
  5. FROM konwersacje_wiadomosci, konwersacje_czlonkowie
  6. WHERE konwersacje_wiadomosci.uzytkownik_id = {$_SESSION['uzytkownik_id']}
  7. AND konwersacje_wiadomosci.wiadomosc_ogladana = 0
  8. AND konwersacje_czlonkowie.konwersacja_ostatnio_ogladana = 0
  9. ";


Dlaczego w pytaniu do bazy dajesz $_SESSION zamiast użyć argumentu z funkcji czyli $uzytkownik_id?

Poza tym daj sobie:
  1. echo <<< html
  2. SELECT
  3. COUNT(konwersacje_wiadomosci.wiadomosc_ogladana) AS nieczytana
  4. FROM konwersacje_wiadomosci, konwersacje_czlonkowie
  5. WHERE konwersacje_wiadomosci.uzytkownik_id = {$_SESSION['uzytkownik_id']}
  6. AND konwersacje_wiadomosci.wiadomosc_ogladana = 0
  7. AND konwersacje_czlonkowie.konwersacja_ostatnio_ogladana = 0
  8. html;

i zobacz co Ci w ogóle wyskoczy, czy zapytanie jest prawidłowe.

Przy $wynik = mysqli_query($connect, $sql); daj
  1. $wynik = mysqli_query($connect, $sql) or die(mysqli_error($connect));
gogomania
Cytat
Dlaczego w pytaniu do bazy dajesz $_SESSION zamiast użyć argumentu z funkcji czyli $uzytkownik_id?

Na chwilę obecną to moja robocza wersja, ale to nic nie zmienia - zapytanie wykonuje się bez błędów... Ale jest nieprawidłowe, właśnie przy nim potrzebuję pomocy.

By podejrzeć prawidłowe zapytanie wstawiam
  1. echo $sql;
w funkcji następnie sprawdzam w MySQL i błędów nie ma.

PS.
Cytat
  1. $wynik = mysqli_query($connect, $sql) or die(mysqli_error($connect));

mam użyte w funkcji - pierwszy post linia 17.

Problemem jest z ułożenie właściwego zapytania - nie potrafię tego ogarnąć.
bostaf
Nieprzeczytane wiadomości dla danego użytkownika tak?

Mógłbyś wyjaśnić strukturę tabeli "konwersacje_wiadomosci"? Nie jestem pewien, czy dobrze ją rozumiem.
gogomania
Cytat(bostaf @ 5.05.2017, 13:42:00 ) *
Nieprzeczytane wiadomości dla danego użytkownika tak?

Mógłbyś wyjaśnić strukturę tabeli "konwersacje_wiadomosci"? Nie jestem pewien, czy dobrze ją rozumiem.


Dokładnie - nieprzeczytane wiadomości ze wszystkich konwersacji dla zalogowanego użytkownika.
np. Ja jestem zalogowany jako 'admin' i mam trzy rozpoczęte konwersacje i w pierwszej mam 2 nowe wiadomości w drugiej mam 3 a w trzeciej bez zmian, co w sumie daje 5 nowych wiadomości.

`konwersacje_wiadomosci`
wiadomosc_id (int 10 oraz AI)
konwersacja_id (int 8) - id konwersacji, który jest też użyty w pozostałych tabelach
uzytkownik_id (int 11) - rejestrowany nadawca wiadomości (jego np. $_SESSION['uzytkownik_id'])
data_wyslania (int 10) - data wysłanej wiadomości
wiadomosc_oglada (int 1) - tą kolumnę dodałem by rejestrować 0 / 1 dla nieodczytana/odczytana ale nie wiem czy jest sens (może jest możliwe wyciągnięcie tego samego z dat?)
wiadomosc_tresc (text) - wiadomo

Głównym zadaniem tabeli jest rejestrowanie pojedynczej wysłanej wiadomości użytkownika. Np. 'admin' wysyła wiadomość do 'test_1' i 'test_2' wówczas w tabeli konwersacje_wiadomosci zostanie zarejestrowana wiadomość tylko raz, a w tabeli konwersacje_czlonkowie dodane zostaną 3 nowe wiersze z użytkownikami tej konwersacji oraz id konwersacji.

Mam nadzieję, że w pełni odpowiedziałem na pytanie i szybko uzyskam pomoc.
bostaf
Hmm w takiej postaci nie ma możliwości ustalenia, kto jaką wiadomość przeczytał. Brakuje jednoznacznej informacji wskazującej, że dany użytkownik przeczytał daną wiadomość.

Masz "konwersacja_ostatnio_ogladana" w tabeli "konwersacje_czlonkowie", ale to tylko wskazuje kiedy dana konwersacja została otwarta w widoku do odczytu.

Masz "wiadomosc_ogladana" w "konwersacje_wiadomosci", ale to też nie wskazuje KTO oglądał daną wiadomość. Tylko tyle, że ktoś oglądał i już nie jest globalnie nieprzeczytana.

Jedyne co można z takimi danymi zrobić, to pokazać pierwszemu zalogowanemu uczestnikowi danej konwersacji, że ma N nieprzeczytanych wiadomości. W momencie jak ten użytkownik otworzy konwersację, to znaczniki się ustawią na 1 i kolejny użytkownik już będzie miał status "wszystko przeczytane".

Musiałbyś dodać jakąś tabelę, która powiąże id_wiadomosci, id_uzytkownika polem "przeczytana" (np.: "wiadomosci_przeczytane_przez"), i dopisywać tam rekordy w momencie otwarcia wiadomości do odczytu. Dodatkowo, autor wiadomości też tam powinien być dopisany w momencie wysyłania wiadomości.
Wtedy określenie ilości nieprzeczytanych wiadomości sprowadzałoby się do obliczenia różnicy a - b, gdzie:
a: ilość wszystkich wiadomości we wszystkich konwersacjach dla danego użytkownika
b: ilość wszystkich rekordów w tabeli "wiadomosci_przeczytane_przez" policzona dla id_wiadomosci z puli liczonej w "a"

To zadziała pod warunkiem, że rozumiesz że:
Cytat(gogomania @ 5.05.2017, 13:57:08 ) *
Np. 'admin' wysyła wiadomość do 'test_1' i 'test_2' [...] a w tabeli konwersacje_czlonkowie dodane zostaną 3 nowe wiersze z użytkownikami tej konwersacji oraz id konwersacji.

ta logika MOŻE spowodować pojawienie się duplikatów, i że programistycznie nie dopuszczasz do pojawienia się takich duplikatów.

Tak mi się wydaje.
Ale ogólnie na twoim miejscu mocno przemyślałbym ten model danych. Nie jestem pewien czy "konwersacja" jest tu w ogóle potrzebna, bo konwersację można ustalić dynamicznie na podstawie analizy łańcucha wiadomości:
1. Jedna wiadomość to logicznie już konwersacja. Bez odpowiedzi, ale konwersacja.
2. Dwie i więcej wiadomości to już porządna konwersacja, której początek, ciąg i koniec można ustalić dodając pole "w_odpowiedzi_na" przechowujące id_wiadomosci poprzedniej, ale jakiejkolwiek innej....
gogomania
W pierwszej kolejności dziękuję za poświęcony czas na rozwiązanie problemu.

Wrócę do początku tego wątku bo wydaje mi się, że nie wyraziłem się jasno stąd powstałe nieścisłości.


Działanie przepływu wiadomości dla konwersacji od użytkownika do użytkownika/ów mam już opracowane w pełni, w zasadzie wszystko mam już zrobione. Pozostał tylko problem a w zasadzie szczegół ze zliczeniem wiadomości nieprzeczytanych.

Nie chodzi mi tutaj o odczytanie pojedynczej wiadomości bo to by kłóciło się z tym co już mam.
Wywnioskowałem, że piszesz o stworzeniu mechanizmu gdyż jak się domyślam, założyłeś, że takiego nie mam. Otóż jest wszystko i ładnie działa. Jedynie pozostaje ta nieszczęsna kwestia zapytania SQL by pobrać wiadomości nieprzeczytane dla zalogowanego obecnie użytkownika ze wszystkich konwersacji w funkcji którą podałem w pierwszym poście.
bostaf
W takim razie zacytuję sedno tego, co napisałem w poprzednim poście:
Cytat(bostaf @ 5.05.2017, 15:11:35 ) *
Hmm w takiej postaci nie ma możliwości ustalenia, kto jaką wiadomość przeczytał. Brakuje jednoznacznej informacji wskazującej, że dany użytkownik przeczytał daną wiadomość.

Miałem tu na myśli, że w bazie danych nie masz w tej chwili informacji o tym kto jaką wiadomość przeczytał lub nie. Czyli nie skonstruujesz zapytania SQL które odpowie na Twoje pytanie.
Reszta tamtego posta to szybka analiza tego co masz dostępne i propozycja (jedna z kilku opcji) w jaki sposób taką funkcjonalność wdrożyć. Liczba nieprzeczytanych to przykład; taką samą techniką można te wiadomości pobrać.
gogomania
Cytat(bostaf @ 6.05.2017, 13:58:08 ) *
W takim razie zacytuję sedno tego, co napisałem w poprzednim poście:

Miałem tu na myśli, że w bazie danych nie masz w tej chwili informacji o tym kto jaką wiadomość przeczytał lub nie. Czyli nie skonstruujesz zapytania SQL które odpowie na Twoje pytanie.
Reszta tamtego posta to szybka analiza tego co masz dostępne i propozycja (jedna z kilku opcji) w jaki sposób taką funkcjonalność wdrożyć. Liczba nieprzeczytanych to przykład; taką samą techniką można te wiadomości pobrać.


Przepraszam, może to nie niemożliwe, ale mam tą funkcjonalność tj. mam tą informację która wiadomość została przeczytana:
  1. function pobierz_sume_konwersacji() {
  2. global $connect;
  3. $sql = "SELECT
  4. k.konwersacja_id
  5. , k.konwersacja_temat
  6. , MAX(kw.data_wyslania) AS konwersacja_ostatnia_odpowiedz
  7. , MAX(kw.data_wyslania) > (kc.konwersacja_ostatnio_ogladana) AS konwersacja_nieprzeczytana
  8. FROM konwersacje AS k
  9. LEFT JOIN konwersacje_wiadomosci AS kw ON k.konwersacja_id = kw.konwersacja_id
  10. INNER JOIN konwersacje_czlonkowie AS kc ON k.konwersacja_id = kc.konwersacja_id
  11. WHERE kc.uzytkownik_id = {$_SESSION['uzytkownik_id']}
  12. AND kc.konwersacja_usunieta = 0
  13. GROUP BY k.konwersacja_id
  14. ORDER BY konwersacja_ostatnia_odpowiedz DESC
  15. ";
  16. $wynik = mysqli_query($connect, $sql);
  17. $konwersacje = array();
  18. while ($wiersz = $wynik->fetch_assoc()) {
  19. $konwersacje[] = array(
  20. 'id' => $wiersz['konwersacja_id'],
  21. 'temat' => $wiersz['konwersacja_temat'],
  22. 'ostatnia_odpowiedz' => $wiersz['konwersacja_ostatnia_odpowiedz'],
  23. 'wiadomosci_nieprzeczytane' => ($wiersz['konwersacja_nieprzeczytana'] == 1)
  24. );
  25. }
  26. return $konwersacje;
  27. }

W tej funkcji pobieram 'konwersacja_nieprzeczytana' i wyświetlam na liście konwersacji informację np. "Nowe" co jest jednoznaczne z tym, że są nowe wiadomości w konwersacji.

  1. function pobierz_wiadomosci_konwersacji($konwersacja_id) {
  2. global $connect;
  3. $konwersacja_id = (int)$konwersacja_id;
  4. $sql = "SELECT
  5. kw.data_wyslania
  6. , kw.data_wyslania > kc.konwersacja_ostatnio_ogladana AS konwersacja_nieprzeczytana
  7. , kw.wiadomosc_tresc
  8. , CONCAT(u1.imie,' ',u1.nazwisko) AS nadawca
  9. , u1.uzytkownik_id AS nadawca_id
  10. , u1.zdjecie
  11. FROM konwersacje_wiadomosci AS kw
  12. INNER JOIN konwersacje_czlonkowie AS kc ON kw.konwersacja_id = kc.konwersacja_id
  13. INNER JOIN uzytkownicy AS u1 ON u1.uzytkownik_id = kw.uzytkownik_id
  14. WHERE kw.konwersacja_id = {$konwersacja_id}
  15. AND kc.uzytkownik_id = {$_SESSION['uzytkownik_id']}
  16. ORDER BY kw.data_wyslania DESC";
  17. $wynik = mysqli_query($connect, $sql);
  18. $wiadomosci = array();
  19. while ($wiersz = $wynik->fetch_assoc()) {
  20. $wiadomosci[] = array(
  21. 'data' => $wiersz['data_wyslania'],
  22. 'nadawca' => $wiersz['nadawca'],
  23. 'nadawca_id' => $wiersz['nadawca_id'],
  24. 'zdjecie' => $wiersz['zdjecie'],
  25. 'nieprzeczytana' => $wiersz['konwersacja_nieprzeczytana'],
  26. 'tresc' => $wiersz['wiadomosc_tresc'],
  27. );
  28. }
  29. return $wiadomosci;
  30. }

Tutaj między innymi pobieram ile jest wiadomosci nieprzeczytanych dla danej konwersacji...

Ale brakuje mi jak wspomniałem funckji która wyświetli mi wszystkie nieprzeczytane wiadomości we wszystkich konwersacjach użytkownika. Tzn. zapytania SQL. Jakieś pomysły jak powinno składać wyglądać te zapytanie?
pmir13
Zakładając że wiadomość nieprzeczytana to taka, która ma datę dodania większą (późniejszą) niż ostatnia data oglądania konwersacji przez danego użytkownika i znajduje się w tej konwersacji to można:
  1. SELECT count(*) AS nieprzeczytane
  2. FROM konwersacje_czlonkowie kc JOIN konwersacje_wiadomosci kw
  3. ON kc.konwersacja_id = kw.konwersacja_id
  4. AND kc.konwersacja_ostatnio_ogladana < kw.data_wyslania
  5. WHERE kc.uzytkownik_id = ?

Pole wiadomosc_ogladana w tabeli konwersacje_wiadomosci jest do usunięcia, nie ma tam sensu.
Nie sprawdzasz też nigdzie czy konwersacja została usunięta, ale to już musisz sam przemyśleć jak to zrobić, bo być może to pole powinno być w tabeli konwersacje albo też użytkownik może chcieć się wypisać z danej konwersacji i tylko dla niego jest ona niewidoczna (usunięta) podczas gdy inni mogą dalej w niej pisać i wtedy to pole jest w dobrym miejscu, choć dziwnie nazwane.
gogomania
Cytat(pmir13 @ 6.05.2017, 22:26:36 ) *
Zakładając że wiadomość nieprzeczytana to taka, która ma datę dodania większą (późniejszą) niż ostatnia data oglądania konwersacji przez danego użytkownika i znajduje się w tej konwersacji to można:
  1. SELECT count(*) AS nieprzeczytane
  2. FROM konwersacje_czlonkowie kc JOIN konwersacje_wiadomosci kw
  3. ON kc.konwersacja_id = kw.konwersacja_id
  4. AND kc.konwersacja_ostatnio_ogladana < kw.data_wyslania
  5. WHERE kc.uzytkownik_id = ?

Pole wiadomosc_ogladana w tabeli konwersacje_wiadomosci jest do usunięcia, nie ma tam sensu.
Nie sprawdzasz też nigdzie czy konwersacja została usunięta, ale to już musisz sam przemyśleć jak to zrobić, bo być może to pole powinno być w tabeli konwersacje albo też użytkownik może chcieć się wypisać z danej konwersacji i tylko dla niego jest ona niewidoczna (usunięta) podczas gdy inni mogą dalej w niej pisać i wtedy to pole jest w dobrym miejscu, choć dziwnie nazwane.


Jesteś mega! O to mi właśnie chodziło. Niby takie proste zapytanie a ja kombinowałem zupełnie w innym kierunku... Dziękuję Ci bardzo.

Btw. Sprawdzam czy konwersacja została usunięta w innej funcji, tutaj (cała funkcja we wcześniejszym poście):
  1. function pobierz_sume_konwersacji() {
  2. ...
  3. AND kc.konwersacja_usunieta = 0
  4. ...
  5. }

Jeżeli jest `konwersacja_usunieta` = 1 wówczas nie pokazuję jej na liście konwersacji zalogowanego użytkownika.

Ogólnie mam już wszystko - dzięki temu zapytaniu, które napisałeś!

Dziękuję wszystkim za udzielone wsparcie.
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.