Возврат нескольких имен получателей в MySQL (система обмена сообщениями) - PullRequest
0 голосов
/ 12 апреля 2011

Я создаю многопользовательскую систему обмена сообщениями, аналогичную системе SMS на iPhone (в которой входящие и исходящие сообщения объединены в один экран, и между двумя пользователями может существовать только одна нить).

Сообщенияхранятся с использованием столбца senderid (например, «11») и столбца получателей (например, «, 13,10,15,20,»).Чтобы сохранить нескольких получателей, я разделяю их запятыми и запрашиваю поле с помощью вызова "%" + ", $ userid," + "#".Проблема с этим заключается в том, что он испортил LEFT JOIN, который соединяет получателейID с таблицей пользователей (которая имеет имя пользователей).

Вот мой текущий запрос:

$sql = 
  "SELECT DISTINCT CASE 
   WHEN $userid != senderid THEN senderid ELSE recipients END someid,   
   CASE WHEN 13 != senderid THEN senders.username ELSE receivers.username END somename,
   messages.body, 
   messages.time 
   FROM messages 
   LEFT JOIN users AS senders ON messages.senderid = senders.id
   LEFT JOIN users AS receivers ON messages.recipients = receivers.id
   WHERE messages.recipients = '#' + ',$userid,' + '#'
   OR messages.senderid = $userid
   ORDER BY messages.time";

Вот что я хотел бы сделать:

  • Если у получателей есть только один идентификатор получателя (содержимое выглядит как ", идентификатор, ", затем удалите запятые, окружающие идентификатор, чтобы найти имя отправителя (пользователи, вышедшие слева, как получатели, включены на messages.recipients (WITHOUT COMMAS) = receivers.id.

  • Если их большеодин идентификатор получателя в получателях (содержимое выглядит как «, id, id2, id3» и т. д.), каким-то образом извлекает все имена, соответствующие идентификаторам, и сохраняет результат, подобный следующему: sendername = "Name1, Name2, Name3";.

Кто-нибудь знает, как бы я подошел к этому? Может быть, подзапрос? Я очень признателен за помощь.

1 Ответ

1 голос
/ 13 апреля 2011

первый. Вместо:

WHERE messages.recipients = '#' + ',$userid,' + '#'

Вы можете удалить начальные и конечные запятые и использовать:

WHERE FIND_IN_SET($userid, messages.recipients) > 0

Таким образом, у вас также может быть это условие для ЛЕВОГО СОЕДИНЕНИЯ:

LEFT JOIN users AS receivers
  ON FIND_IN_SET(receivers.id, messages.recipients) > 0

, затем группируйте по сообщению и объединяйте имена с GROUP_CONCAT().

Примерно так:

  SELECT senders.name AS senderName
       , messages.body
       , messages.time 
       , GROUP_CONCAT( receivers.name
                       ORDER BY receivers.id
                       SEPARATOR ','
                     )
         AS receiversNames
  FROM messages 
    LEFT JOIN users AS senders
      ON messages.senderid = senders.id
    LEFT JOIN users AS receivers
      ON FIND_IN_SET(receivers.id, messages.recipients) > 0
  GROUP BY messages.id
  ORDER BY messages.time

выдаст вам все сообщения с объединенными именами отправителя и получателя.

Я предполагаю, что каждое сообщение имеет ровно 1 (или ноль) отправителей. Если нет, а некоторые сообщения имеют более 1 отправителя, то вам, вероятно, потребуется отредактировать GROUP BY.

Предупреждение : этот тип запросов может быть медленным (или даже ужасно медленным), когда в таблицах будет много строк. Для messages.recipients нельзя использовать индекс, что замедляет запрос. Итак, вам лучше рассмотреть вариант нормализации вашей структуры с помощью MessageRecipient промежуточной таблицы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...