Дизайн базы данных личных сообщений
Хорошо, поэтому я думаю, что я довольно близок к тому, что мне нужно, но я не уверен в двух вещах:
TABLE messages
message_id
message_type
sender_id
timestamp
TABLE message_type
message_type_code (1, 2, 3)
name (global, company, personal)
TABLE message_to_user
message_id
receiver_id
status (read/unread)
Цель:
- Возможность отправлять GLOBAL-сообщения всем пользователям.
- Отправлять ПЕРСОНАЛЬНЫЕ сообщения между 1 и более пользователями.
- Определите, было ли какое-либо из этих сообщений прочитано или нет получателем.
Вопросы:
- Описывает ли моя схема все, что ей нужно?
- Какой пример SQL-запроса будет выглядеть так, чтобы заполнить почтовый ящик someones, введя GLOBAL-сообщения, а также ПЕРСОНАЛЬНЫЕ сообщения - я бы хотел определить, что для пользовательского интерфейса.
И, пожалуйста, не стесняйтесь добавлять к моей схеме, если вы считаете, что это принесет пользу.
Ответы
Ответ 1
Схема выглядит так, как будто она будет работать. Вероятно, у вас тоже есть дата создания. Невозможно узнать, прочитали ли вы глобальное сообщение, не создавая записей для всех.
Вот некоторые SQL:
SELECT M.*, MTU.*
FROM messages M
LEFT JOIN message_to_user MTU ON MTU.message_id=M.message_id
WHERE MTU.receiver_id={$UserID} OR M.message_type={$GlobalType}
ORDER BY M.created_on DESC
[EDIT]
Проблема. Каждый пользователь должен иметь свой собственный уникальный "прочитанный" статус для глобальных электронных писем. Вероятно, вы также захотите дать им возможность "удалить" /скрыть это электронное письмо, чтобы они не смотрели на него все время. Нет никакого способа обойти это, не создавая ни строки для каждого электронного письма, как это происходит, что, вероятно, облагает налогом, чтобы сделать это много ВСТАВКИ одновременно... или еще лучше, не создавайте статус до его чтения. Таким образом, INSERTS для глобальных электронных писем будет возникать только при чтении сообщения.
messages
message_id
message_type
sender_id
timestamp
message_recipient
message_id
user_id
message_status
message_status_id
message_id
user_id
is_read
read_datetime
is_deleted
deleted_datetime
SELECT M.*, MR.*, MS.*
FROM messages M
LEFT JOIN message_recipient MR ON MR.message_id=M.message_id
LEFT JOIN message_status MS ON MS.message_id=M.message_id
WHERE
(MS.message_status_id IS NULL OR MS.is_deleted = 0)
(MR.user_id={$UserId} OR M.message_type={$GlobalType})
ORDER BY M.timestamp DESC
[EDIT]
Следует ли использовать message_type в качестве таблицы БД или просто как настройки в вашем коде, отчасти является личным предпочтением и отчасти вашим потребностям. Если вам нужно запросить БД и увидеть текст "личный" и "глобальный" непосредственно из вашего запроса, то вы хотите использовать таблицу message_type. Однако, если вам нужен только "тип" для обработки вашей бизнес-логики, но не нужно видеть его в результатах запроса, я бы пошел с подходом "Enum". Перечисления - это вещь С#... в PHP, ближайший у вас есть класс с константами... что-то вроде:
class MessageTypes {
public const Global = 0;
public const Personal = 1;
}
Итак, ваш запрос будет выглядеть следующим образом: WHERE ... message_type=".MessageTypes::Global."...
Ответ 2
Один метод может состоять в том, чтобы отделить глобальные сообщения от личных сообщений, как я думаю, вы уже пытались сделать.
Чтобы эффективно получить статус чтения для глобального сообщения, вам нужно будет добавить таблицу с составным ключом, содержащим global_message_id и user_id вместе.
messages_tbl
- message_id | int(11) | Primary Key / Auto_Increment
- message_type | int(11)
- sender_id | int(11) | FK to sender
- receiver_id | int(11) | FK to receiver
- status | int(1) | 0/1 for Unread / Read
- message | text
- date | datetime
global_message_tbl
- g_message_id | int(11) | Primary Key / Auto_Increment
- g_message_type | int(11)
- sender_id | int(11) | FK to sender
- date | datetime
global_readstatus_tbl
- user_id | int(11) | Primary Key
- g_message_id | int(11) | Primary Key
- date | datetime
Альтернативно объединяйте messages_tbl
и global_message_tbl
, чтобы каждый пользователь отправлял глобальное сообщение лично в цикле. Это уменьшает вашу схему вплоть до одной таблицы.
messages_tbl
- message_id | int(11) | Primary Key / Auto_Increment
- sender_id | int(11) | FK to sender
- receiver_id | int(11) | FK to receiver
- status | int(1) | 0/1 for Unread / Read
- message_type | varchar(8) | Personal / Global / Company
- message | text
- date | datetime
- type | varchar(8)
Если вы хотите улучшить нормализацию своей таблицы и упростить добавление типов сообщений в будущем, снова переместите message_type в свою собственную таблицу и сделайте message_type
FK message_type_id
message_type_tbl
- message_type_id | int(11) | Primary Key / Auto_Increment
- message_type | varchar(8) | Personal / Global / Company
Обновление - Пример таблицы (1 таблица)
message_tbl
message_id | message_type | sender_id | receiver_id | status | message | datetime
1 | personal | 2 | 3 | read | foobar | 12/04/11 00:09:00
2 | personal | 2 | 4 | unread | foobar | 12/04/11 00:09:00
3 | personal | 3 | 2 | unread | barfoo | 12/04/11 02:05:00
4 | global | 1 | 2 | unread | gmessage | 13/04/11 17:05:00
5 | global | 1 | 3 | unread | gmessage | 13/04/11 17:05:00
6 | global | 1 | 4 | read | gmessage | 13/04/11 17:05:00
user_tbl
user_id | name
1 | Admin
2 | johnsmith
3 | mjordan
4 | spippen
Вышеприведенное предполагает, что пользователи 2, 3 и 4 являются пользователями общего доступа, отправляющими сообщения друг другу, пользователь 1 является учетной записью администратора, которая будет использоваться для отправки глобальных сообщений (доставляемых непосредственно каждому пользователю отдельно), позволяя вам видеть ту же информацию как будто это личное сообщение.
Чтобы отправить глобальное сообщение в этом формате, вы просто прокрутите таблицу пользователей, чтобы получить весь идентификатор, из которого вы хотите отправить глобальное сообщение, а затем просто INSERT
строки для каждого пользователя в messages_tbl
.
Если вы не ожидаете, что ваши пользователи будут отправлять миллионы сообщений в день, а также обычные глобальные сообщения миллионам пользователей, то количество строк не должно быть проблемой. Вы всегда можете очистить старые прочитанные сообщения от пользователей, создав очистку script.