2013-05-22 2 views
0

Я делаю приложение для знакомств, похожее на tindler, где пользователи могут любить или не любить друг друга. Если оба пользователя одинаково похожи друг на друга, они должны иметь возможность общаться друг с другом. Я придумал следующий запрос, чтобы обработать вытягивание списка пользователей, с которыми вы можете общаться в чате/с часами - проблема, с которой я сталкиваюсь, - это только желание вытащить последнее сообщение чата, только чтобы показать небольшую рекламу перед вами нажмите на сам чат. Мой запрос работает, но он возвращает самую старую запись (самый низкий ID) чата, а не самую новую. Заказ, по-видимому, не влияет на возвращение правильного результата.codeigniter присоединиться только к последней строке

$data = $this->db->select('users.id,display_name,city,state,gender,users_pictures.picture,users_chats.message') 
       ->join('users_pictures','users_pictures.user_id=users.id') 
       ->join('users_chats','users_chats.user_id=users.id OR users_chats.foreign_user_id=users.id','left outer') 
       ->where('EXISTS (SELECT 1 FROM users_likes_dislikes ld WHERE (ld.foreign_user_id = '.$this->user_id.' AND ld.user_id=users.id AND ld.event_type=1) OR (SELECT 1 FROM users_likes_dislikes ld WHERE ld.foreign_user_id = users.id AND ld.user_id='.$this->user_id.' AND ld.event_type=1))', '', FALSE) 
       ->where('NOT EXISTS (SELECT 1 FROM users_blocks ub WHERE (ub.foreign_user_id = users.id AND ub.user_id='.$this->user_id.') OR (SELECT 1 FROM users_blocks ub WHERE ub.foreign_user_id = '.$this->user_id.' AND ub.user_id=users.id))', '', FALSE) 
       ->where('((users_chats.user_id='.$this->user_id.' OR users_chats.foreign_user_id='.$this->user_id.') OR (users_chats.user_id is NULL AND users_chats.foreign_user_id is NULL))') 
       ->order_by('users_chats.id','DESC') 
       ->group_by('users.id')    
       ->get('users') 
       ->result_array(); 

Вот текущая таблица MySQL для users_chats:

id user_id foreign_user_id message created 
1 1 4 test 2013-05-22 15:42:44 
2 1 4 test2 2013-05-22 15:44:38 

Я принял order_by бы гарантировать, что сообщение test2 является то, что отображается.

Вот пример вывода:

Array ([0] => Array ([id] => 4 [display_name] => testinguser [city] => west hills [state] => ca [gender] => 2 [picture] => testasdfasdf.jpg [message] => test)) 

Любая помощь очень ценится :)

редактировать - сам запрос (без группы по, это работает, но мне нужно его группе в user.id так что я не иметь несколько записей для одного пользователя в массиве):

SELECT 
    `users`.`id`, 
    `display_name`, 
    `city`, 
    `state`, 
    `gender`, 
    `users_pictures`.`picture`, 
    `users_chats`.`message` 
FROM (`users`) 
    JOIN `users_pictures` 
    ON `users_pictures`.`user_id` = `users`.`id` 
    JOIN `users_chats` 
    ON `users_chats`.`user_id` = `users`.`id` 
     OR users_chats.foreign_user_id = users.id 
WHERE EXISTS(SELECT 
      1 
     FROM users_likes_dislikes ld 
     WHERE (ld.foreign_user_id = 1 
      AND ld.user_id = users.id 
      AND ld.event_type = 1) 
      OR (SELECT 
      1 
       FROM users_likes_dislikes ld 
       WHERE ld.foreign_user_id = users.id 
       AND ld.user_id = 1 
       AND ld.event_type = 1)) 
    AND NOT EXISTS(SELECT 
      1 
      FROM users_blocks ub 
      WHERE (ub.foreign_user_id = users.id 
       AND ub.user_id = 1) 
      OR (SELECT 
        1 
       FROM users_blocks ub 
       WHERE ub.foreign_user_id = 1 
       AND ub.user_id = users.id)) 
    AND ((users_chats.user_id = 1 
     OR users_chats.foreign_user_id = 1) 
     OR (users_chats.user_id is NULL 
      AND users_chats.foreign_user_id is NULL)) 
ORDER BY `users_chats`.`created` DESC 
+0

Знаете ли вы, что ваши таблицы выглядят? – FrankieTheKneeMan

+0

users_chats содержит id, to (int), from (int), сообщение и созданную дату :) – skrilled

+0

@skrilled on SO всегда публикует структуру таблицы, образцы данных, ожидаемый результат и то, что вы пытались, чтобы люди не просили вас чтобы дать им больше информации. –

ответ

1

Ваша группа по статье может быть виновником здесь. Я считаю, что операция группировки происходит сначала, оставив вас с вашим первым результатом. Вместо того, чтобы выбирать все эти строки (когда есть тонны, это займет больше времени), вы должны указать, сколько вы хотите - мне кажется, что это не так уж далеко от картины здесь, так или иначе. Укажите, сколько вы хотите, избавитесь от предложения group by, и вы должны упорядочить по дате, так как у вас есть столбец даты. Это помогает?

+0

вы правы, если я удаляю group_by, он сортирует его правильно, но затем я получаю несколько записей в массиве для того же профиля. я не хочу ограничивать количество возвращаемых пользователей, но я предполагаю, что хочу ограничить количество возвращенных чатов. установив предел, один результат, который я делаю, правильный, но я не вижу других пользователей/чатов в одном и том же запросе. – skrilled

+0

все, что вы сказали, помогает, и вы правы, я должен сортировать по дате, а не по id. – skrilled

+0

Да, для этого вы используете слой абстракции DB (или свою собственную инфраструктуру), поэтому его трудно диагностировать, не видя фактического SQL. – dudewad

-1

Попробуйте MySQL MAX():

$this->db->join('(SELECT MAX(message) AS lastMsg FROM users_chats WHERE users_chats.user_id=users.id OR users_chats.foreign_user_id=users.id GROUP BY users.id)', 'left outer'); 

Затем добавьте "lastMsg" на ваш выбор.

+0

MAX получает по порядку максимальный элемент. Не самый последний. – FrankieTheKneeMan

1

Я не знаю, как сделать это с дб абстракции, но запрос вы хотите

SELECT 
    `users`.`id`, 
    `display_name`, 
    `city`, 
    `state`, 
    `gender`, 
    `users_pictures`.`picture`, 
    chats1.`message` 
    FROM (`users`) 
    JOIN `users_pictures` 
     ON `users_pictures`.`user_id` = `users`.`id` 
    JOIN `users_chats` AS chats1 
     ON (chats1.`user_id` = `users`.`id` 
     OR chats1.foreign_user_id = users.id) 

Здесь приходит важная часть

  AND NOT EXISTS(
      SELECT * 
      FROM users_chats AS chats2 
      WHERE ((chats2.user_id = chats1.user_id AND chats2.foreign_user_id = chats1.foreign_user_id) 
       OR (chats2.user_id = chats1.foreign_user_id AND chats1.user_id = chats2.foreign_user_id)) 
       AND chats2.created_date > chats1.created_date --which I assume is a time stamp 
      ) 

Это не красиво, я знаю.

WHERE EXISTS(SELECT 1 
    FROM users_likes_dislikes ld 
     WHERE (ld.foreign_user_id = 1 
     AND ld.user_id = users.id 
     AND ld.event_type = 1) 
     OR (SELECT 1 
      FROM users_likes_dislikes ld 
      WHERE ld.foreign_user_id = users.id 
      AND ld.user_id = 1 
      AND ld.event_type = 1) 
    ) 
    AND NOT EXISTS(SELECT 1 
     FROM users_blocks ub 
     WHERE (ub.foreign_user_id = users.id 
      AND ub.user_id = 1) 
     OR (SELECT 
       1 
      FROM users_blocks ub 
      WHERE ub.foreign_user_id = 1 
      AND ub.user_id = users.id) 
    ) 
    AND ((chats1.user_id = 1 
     OR chats1.foreign_user_id = 1) 
     OR (chats1.user_id is NULL 
     AND chats1.foreign_user_id is NULL)) 
    ORDER BY `users_chats`.`created` DESC 

В принципе, только успешное соединение, если нет более позднего сообщения. Есть несколько лучших родных решений - TSQL (Microsoft SQL Server) имеет CROSS APPLY, что было бы здорово здесь - но, не зная больше о вашем уровне БД, я не могу быть уверен.Вы можете рассмотренное изменение архитектуры вашей структура чата:

Users(int id /*also other user info*/) 
chats(int id, datetime date_initiated, bool /*or bit, or short int*/ is_active) 
chat_users (int chat_id, int user_id) 
chat_messages (int chat_id, int user_id /*author*/, datetime date_sent, varchar(n) message) 

С структурой, как это, вы могли бы получить все самые последние сообщения, как это:

SELECT * 
    FROM Users AS u 
    INNER JOIN chat_users AS cu 
     ON u.id = cu.user_id 
    INNER JOIN chats AS c 
     ON c.id = cu.chat_id 
     AND c.is_active = 1 
    INNER JOIN chat_messages AS m 
     ON m.chat_id = c.id 
     AND NOT EXISTS (
      SELECT 1 
      FROM chat_messages AS m2 
       WHERE m2.chat_id = m.chat_id 
       AND m.date_sent < m2.date_sent 
     ) 
    INNER JOIN Users as sender 
     ON m.user_id = sender.id 
    WHERE u.id = ### 
    ORDER BY m.date_sent DESC 

Можно даже создать «чат последнее сообщение "вид:

CREATE VIEW Chat_Recent AS 
    SELECT * /* WHATEVER YOU LIKE */ 
    FROM chats AS c 
     INNER JOIN chat_messages AS m 
     ON m.chat_id = c.id 
      AND NOT EXISTS (
      SELECT 1 
       FROM chat_messages AS m2 
       WHERE m2.chat_id = m.chat_id 
        AND m.date_sent < m2.date_sent 
     ) 
     INNER JOIN Users as sender 
     ON m.user_id = sender.id 
Смежные вопросы