Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Pobranie z bazy ostatniej wiadomości od lub do użytkownika
Forum PHP.pl > Forum > Bazy danych > MySQL
mkudej
Witam.
Używam CakePHP i staram się napisać czat w stylu facebook`owego.
Wyjaśnie o co dokładnie mi chodzi:

Posiadam tabele messages z kolumnami
- id
- message
- user_from
- user_to
-date

Oraz tabela uzytkowników (users) z kolumnami
-id
-username
-name
-surname
-password
-email
- itd smile.gif

No i teraz powiedzmy że jestem zalogowany jako użytkownik o id 1 i wchodze do skrzynki wiadomości.
Chciałbym tu widzieć tylko po 1 NAJNOWSZEJ wiadomości w której jestem nadawcą bądź odbiorcą.
Czyli tak jak jest np w skrzynce gmaila, że widizmy ostatnią wiadomość z jakimś użytkownikiem i możemy w nią wejść żeby zobaczyć więcej...
Sprawia mi to nie lada problem, udało mi się dojść do wybrania wiadomości i zgrupowania ich po user_from i user_to, ale problem w tym ze wybiera on wiadomosci z najmniejszym id... czyli pierwsze napisane... A chciałbym żeby wybrał mi najnowsze

Oto zapytanie które prawie rozwiązało mój problem:
  1. SELECT `Message`.`id`, `Message`.`user_from`, `Message`.`user_to`, `Message`.`message`, `Message`.`date`, `UserFrom`.`id`, `UserFrom`.`username`, `UserFrom`.`email`, `UserFrom`.`password`, `UserFrom`.`name`, `UserFrom`.`surname`, `UserFrom`.`city`, `UserFrom`.`street`, `UserFrom`.`born_date`, `UserFrom`.`role`, `UserTo`.`id`, `UserTo`.`username`, `UserTo`.`email`, `UserTo`.`password`, `UserTo`.`name`, `UserTo`.`surname`, `UserTo`.`city`, `UserTo`.`street`, `UserTo`.`born_date`, `UserTo`.`role`
  2. FROM `gametrade_cake`.`messages` AS `Message`
  3. LEFT JOIN `gametrade_cake`.`users` AS `UserFrom` ON (`Message`.`user_from` = `UserFrom`.`id`)
  4. LEFT JOIN `gametrade_cake`.`users` AS `UserTo` ON (`Message`.`user_to` = `UserTo`.`id`)
  5. WHERE ((`user_to` = 1) OR (`user_from` = 1))
  6. GROUP BY UserTo.id, UserFrom.id
  7. ORDER BY `Message`.`date` DESC, `Message`.`id` DESC


Niestety tak jak wspomniałem nie sortuje mi po id DESC tylko robi ASC... Order wogole nie ma na to wpływu..
Drugim problemem jest to że w sumie wybiera 2 ostatnie wiadomości od nadawcy i odbiorcy (dlatego ze wybiera po user_from i user_to), dużo fajniej było by gdyby wybierało tylko 1 ostatnią z najwiekszym id bądź datą...
Wyeliminuje to późniejszy problem przy stronicowaniu.

Zrzuty struktury z mojej bazy, gdyby ktoś miał ochotę sie pobawić.
  1. CREATE TABLE IF NOT EXISTS `messages` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `user_from` int(11) NOT NULL,
  4. `user_to` int(11) NOT NULL,
  5. `message` text NOT NULL,
  6. `date` datetime NOT NULL,
  7. PRIMARY KEY (`id`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=15 ;

  1. CREATE TABLE IF NOT EXISTS `users` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `username` varchar(64) NOT NULL,
  4. `email` varchar(128) NOT NULL,
  5. `password` varchar(64) NOT NULL,
  6. `name` varchar(32) NOT NULL,
  7. `surname` varchar(32) NOT NULL,
  8. `city` varchar(64) NOT NULL,
  9. `street` varchar(64) NOT NULL,
  10. `born_date` date NOT NULL,
  11. `role` varchar(32) NOT NULL,
  12. PRIMARY KEY (`id`)
  13. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;
erix
Pokaż, jakich kryteriów używasz (w kodzie).
mkudej
Nie bardzo rozumiem co masz na myśli, kod z cake? modelu?
mmmmmmm
  1. SELECT `m`.`id`, `m`.`user_from`, `m`.`user_to`, `m`.`message`, `m`.`date`, `uf`.`id`, `uf`.`username`, `uf`.`email`, `uf`.`password`, `uf`.`name`, `uf`.`surname`, `uf`.`city`, `uf`.`street`, `uf`.`born_date`, `uf`.`role`, `ut`.`id`, `ut`.`username`, `ut`.`email`, `ut`.`password`, `ut`.`name`, `ut`.`surname`, `ut`.`city`, `ut`.`street`, `ut`.`born_date`, `ut`.`role`
  2. FROM
  3. `gametrade_cake`.`messages` AS `m`
  4. JOIN `gametrade_cake`.`users` AS `uf`
  5. ON `m`.`user_from` = `uf`.`id`
  6. JOIN `gametrade_cake`.`users` AS `ut`
  7. ON `m`.`user_to` = `ut`.`id`
  8. WHERE 1 IN (`m`.`user_to`, `m`.`user_to`)
  9. ORDER BY `m`.`date` DESC
  10. LIMIT 1
mkudej
Cytat(mmmmmmm @ 16.08.2012, 14:46:58 ) *
  1. SELECT `m`.`id`, `m`.`user_from`, `m`.`user_to`, `m`.`message`, `m`.`date`, `uf`.`id`, `uf`.`username`, `uf`.`email`, `uf`.`password`, `uf`.`name`, `uf`.`surname`, `uf`.`city`, `uf`.`street`, `uf`.`born_date`, `uf`.`role`, `ut`.`id`, `ut`.`username`, `ut`.`email`, `ut`.`password`, `ut`.`name`, `ut`.`surname`, `ut`.`city`, `ut`.`street`, `ut`.`born_date`, `ut`.`role`
  2. FROM
  3. `gametrade_cake`.`messages` AS `m`
  4. JOIN `gametrade_cake`.`users` AS `uf`
  5. ON `m`.`user_from` = `uf`.`id`
  6. JOIN `gametrade_cake`.`users` AS `ut`
  7. ON `m`.`user_to` = `ut`.`id`
  8. WHERE 1 IN (`m`.`user_to`, `m`.`user_to`)
  9. ORDER BY `m`.`date` DESC
  10. LIMIT 1


Niestety to zwraca tylko jeden wynik... A chce wybrać po 1 ostatniej wiadomości + pobrać dane użytkowników.
Nie wiem czy będzie to w ogóle możliwe...
erix
Kryteria, które wykorzystujesz w metodzie find*.
mkudej
  1. public function getChats($user_id) {
  2. $this->order = 'Message.date DESC, Message.id DESC';
  3. $data = $this->find('all', array(
  4. 'conditions' => array(
  5. 'OR' => array(
  6. array('user_to' => $user_id),
  7. array('user_from' => $user_id)
  8. ),
  9. )
  10. ));
  11. return $data;
  12. }
sazian
tak na szybko przyszło mi do głowy coś takiego

  1. WHERE ((`user_to` = 1) OR (`user_from` = 1)) AND `Message`.`id`=(SELECT max(id) FROM messages m WHERE m.user_to=`Message`.user_to AND m.user_from`=`Message`.user_from`)


i ja bym zamienił LEFT JOIN na JOIN - przecież użytkownik zawsze istnieje skoro napisał wiadomość, a patrząc w drugą stronę skoro system zezwolił na wysłanie wiadomości to użytkownik docelowy też istnieje
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.